从零实现多层RNN:输入逻辑困惑与PyTorch反向传播原地修改错误
问题解决:堆叠RNN输入逻辑与反向传播原地修改错误
一、堆叠RNN的输入逻辑澄清
你对堆叠RNN的理解是正确的:每个时间步中,第一层的输出作为同时间步第二层的输入,后续层以此类推。
PyTorch官方文档中给出的RNN代码是简化的示意版本,目的是展示RNN的基础循环逻辑,并非真实的堆叠RNN实现。实际PyTorch内部的nn.RNN当num_layers>1时,严格遵循层间传递输入的逻辑——上层的输出作为下层的输入,而非所有层都使用原始输入x[t]。
二、反向传播原地修改错误的解决
错误原因
你的代码中h_t = h_0是直接赋值,导致h_t与h_0共享同一块内存空间。后续的h_t[layer] = ...属于原地修改张量,这会破坏PyTorch自动微分系统对张量版本的跟踪,从而引发梯度计算错误。
修复方案
每次时间步循环时,创建新的h_t张量来存储当前层的隐藏状态,避免复用之前的张量内存。同时修正层间输入传递的语法错误。
修改后的完整代码:
def forward(self, x, h_0=None): batch_size, seq_len, _ = x.size() x = x.transpose(0, 1) # 切换为(seq_len, batch_size, input_dim)格式 if h_0 is None: h_0 = torch.zeros(self.num_layers, batch_size, self.hidden_dim, device=x.device) h_t_minus_1 = h_0 output_list = [] for t in range(seq_len): # 为当前时间步创建新的隐藏状态张量,避免原地修改 h_t = torch.zeros_like(h_t_minus_1) for layer in range(self.num_layers): if layer == 0: current_input = x[t] else: # 上层输出作为当前层输入,做线性变换匹配维度 current_input = F.linear(h_t[layer-1], self.w_hh2.T) # 计算当前层的隐藏状态 h_t[layer] = torch.tanh( current_input @ self.w_ih[layer].T + h_t_minus_1[layer] @ self.w_hh[layer].T + self.b_hh[layer] ) # 输出层计算 output = F.linear(h_t[-1], self.w_oh, self.b_oh) output_list.append(output) h_t_minus_1 = h_t # 更新隐藏状态 # 转换回(batch_size, seq_len, output_dim)格式 output_list = torch.stack(output_list).transpose(0, 1) return output_list
关键改动点
- 移除
h_t = h_0的直接赋值,改为在每个时间步创建全新的h_t = torch.zeros_like(h_t_minus_1),避免内存共享。 - 修正了
current_input赋值的语法错误(原代码if-else结构不完整)。 - 增加
device=x.device参数,确保张量在同一设备上运行,避免潜在的设备不匹配问题。
内容的提问来源于stack exchange,提问作者Tuhin Subhra De
相关产品推荐
相关产品推荐

