将使用老版本torch的项目迁移到较新的环境中需要注意的问题(以强化学习项目DeepRL-Grounding为例)(第一部分)
一、项目介绍
DeepRL-Grounding 是一个基于 PyTorch 的开源项目,旨在训练一个强化学习Agent,使其能够在 Doom游戏场景中执行自然语言指令。该项目是AAAI 2018年论文[1706.07230] Gated-Attention Architectures for Task-Oriented Language Grounding的Pytorch实现。项目的Github地址:devendrachaplot/DeepRL-Grounding: Train an RL agent to execute natural language instructions in a 3D Environment (PyTorch)
原项目环境:(可能是)Python2、Pytorch(<=0.3.1)、VizDoom、Opencv
我的环境:Python3.8、Pytorch(2.6.0)、VizDoom、Opencv
之所以不使用原环境复现,有两个原因:
1.Python 2和PyTorch 0.3.1都已被官方弃用。手动构建有点麻烦。
2.手动构建原环境的意义仅是复现论文,我最终还是要在新环境下跑通并集成其他功能为我自己的项目所用。为了省(tou)时(lan)间,我假设论文在原环境下是能复现出来的。如果最后山穷水尽,再去考虑论文不能复现的问题。
以下章节中,每一章描述一个任务,在每个任务中,都有将使用老版本torch的项目迁移到较新的环境引起的问题。每一节描述一个问题。我分别描述并解决它们,以供类似问题参考。
二、验证Pretrained model
首先验证预训练模型是否可以直接使用。这里只是浅浅尝试,最后还是要自己训练。
2.1 nn.GRU与nn.GRUCell
报错:
RuntimeError: input must have 3 dimensions, got 2
原因:在早期 PyTorch 版本(<=1.0)中,GRU 允许 2 维输入(默认 seq_len=1),所以代码可以运行。而在新版本 PyTorch(>=1.2+)中,GRU 现在严格要求 seq_len 维度,即输入必须是 (seq_len, batch, input_size),否则报错。
解决方式:GRUCell 本来就是处理单步输入的,支持 (batch, input_size),因此可以用 GRUCell 代替 GRU 来兼容 2 维输入。
修改1:
self.gru = nn.GRU(32, self.gru_hidden_size)
改为
self.gru = nn.GRUCell(32, self.gru_hidden_size)
修改2:
def forward(self, inputs):
x, input_inst, (tx, hx, cx) = inputs
# Get the image representation
x = F.relu(self.conv1(x))
x = F.relu(self.conv2(x))
x_image_rep = F.relu(self.conv3(x))
# Get the instruction representation
encoder_hidden = Variable(torch.zeros(1, 1, self.gru_hidden_size))
for i in range(input_inst.data.size(1)):
word_embedding = self.embedding(input_inst[0, i]).unsqueeze(0)
_, encoder_hidden = self.gru(word_embedding, encoder_hidden)
x_instr_rep = encoder_hidden.view(encoder_hidden.size(1), -1)
# Get the attention vector from the instruction representation
x_attention = F.sigmoid(self.attn_linear(x_instr_rep))
# Gated-Attention
x_attention = x_attention.unsqueeze(2).unsqueeze(3)
x_attention = x_attention.expand(1, 64, 8, 17)
assert x_image_rep.size() == x_attention.size()
x = x_image_rep*x_attention
x = x.view(x.size(0), -1)
# A3C-LSTM
x = F.relu(self.linear(x))
hx, cx = self.lstm(x, (hx, cx))
time_emb = self.time_emb_layer(tx)
x = torch.cat((hx, time_emb.view(-1, self.time_emb_dim)), 1)
return self.critic_linear(x), self.actor_linear(x), (hx, cx)
改为
def forward(self, inputs):
x, input_inst, (tx, hx, cx) = inputs
# Get the image representation
x = F.relu(self.conv1(x))
x = F.relu(self.conv2(x))
x_image_rep = F.relu(self.conv3(x))
# Get the instruction representation
encoder_hidden = torch.zeros(1, self.gru_hidden_size) # seq_len=1
for i in range(input_inst.data.size(1)):
word_embedding = self.embedding(input_inst[0, i]).unsqueeze(0)
#print(word_embedding.shape) # [1, 32]
encoder_hidden = self.gru(word_embedding, encoder_hidden)
x_instr_rep = encoder_hidden.view(-1, encoder_hidden.size(1))
# print(x_instr_rep.shape)
# Get the attention vector from the instruction representation
x_attention = torch.sigmoid(self.attn_linear(x_instr_rep))
# Gated-Attention
x_attention = x_attention.unsqueeze(2).unsqueeze(3)
x_attention = x_attention.expand(1, 64, 8, 17)
assert x_image_rep.size() == x_attention.size()
x = x_image_rep*x_attention
x = x.view(x.size(0), -1)
# A3C-LSTM
x = F.relu(self.linear(x))
hx, cx = self.lstm(x, (hx, cx))
time_emb = self.time_emb_layer(tx)
x = torch.cat((hx, time_emb.view(-1, self.time_emb_dim)), 1)
return self.critic_linear(x), self.actor_linear(x), (hx, cx)
2.2 模型权重 key 名称变更
报错:
File "a3c_main.py", line 115, in <module>
torch.load(args.load, map_location=lambda storage, loc: storage))
File "/home/yunlian/virtualenvs/python3.7/lib/python3.7/site-packages/torch/nn/modules/module.py", line 839, in load_state_dict
self.__class__.__name__, "\n\t".join(error_msgs)))
RuntimeError: Error(s) in loading state_dict for A3C_LSTM_GA:
Missing key(s) in state_dict: "gru.weight_ih", "gru.weight_hh", "gru.bias_ih", "gru.bias_hh".
Unexpected key(s) in state_dict: "gru.weight_ih_l0", "gru.weight_hh_l0", "gru.bias_ih_l0", "gru.bias_hh_l0".
原因:代码期望的 state_dict 使用了旧版 PyTorch 的 GRU key 命名规则,导致 state_dict 加载失败。
解决方式:
第一种:更改键名(推荐),我会后续更新详细的修改。
可以单独写一个py程序,将键名"gru.weight_ih_l0", "gru.weight_hh_l0", "gru.bias_ih_l0", "gru.bias_hh_l0"转换为"gru.weight_ih", "gru.weight_hh", "gru.bias_ih", "gru.bias_hh"。
但实际运行后,pretrained model的效果并不好。个人猜测是因为代码没有给具体环境,所以就算在老环境下,效果也不好。只有在作者真正运行的环境下才有好的效果。
第二种:使用strict=False启用严格禁用模式忽略报错(不推荐,最多仅适用于 PyTorch 1.x 到 1.x 迁移)。修改:
model.load_state_dict(torch.load(args.load))
改为
model.load_state_dict(torch.load(args.load), strict=False)
三、模型部分
四、测试部分
五、训练部分
请移步将使用老版本torch的项目迁移到较新的环境中需要注意的问题(以强化学习项目DeepRL-Grounding为例)(第二部分)-CSDN博客
更多推荐


所有评论(0)