我正在阅读 Aurelion Geron 的“Hands-On Machine Learning with Scikit-Learn and TensorFlow”。我目前正在阅读本书的编码器-解码器部分,偶然发现了一些我不完全理解的代码,并且我发现书中的解释并不令人满意(至少对于像我这样的初学者来说)。下图展示了我们正在尝试实现的模型(或者更准确地说,我们将实现一个与下图类似的模型,不完全是这个模型):
(图片来自Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow,第 16 章,第 543 页,图 16-3)
这是使用的代码(同样,上面的模型不是我们要编码的确切内容。作者明确表示我们将构建的模型与上图类似):
import tensorflow_addons as tfa
encoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)
decoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)
sequence_lengths = keras.layers.Input(shape=[], dtype=np.int32)
embeddings = keras.layers.Embedding(vocab_size, embed_size)
encoder_embeddings = embeddings(encoder_inputs)
decoder_embeddings = embeddings(decoder_inputs)
encoder = keras.layers.LSTM(512, return_state=True)
encoder_outputs, state_h, state_c = encoder(encoder_embeddings)
encoder_state = [state_h, state_c]
sampler = tfa.seq2seq.sampler.TrainingSampler()
decoder_cell = keras.layers.LSTMCell(512)
output_layer = keras.layers.Dense(vocab_size)
decoder = tfa.seq2seq.basic_decoder.BasicDecoder(decoder_cell, sampler,
output_layer=output_layer)
final_outputs, final_state, final_sequence_lengths = decoder(
decoder_embeddings, initial_state=encoder_state,
sequence_length=sequence_lengths)
Y_proba = tf.nn.softmax(final_outputs.rnn_output)
model = keras.Model(inputs=[encoder_inputs, decoder_inputs, sequence_lengths],
outputs=[Y_proba])
上面的代码中有些事情我不知道他们在做什么,有些事情我认为我知道他们在做什么,所以我将尝试准确解释我的困惑。如果我从这一点上说的任何内容有误,请告诉我。
我们导入 tensorflow_addons。
在第 2-4 行中,我们为编码器、解码器和原始字符串创建输入层。我们可以在图片中看到它们的去向。这里出现了第一个困惑:为什么 shape of是一个包含 in元素的列表,encoder_inputs
而shape of是一个空列表?这些形状的含义是什么?为什么它们不同?为什么我们必须像这样初始化它们?decoder_inputs
None
sequence_lengths
在第 5-7 行中,我们创建了嵌入层并将其应用于编码器输入和解码器输入。
在第 8-10 行中,我们为编码器创建了 LSTM 层。我们保存 LSTM 的隐藏状态h
和记忆单元状态C
,因为这将是解码器的输入。
第 11 行对我来说是另一个困惑。我们显然创建了一个所谓的TrainingSampler
,但我不知道这是什么或它做什么。用作者的话来说:
TrainingSampler 是 TensorFlow Addons 中可用的几个采样器之一:它们的作用是在每一步告诉解码器它应该假装以前的输出是什么。在推理过程中,这应该是实际输出的令牌的嵌入。在训练期间,应该是之前目标令牌的嵌入:这就是我们使用 TrainingSampler 的原因。
我真的不明白这个解释。具体是TrainingSampler
做什么的?它是否告诉解码器正确的先前输出是先前的目标?它是如何做到的?更重要的是,我们是否需要在推理过程中更改这个采样器(因为我们在推理过程中没有目标)?
在第 12 和 13 行,我们定义了解码器单元和输出层。我的问题是为什么我们将解码器定义为LSTMCell
,而我们将编码器声明为 ,而LSTM
不是单元格。我阅读了LSTM
作为循环层的stackoverflow,同时LSTMCell
包含一步的计算逻辑。但我不明白为什么我们必须LSTM
在编码器和LSTMCell
解码器中使用。为什么会有这种差异?是因为在下一行中,BasicDecoder
实际上需要一个单元格吗?
在接下来的几行中,我们定义BasicDecoder
并将其应用于解码器嵌入(同样,我不知道sequence_lengths
这里是做什么的)。我们得到最终输出,然后我们将其传递给 softmax 函数。
该代码中发生了很多事情,我对发生的事情感到非常困惑。如果有人能把事情弄清楚一点,我将非常感激。