Basierend auf meinen Erkenntnissen im Pytorch-Diskussionsforum gibt es dafür mehrere Möglichkeiten.
Als Beispiel, basierend auf dieser Diskussion, dachte ich, dass es reichen würde, einfach die transponierten Gewichtungen zuzuweisen. Das macht:
Code: Select all
self.decoder[0].weight = self.encoder[0].weight.t()
Ich habe dann versucht, die obige Zeile in einen nn.Parameter() einzuschließen:
Code: Select all
self.decoder[0].weight = nn.Parameter(self.encoder[0].weight.t())
Ich habe dann gefunden Dieser Link bietet verschiedene Möglichkeiten zum Teilen von Gewichten. Allerdings bin ich skeptisch, ob alle dort angegebenen Methoden tatsächlich korrekt sind.
Eine Möglichkeit wird beispielsweise so demonstriert:
Code: Select all
# 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
Code: Select all
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)
Klont es nicht nur die „Rohdaten“?
Als ich diesen Ansatz verwendete und die Gewichte visualisierte, bemerkte ich, dass die Visualisierungen anders waren und das machte mich noch sicherer, dass etwas nicht stimmte.
Ich bin mir nicht sicher wenn die unterschiedlichen Visualisierungen nur darauf zurückzuführen wären, dass eine davon transponiert wurde die andere, oder wie ich gerade schon vermutet habe, werden sie unabhängig voneinander optimiert (d. h. die Gewichte werden nicht zwischen den Schichten geteilt)
Beispiel für die Gewichtsinitialisierung:

