即使使用显式 cuda() 调用,pytorch 实例张量也不会移动到 gpu

Lui*_*eal 3 python artificial-intelligence machine-learning pytorch

我正在开发一个项目,其中模型需要访问我在类的构造函数init中声明的张量(我对 torch.nn.Module 类进行了子类),然后我需要在 forward() 中使用这个张量通过简单的 matmul() 方法,模型通过 cuda() 调用发送到 GPU:

model = Model()
model.cuda()
Run Code Online (Sandbox Code Playgroud)

但是,当我通过以下方式对简单输入 X 进行前向传播时:

model(X) # or model.forward(X)
Run Code Online (Sandbox Code Playgroud)

我得到

RuntimeError: 类型为 torch.cuda.FloatTensor 的预期对象,但为参数 #2 'mat2' 找到类型 torch.FloatTensor

表示 matmul 的第二个参数(我声明的实例张量)在 CPU 上,并且在 GPU 上是预期的(作为模型和数据的其余部分)。

在 matmul 中,张量通过 matrix.t() 转置

我什至尝试通过覆盖 cuda() 方法:

def cuda(self):
    super().cuda()
    self.matrix.cuda()
Run Code Online (Sandbox Code Playgroud)

数据已经在 GPU 中,这意味着已经执行了以下代码行:

X = X.cuda()
Run Code Online (Sandbox Code Playgroud)

错误还明确指出 matmul 的参数 2,在这种情况下,它是张量(称为矩阵)而不是 X。

dre*_*cko 8

我想从@Vaisakh 的回答中强调这一点:

nn.Module.cuda() 将模块的所有参数和缓冲区移动到 GPU 并返回自身,而 torch.Tensor.cuda()只返回GPU 上张量的副本。

换句话说,正如@Umang_Gupta 在他的评论中所说:

# if m is a Module, you do:
m.cuda()

# if t is a Tensor, you do:
t = t.cuda()
Run Code Online (Sandbox Code Playgroud)


小智 7

让我们假设以下情况:

  1. X 正确移动到 GPU

  2. 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)
Run Code Online (Sandbox Code Playgroud)

如果是这样,您的第一次尝试将不起作用,因为该nn.Module.cuda()方法仅将所有Parameters和移动Buffers到 GPU。

您需要创建Model.matrix一个Parameter而不是常规属性。将其包装在参数类中。就像是:

self.matrix = nn.Parameter(torch.randn(784, 10))
Run Code Online (Sandbox Code Playgroud)

现在,您尝试在覆盖中手动调用.cuda()方法,而不是像上面那样自动转换到 GPU Model.matrix

由于nn.Module.cuda()方法和torch.Tensor.cuda()方法之间的细微差别,这也不起作用。

虽然nn.Module.cuda()移动所有的ParametersBuffersModule对GPU和回报本身,torch.Tensor.cuda()只返回一个副本的张量在GPU上。

原始张量不受影响。


总之,要么:

  1. 将您的matrix属性包装为Parameter
  2. 通过以下方式将 GPU 副本分配回矩阵:
self.matrix = self.matrix.cuda()
Run Code Online (Sandbox Code Playgroud)

在您的覆盖中。

我会建议第一个。