Skip to main content
 首页 » 编程设计

python之在 PyTorch 中使用 module.to() 移动成员张量

2025年05月04日15fff_TT

我正在 PyTorch 中构建变分自动编码器 (VAE),但在编写与设备无关的代码时遇到了问题。 Autoencoder 是 nn.Module 的子项,具有编码器和解码器网络,它们也是。通过调用 net.to(device),可以将网络的所有权重从一台设备转移到另一台设备。

我遇到的问题是重新参数化技巧:

encoding = mu + noise * sigma 

噪声是一个与mu和sigma大小相同的张量,保存为autoencoder模块的成员变量。它在构造函数中初始化,并在每个训练步骤中就地重新采样。我这样做是为了避免每一步都构建一个新的噪声张量并将其推送到所需的设备。此外,我想修复评估中的噪音。这是代码:

class VariationalGenerator(nn.Module): 
    def __init__(self, input_nc, output_nc): 
        super(VariationalGenerator, self).__init__() 
 
        self.input_nc = input_nc 
        self.output_nc = output_nc 
        embedding_size = 128 
 
        self._train_noise = torch.randn(batch_size, embedding_size) 
        self._eval_noise = torch.randn(1, embedding_size) 
        self.noise = self._train_noise 
 
        # Create encoder 
        self.encoder = Encoder(input_nc, embedding_size) 
        # Create decoder 
        self.decoder = Decoder(output_nc, embedding_size) 
 
    def train(self, mode=True): 
        super(VariationalGenerator, self).train(mode) 
        self.noise = self._train_noise 
 
    def eval(self): 
        super(VariationalGenerator, self).eval() 
        self.noise = self._eval_noise 
 
    def forward(self, inputs): 
        # Calculate parameters of embedding space 
        mu, log_sigma = self.encoder.forward(inputs) 
        # Resample noise if training 
        if self.training: 
            self.noise.normal_() 
        # Reparametrize noise to embedding space 
        inputs = mu + self.noise * torch.exp(0.5 * log_sigma) 
        # Decode to image 
        inputs = self.decoder(inputs) 
 
        return inputs, mu, log_sigma 

当我现在使用 net.to('cuda:0') 将自动编码器移动到 GPU 时,我在转发时遇到错误,因为噪声张量没有移动。

我不想在构造函数中添加设备参数,因为那样以后仍然无法将其移动到另一个设备。我还尝试将噪声包装到 nn.Parameter 中,以便它受到 net.to() 的影响,但这会导致优化器出错,因为噪声是标记为 requires_grad=False。

谁有解决方案,可以使用 net.to() 移动所有模块?

请您参考如下方法:

tilman151's second approach 的更好版本可能是覆盖_apply,而不是to。这样 net.cuda()、net.float() 等都可以正常工作,因为它们都调用 _apply 而不是 to(如 the source 所示,比您想象的要简单):

def _apply(self, fn): 
    super(VariationalGenerator, self)._apply(fn) 
    self._train_noise = fn(self._train_noise) 
    self._eval_noise = fn(self._eval_noise) 
    return self