活动介绍
file-type

PyTorch获取模型输入输出Shape详解

PDF文件

44KB | 更新于2024-08-30 | 35 浏览量 | 0 下载量 举报 收藏
download 立即下载
"在PyTorch中,与TensorFlow或Caffe不同,官方并没有提供直接获取模型input/output shape的功能。然而,可以通过编写自定义代码来实现这一目的。本实例提供了一种解决办法,但需要注意,由于不同的模块如CNN、RNN实现方式不同,可能需要针对特定模块进行代码调整。这个方法依赖于对模型进行一次前向传播(model(x)),以计算出形状信息。" 在PyTorch中,获取模型输入和输出的形状通常是通过动态图的特性实现的,而不是像TensorFlow或Caffe那样有内置的模型摘要工具。在给定的代码片段中,我们看到一个工作示例,它使用了`OrderedDict`来存储每个层的输入和输出形状。首先,导入所需的库,包括`collections.OrderedDict`、`torch`、`torch.autograd.Variable`、`torch.nn`以及一个假设存在的`models.crnn`模块。 `get_output_size`函数是一个递归函数,用于处理模型输出可能是单个张量或元组的情况。如果输出是元组(多输出模型),它会遍历每个元素并递归地获取它们的形状。对于单个张量,它简单地将形状转换为列表并存储到`summary_dict`中。 `summary`函数是核心部分,它接收输入尺寸`input_size`和模型对象`model`作为参数。通过注册钩子函数`hook`到模型的每个模块,我们可以在前向传播过程中捕获输入和输出。`hook`函数记录了模块的类名(class_name)、模块的索引(module_idx)以及输入和输出的形状。 `register_hook`函数遍历模型的子模块,并对每个子模块调用`hook`函数进行注册。这样,当模型被调用时,每个模块的输入和输出都会被记录下来。 请注意,这种方法依赖于给定一个输入尺寸`input_size`来执行前向传播,因此获取的形状信息是基于这个特定输入的。在实际应用中,这可能需要根据训练数据的形状进行调整。 这段代码提供了一个实用的解决方案,尽管它可能不适用于所有类型的PyTorch模块,特别是那些具有特殊特性的模块,如RNN,可能需要对代码进行调整以正确处理它们的权重和偏置。然而,对于大多数标准的卷积神经网络和全连接网络,这个方法应该是足够的。

相关推荐

filetype
filetype

### 解决 PyTorch Lightning 中 "optimizer got an empty parameter list" 错误 这个错误发生在优化器尝试初始化时发现模型没有可训练参数。以下是常见原因和解决方法: #### 主要原因分析 1. **模型参数未正确定义**: - 模型中的子模块(如 CNN、LSTM)未正确注册到主模型中 - 参数未设置 `requires_grad=True`(默认应为 True) - 模型结构定义错误导致无参数生成 2. **代码结构问题**: - 子模块定义在错误的位置(如内部类未实例化) - 参数未通过 `self.` 正确绑定到模型实例 3. **数据流问题**: - 输入数据形状与模型预期不匹配 - 预处理步骤导致有效参数为零 #### 解决方案 ##### 1. 检查模型参数注册 在你的 `CNNDeepAR` 类中,确保所有子模块都通过 `self.` 注册: ```python class CNNDeepAR(BaseModelWithCovariates): def __init__(self, **kwargs): super().__init__(**kwargs) # 确保所有子模块都通过 self 注册 self.embedding = MultiEmbedding(...) self.cnn = nn.Conv1d(...) self.rnn = nn.LSTM(...) self.output_layer = nn.Linear(...) # 检查参数总数 total_params = sum(p.numel() for p in self.parameters()) print(f"模型总参数数: {total_params}") ``` ##### 2. 修复子模块实例化问题 当前代码中 `EmbeddingLayer` 是内部类但未实例化,应改为直接定义模块: ```python class CNNDeepAR(BaseModelWithCovariates): def __init__(self, **kwargs): super().__init__(**kwargs) # 删除 EmbeddingLayer 类,直接实例化模块 self.embedding = MultiEmbedding( self.hparams.embedding_sizes, self.hparams.x_categoricals ) # 计算输入尺寸 output_value = int(self.embedding.output_size) self.input_size = len(self.hparams.x_reals) + output_value # 实例化其他模块 self.cnn = nn.Conv1d(...) self.rnn = nn.LSTM(...) self.output_layer = nn.Linear(...) ``` ##### 3. 验证参数是否可训练 添加参数检查代码: ```python # 在训练前添加检查 def before_train(): model = cnn_deepar_model print("可训练参数:") for name, param in model.named_parameters(): if param.requires_grad: print(f"{name}: {param.shape}") if sum(p.numel() for p in model.parameters()) == 0: raise RuntimeError("模型没有可训练参数!") before_train() trainer.fit(...) ``` ##### 4. 确保数据形状匹配 在 `forward` 方法中添加形状检查: ```python def forward(self, x): print("输入形状:", {k: v.shape for k, v in x.items()}) # ...原有处理逻辑... # 添加调试输出 print("CNN输出形状:", x_cnn_encoder.shape) print("RNN输出形状:", rnn_output.shape) return output ``` #### 根本原因分析 在你的代码中,问题最可能出现在: 1. `EmbeddingLayer` 类定义了子模块但未实例化,导致这些模块未注册到主模型 2. 计算 `input_size` 的逻辑可能得到零值,使 CNN 层创建失败 3. 多层嵌套的类结构导致参数未正确绑定 #### 预防措施 1. 使用 PyTorch 的 `nn.ModuleList` 或 `nn.Sequential` 管理子模块 2. 在 `__init__` 结尾添加参数验证: ```python assert len(list(self.parameters())) > 0, "模型无参数!" ``` 3. 使用 Lightning 的 `configure_optimizers` 调试: ```python def configure_optimizers(self): params = list(self.parameters()) print(f"优化器将接收 {len(params)} 组参数") return torch.optim.Adam(params, lr=self.learning_rate) ``` ### i an a full pipeline

weixin_38599412
  • 粉丝: 7
上传资源 快速赚钱