You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何打印预训练TimeSformer模型各层的输入输出尺寸?

打印TimeSformer模型各层输入输出尺寸的解决方案

问题背景

在自定义nn.Module子类中,将预训练TimeSformer模型作为self.feature属性,尝试打印所有层的输入输出尺寸时,遇到TypeError: 'TimeSformer' object is not iterable错误,后续使用children()的尝试也未达到预期效果。

模型结构概述

TimeSformer(
  (model): VisionTransformer(
    (dropout): Dropout(p=0.0, inplace=False)
    (patch_embed): PatchEmbed(
      (proj): Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))
    )
    (pos_drop): Dropout(p=0.0, inplace=False)
    (time_drop): Dropout(p=0.0, inplace=False)
    (blocks): ModuleList(  
      (0): Block(...)  # 共12个Block,每个包含空间注意力、时间注意力、MLP等子模块
      ...
      (11): Block(...)
    )
    (norm): LayerNorm((768,), eps=1e-06, elementwise_affine=True) 
    (head): Linear(in_features=768, out_features=400, bias=True) 
  )
)

错误代码示例

最初尝试直接遍历self.feature导致报错:

class Class(nn.Module):
    def __init__(self, pretrained=False):
        super(Class, self).__init__()
        
        self.feature = TimeSformer(img_size=224, num_classes=400, num_frames=8, attention_type='divided_space_time',  
                                   pretrained_model='path/to/the/weight.pyth')

    def forward(self, x):
        for layer in self.feature:
            x = layer(x)
            print(x.size())
        return x

报错信息:

TypeError: 'TimeSformer' object is not iterable

可行解决方案

方案1:利用前向钩子自动记录所有层IO

通过注册前向钩子,递归捕获所有子模块的输入输出尺寸,无需手动拆解模型:

import torch
import torch.nn as nn
from timesformer.models.vit import TimeSformer

class Class(nn.Module):
    def __init__(self, pretrained=False):
        super(Class, self).__init__()
        self.feature = TimeSformer(img_size=224, num_classes=400, num_frames=8, attention_type='divided_space_time',  
                                   pretrained_model='path/to/the/weight.pyth')

    def _log_io(self, module, input, output):
        # 打印模块类名、输入尺寸、输出尺寸
        input_shape = tuple(input[0].shape) if input else "无输入"
        output_shape = tuple(output.shape) if output is not None else "无输出"
        print(f"[{module.__class__.__name__}] 输入尺寸: {input_shape} | 输出尺寸: {output_shape}")

    def forward(self, x):
        # 给所有子模块注册钩子
        hooks = []
        # 注意要访问TimeSformer内部的model属性(VisionTransformer核心)
        for sub_module in self.feature.model.modules():
            hook = sub_module.register_forward_hook(self._log_io)
            hooks.append(hook)
        
        # 执行前向传播
        output = self.feature(x)
        
        # 移除钩子,避免重复注册
        for hook in hooks:
            hook.remove()
        
        return output

方案2:手动逐层遍历(针对TimeSformer结构定制)

如果需要更清晰的层级展示,可根据模型结构手动拆解前向流程,逐个打印尺寸:

import torch
import torch.nn as nn
from timesformer.models.vit import TimeSformer

class Class(nn.Module):
    def __init__(self, pretrained=False):
        super(Class, self).__init__()
        self.feature = TimeSformer(img_size=224, num_classes=400, num_frames=8, attention_type='divided_space_time',  
                                   pretrained_model='path/to/the/weight.pyth')
        # 提取核心VisionTransformer模块
        self.vit = self.feature.model

    def forward(self, x):
        print(f"初始输入尺寸: {x.shape}")
        
        # Patch嵌入层
        x = self.vit.patch_embed(x)
        print(f"PatchEmbed输出尺寸: {x.shape}")
        
        # 位置Dropout
        x = self.vit.pos_drop(x)
        print(f"pos_drop输出尺寸: {x.shape}")
        
        # 时间Dropout
        x = self.vit.time_drop(x)
        print(f"time_drop输出尺寸: {x.shape}")
        
        # 遍历所有Block
        for idx, block in enumerate(self.vit.blocks):
            print(f"\n=== Block {idx} ===")
            # 空间注意力分支
            norm1_out = block.norm1(x)
            print(f"norm1输出尺寸: {norm1_out.shape}")
            attn_out = block.attn(norm1_out)
            print(f"空间attn输出尺寸: {attn_out.shape}")
            x = x + block.drop_path(attn_out)
            
            # 时间注意力分支
            temp_norm_out = block.temporal_norm1(x)
            print(f"temporal_norm1输出尺寸: {temp_norm_out.shape}")
            temp_attn_out = block.temporal_attn(temp_norm_out)
            print(f"时间attn输出尺寸: {temp_attn_out.shape}")
            temp_fc_out = block.temporal_fc(temp_attn_out)
            print(f"temporal_fc输出尺寸: {temp_fc_out.shape}")
            x = x + block.drop_path(temp_fc_out)
            
            # MLP分支
            norm2_out = block.norm2(x)
            print(f"norm2输出尺寸: {norm2_out.shape}")
            mlp_out = block.mlp(norm2_out)
            print(f"MLP输出尺寸: {mlp_out.shape}")
            x = x + block.drop_path(mlp_out)
            print(f"Block {idx} 最终输出尺寸: {x.shape}")
        
        # 最终LayerNorm
        x = self.vit.norm(x)
        print(f"\n最终Norm输出尺寸: {x.shape}")
        
        # 分类头
        x = self.vit.head(x)
        print(f"分类头输出尺寸: {x.shape}")
        
        return x

关键注意点

  • TimeSformer模块的核心逻辑在内部的model属性(即VisionTransformer)中,不能直接遍历self.feature,需访问self.feature.model。
  • modules()方法会递归获取所有嵌套子模块,适合用钩子自动记录;children()仅获取直接子模块,无法覆盖深层嵌套的子层。

内容的提问来源于stack exchange,提问作者dtr43

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 01:45:30