PyTorch中model.cuda()执行报错RuntimeError求助
解决PyTorch中调用.cuda()时的RuntimeError:Variable data has to be a tensor, but got torch.cuda.FloatTensor
嘿,我马上就发现了问题的根源!你遇到的这个报错看起来有点迷惑——torch.cuda.FloatTensor明明就是张量啊,怎么会说不是呢?其实问题出在你TR_LSTM模型的init_hidden方法里,咱们一步步拆解:
错误原因分析
在你的init_hidden方法中,你做了两个不该做的操作:
- 把初始隐藏状态
h_0和c_0转换成了torch.nn.Parameter - 提前对这两个张量调用了
.cuda()
这两个操作结合起来导致了问题:
- Parameter的误用:LSTM的初始隐藏状态是每次前向传播的临时输入,不是模型需要训练的参数,完全不需要封装成
Parameter。当你把它们定义为Parameter后,PyTorch会把它们当作模型的可训练参数来管理。 - 提前移动设备冲突:你提前把
h_0和c_0移到了GPU,之后调用model.cuda()时,PyTorch会遍历所有模型参数(包括你错误定义的这两个Parameter),尝试把它们的data再次移到GPU,这就触发了这个看似矛盾的报错。
解决方案:修改init_hidden方法
把init_hidden改成下面这样,移除Parameter封装和提前.cuda()的操作,而是根据当前模型所在的设备来创建张量:
class TR_LSTM(nn.Module): def __init__(self,args, use_hidden_average=False, pretrained_emb = None): super(TR_LSTM,self).__init__() # 参数 self.emb_dim = args.embed_dim self.emb_num = args.embed_num self.num_hidden_unit = args.hidden_state_dim self.num_lstm_layer = args.num_lstm_layer self.use_hidden_average = use_hidden_average self.batch_size = args.batch_size # 网络层 self.embed = nn.Embedding(self.emb_num, self.emb_dim) if pretrained_emb is not None: self.embed.weight.data.copy_(pretrained_emb) self.lstm_layer = nn.LSTM(self.emb_dim, self.num_hidden_unit, self.num_lstm_layer, batch_first = True) self.fc_layer = nn.Sequential(nn.Linear(self.num_hidden_unit,self.num_hidden_unit), nn.Linear(self.num_hidden_unit,2)) def forward(self,x): x = self.embed(x) # batch * max_seq_len * emb_dim h_0,c_0 = self.init_hidden(x.size(0)) x, (_, _) = self.lstm_layer(x, (h_0,c_0)) # batch * seq_len * hidden_unit_num if not self.use_hidden_average: x = x[:,x.size(1)-1,:] x = x.squeeze(1) else: x = x.mean(1).squeeze(1) x = self.fc_layer(x) return x def init_hidden(self,batch_size): # 移除Parameter封装,并且使用模型的设备来创建张量 device = next(self.parameters()).device h_0 = torch.zeros(self.num_lstm_layer, batch_size, self.num_hidden_unit, device=device) c_0 = torch.zeros(self.num_lstm_layer, batch_size, self.num_hidden_unit, device=device) return h_0, c_0
额外说明
- 你提到修改epoch参数后问题出现,改回去也没解决——这其实是巧合,问题的本质和epoch无关,只是刚好在调整epoch时触发了报错,实际是
init_hidden的写法错误导致的。 - 使用
next(self.parameters()).device可以自动获取模型当前所在的设备(CPU或GPU),这样不管你是先调用model.cuda()还是先执行前向传播,隐藏状态都会自动匹配设备,避免设备不匹配的问题。
内容的提问来源于stack exchange,提问作者Peter Kim
相关产品推荐
相关产品推荐

