如何在keras中将词嵌入和softmax权重结合起来?

问题描述 投票:0回答:2

将初始词嵌入层的权重与输出 softmax 的权重联系起来,对于 NLP 和视觉语言问题中的各种神经网络架构来说很常见。通常这会提高句子生成的质量。 (参见示例此处

在 Keras 中,通常使用 Embedding 类嵌入单词嵌入层,但是似乎没有简单的方法将该层的权重与输出 softmax 联系起来。有人知道如何实施吗?

machine-learning neural-network nlp deep-learning keras
2个回答
11
投票

请注意,Press 和 Wolf 并不建议将权重冻结为某些预训练的权重,而是将它们捆绑在一起。这意味着,要确保训练期间输入和输出权重始终相同(同步意义上)。

在典型的 NLP 模型(例如语言建模/翻译)中,您有一个大小为

V
的输入维度(词汇)和一个隐藏表示大小为
H
。然后,从
Embedding
层开始,它是一个矩阵
VxH
。输出层(可能)类似于
Dense(V, activation='softmax')
,它是一个矩阵
H2xV
。当绑定权重时,我们希望这些矩阵是相同的(因此,
H==H2
)。 为了在 Keras 中做到这一点,我认为可行的方法是通过共享层:

在您的模型中,您需要实例化一个共享嵌入层(维度为

VxH
),并将其应用到您的输入和输出。但您需要对其进行转置,以获得所需的输出尺寸 (
HxV
)。因此,我们声明一个
TiedEmbeddingsTransposed
层,它转置给定层的嵌入矩阵(并应用激活函数):

class TiedEmbeddingsTransposed(Layer):
    """Layer for tying embeddings in an output layer.
    A regular embedding layer has the shape: V x H (V: size of the vocabulary. H: size of the projected space).
    In this layer, we'll go: H x V.
    With the same weights than the regular embedding.
    In addition, it may have an activation.
    # References
        - [ Using the Output Embedding to Improve Language Models](https://arxiv.org/abs/1608.05859)
    """
    
    def __init__(self, tied_to=None,
                    activation=None,
                    **kwargs):
        super(TiedEmbeddingsTransposed, self).__init__(**kwargs)
        self.tied_to = tied_to
        self.activation = activations.get(activation)

    def build(self, input_shape):
        self.transposed_weights = K.transpose(self.tied_to.weights[0])
        self.built = True

    def compute_mask(self, inputs, mask=None):
        return mask

    def compute_output_shape(self, input_shape):
        return input_shape[0], K.int_shape(self.tied_to.weights[0])[0]

    def call(self, inputs, mask=None):
        output = K.dot(inputs, self.transposed_weights)
        if self.activation is not None:
            output = self.activation(output)
        return output


    def get_config(self):
        config = {'activation': activations.serialize(self.activation)
                    }
        base_config = super(TiedEmbeddingsTransposed, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

该层的用法是:

# Declare the shared embedding layer
shared_embedding_layer = Embedding(V, H)
# Obtain word embeddings
word_embedding = shared_embedding_layer(input)
# Do stuff with your model
# Compute output (e.g. a vocabulary-size probability vector) with the shared layer:
output = TimeDistributed(TiedEmbeddingsTransposed(tied_to=shared_embedding_layer, activation='softmax')(intermediate_rep)

我已经在 NMT-Keras 中对此进行了测试,并且它可以正常训练。但是,当我尝试加载经过训练的模型时,它出现了一个错误,与 Keras 加载模型的方式相关:它没有从

tied_to
加载权重。我发现了几个与此相关的问题(123),但我还没有设法解决这个问题。如果有人对下一步要采取的任何想法,我会很高兴听到他们:)


0
投票

正如您可能在here阅读的那样,您应该简单地将

trainable
标志设置为
False
。例如

aux_output = Embedding(..., trainable=False)(input)
....
output = Dense(nb_of_classes, .. ,activation='softmax', trainable=False)
© www.soinside.com 2019 - 2024. All rights reserved.