我在进行一个项目,模型需要访问在类构造函数中声明的张量(我继承了torch.nn.Module类),然后我需要在forward()方法中通过简单的matmul()使用这个张量,模型通过cuda()调用被发送到GPU上:
model = Model()
model.cuda()
然而,当我通过以下方式对简单输入X进行前向传播时:
model(X) # 或 model.forward(X)
我得到了以下错误:
RuntimeError: Expected object of type torch.cuda.FloatTensor but found type torch.FloatTensor for argument #2 ‘mat2’
这表明matmul的第二个参数(我声明的实例张量)在CPU上,而预期它在GPU上(与模型和数据的其余部分一样)。
在matmul中,张量通过matrix.t()进行转置。
我甚至尝试通过以下方式重写cuda()方法:
def cuda(self):
super().cuda()
self.matrix.cuda()
数据已经在GPU上,这意味着以下代码行已经执行:
X = X.cuda()
此外,错误明确指出matmul的第二个参数是张量(称为matrix),而不是X。
回答:
我们假设以下几点:
-
X
正确地移动到了GPU上 -
在
Model
类中声明的张量是一个简单的属性。即类似于以下内容:
class Model(nn.Module):
def __init__(self):
super().__init__()
self.matrix = torch.randn(784, 10)
def forward(self, x):
return torch.matmul(x, self.matrix)
如果是这样的话,你的第一次尝试不会成功,因为nn.Module.cuda()
方法只会将所有的Parameters
和Buffers
移动到GPU上。
你需要将Model.matrix
变成一个Parameter
,而不是普通的属性。将其包装在参数类中。类似于这样:
self.matrix = nn.Parameter(torch.randn(784, 10))
现在,你没有像上面那样自动转换到GPU,而是尝试在重写中手动对Model.matrix
调用.cuda()
方法。
这也不起作用,因为nn.Module.cuda()
方法和torch.Tensor.cuda()
方法之间存在细微的区别。
虽然nn.Module.cuda()
将Module
的所有Parameters
和Buffers
移动到GPU并返回自身,但torch.Tensor.cuda()
只返回GPU上的张量的副本。
原始张量不受影响。
总结来说,可以采取以下两种方法之一:
- 将你的
matrix
属性包装为Parameter
,或者 - 通过以下方式将GPU副本重新赋值给matrix:
self.matrix = self.matrix.cuda()
在你的重写中。
我建议采用第一种方法。