如何在 Pytorch 中的模块之间共享权重?

Rik*_*ika 5 python pytorch

Pytorch 中两层(模块)之间共享权重的正确方法是什么?
根据我在 Pytorch 讨论论坛中的发现,有多种方法可以做到这一点。
举个例子,根据这个讨论,我认为简单地分配转置权重就可以了。那是在做:

 self.decoder[0].weight = self.encoder[0].weight.t()
Run Code Online (Sandbox Code Playgroud)

然而,事实证明这是错误的并导致错误。然后我尝试将上面的行包装在nn.Parameter()

self.decoder[0].weight = nn.Parameter(self.encoder[0].weight.t())
Run Code Online (Sandbox Code Playgroud)

这消除了错误,但话又说回来,这里没有发生共享。通过这个,我刚刚初始化了一个新的张量,其值与encoder[0].weight.t().

然后我发现这个链接提供了共享权重的不同方法。然而,我怀疑那里给出的所有方法是否实际上都是正确的。
例如,一种方法是这样演示的:

# tied autoencoder using off the shelf nn modules
class TiedAutoEncoderOffTheShelf(nn.Module):
    def __init__(self, inp, out, weight):
        super().__init__()
        self.encoder = nn.Linear(inp, out, bias=False)
        self.decoder = nn.Linear(out, inp, bias=False)

        # tie the weights
        self.encoder.weight.data = weight.clone()
        self.decoder.weight.data = self.encoder.weight.data.transpose(0,1)

    def forward(self, input):
        encoded_feats = self.encoder(input)
        reconstructed_output = self.decoder(encoded_feats)
        return encoded_feats, reconstructed_output
Run Code Online (Sandbox Code Playgroud)

基本上它使用创建一个新的权重张量nn.Parameter()并将其分配给每个层/模块,如下所示:

weights = nn.Parameter(torch.randn_like(self.encoder[0].weight))
self.encoder[0].weight.data = weights.clone()
self.decoder[0].weight.data = self.encoder[0].weight.data.transpose(0, 1)
Run Code Online (Sandbox Code Playgroud)

这真的让我很困惑,这两个层之间如何共享相同的变量?这不只是克隆“原始”数据吗?
当我使用这种方法并对权重进行可视化时,我注意到可视化效果有所不同,这让我更加确定有些事情是不对的。
我不确定不同的可视化是否仅仅是由于一个可视化是另一个可视化的转置,或者正如我已经怀疑的那样,它们是独立优化的(即权重不在层之间共享)

权重初始化示例: 在此输入图像描述 在此输入图像描述

Rik*_*ika 1

事实证明,经过进一步调查,即简单地重新转换解码器的权重并将其可视化,它们确实是共享的。
下面是编码器和解码器权重的可视化: 在此输入图像描述 在此输入图像描述