我正在使用序列到lstm模型的序列构建机器翻译(Eng-French)。
我已经看到了kerasseq2seq-lstm
示例,但我不明白如何从文本准备数据,这是用于准备数据的for循环。但是我无法理解其中的一些内容。
for i, (input_text, target_text) in enumerate(zip(input_texts, target_texts)):
for t, char in enumerate(input_text):
encoder_input_data[i, t, input_token_index[char]] = 1.
encoder_input_data[i, t + 1:, input_token_index[' ']] = 1.
for t, char in enumerate(target_text):
# decoder_target_data is ahead of decoder_input_data by one timestep
decoder_input_data[i, t, target_token_index[char]] = 1.
if t > 0:
# decoder_target_data will be ahead by one timestep
# and will not include the start character.
decoder_target_data[i, t - 1, target_token_index[char]] = 1.
decoder_input_data[i, t + 1:, target_token_index[' ']] = 1.
decoder_target_data[i, t:, target_token_index[' ']] = 1.
为什么我们需要三个不同的数据,encoder_input,decoder_input和decoder_ouput?
for t, char in enumerate(target_text):
decoder_input_data[i, t, target_token_index[char]] = 1.
if t > 0:
# decoder_target_data will be ahead by one timestep
# and will not include the start character.
decoder_target_data[i, t - 1, target_token_index[char]] = 1.
# why it's t - 1 shouldn't it be t + 1
在这里,它表示解码器目标将提前一个时间步长,这意味着我要提前表示的意思不是“ t + 1”而不是“ t-1”。我已经读到“我们必须将decode_target_data偏移一个时间步。” 这是什么意思?
如果有可能,您是否可以完整地解释一下for循环,以及在为将来的seq2seq模型准备数据时我要牢记的任何要点?我的意思是我们如何为模型准备数据?这很令人困惑。
好的,我假设您已阅读第11至34行(“算法概述”),因此您了解此特定序列2序列模型背后的基本思想。首先,编码器产生2个“状态向量”(潜在的“某物”)。然后将其馈送到解码器,无论如何,让我们逐步看一下它(第127-132行):
# Define an input sequence and process it.
encoder_inputs = Input(shape=(None, num_encoder_tokens))
encoder = LSTM(latent_dim, return_state=True)
encoder_outputs, state_h, state_c = encoder(encoder_inputs)
# We discard `encoder_outputs` and only keep the states.
encoder_states = [state_h, state_c]
对于LSTM,有两个“状态”,请参见此处:“输出形状”下的https://keras.io/layers/recurrent/。它是处理输入序列后的内部状态-或批次中所有序列的状态数组(行式)。产生的输出将被忽略。latent_dim
表示LSTM单元的数量(第60行:256)-还将确定状态向量的大小。
下一个:
# Set up the decoder, using `encoder_states` as initial state.
decoder_inputs = Input(shape=(None, num_decoder_tokens))
# We set up our decoder to return full output sequences,
# and to return internal states as well. We don't use the
# return states in the training model, but we will use them in inference.
decoder_lstm = LSTM(latent_dim, return_sequences=True, return_state=True)
decoder_outputs, _, _ = decoder_lstm(decoder_inputs,
initial_state=encoder_states)
decoder_dense = Dense(num_decoder_tokens, activation='softmax')
decoder_outputs = decoder_dense(decoder_outputs)
# Define the model that will turn
# `encoder_input_data` & `decoder_input_data` into `decoder_target_data`
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
首先,请注意,此模型不是Sequential
,它使用功能性API:https : //keras.io/models/model/-因此,输入既是编码器又是解码器输入,输出是解码器输出。
解码器输出的大小?num_decoder_tokens
字典的大小!(不是输出序列)。给定“历史记录”和当前输入,它应该在输出序列中产生下一个字符的概率分布,但是此“历史记录”(初始内部状态)是编码器在处理输入序列后的最终状态。
注意-解码器将使用编码器的最终状态进行初始化,然后,在对每个字符进行采样之后,修改后的状态将与新的“输入”一起用于下一个推论-新的“输入”是最后预测的单向矢量字符。
现在,对您的问题-我想您想了解,为什么训练数据看起来像它的样子。
首先(第104-112行):
encoder_input_data = np.zeros(
(len(input_texts), max_encoder_seq_length, num_encoder_tokens),
dtype='float32')
decoder_input_data = np.zeros(
(len(input_texts), max_decoder_seq_length, num_decoder_tokens),
dtype='float32')
decoder_target_data = np.zeros(
(len(input_texts), max_decoder_seq_length, num_decoder_tokens),
dtype='float32')
编码器训练集由每批组成len(input_texts)
。下一个维度是最大序列长度,第三个维度是标记(“字符”)索引,在文本中找到所有字母(num_encoder_tokens
-英文字母和num_decoder_tokens
-法语字母,加上'\t'
句子的开头或其他内容)。
因此,让我们用字符串来说明它,然后显示出一点点的区别。
假设解码器的输出顺序为'Bonjour'
(抱歉,我不知道法语),并假设“ max_decoder_seq_length == 10”。然后,
decoder_input_data = 'Bonjour ' # 3 spaces, to fill up to 10
decoder_output_data = 'onjour ' # 4 spaces, to fill up to 10
但是,它不能表示为简单的字符串-实际上是掩码-0表示不是此字符,而1表示-是。
所以它更像是:
decoder_input_data[0]['B'] = 1 # and decoder_input_data[0][anything_else] == 0
decoder_input_data[1]['o'] = 1 # HERE: t == 1
decoder_input_data[2]['n'] = 1
# ...
decoder_input_data[6]['r'] = 1
decoder_input_data[7:10][' '] = 1 # the padding
编码器必须向左移动1:
# for t == 0, the `decoder_output_data` is not touched (`if t > 0`)
# decoder_output_data[t-1]['o'] = 1 # t-1 == 0
decoder_output_data[0]['o'] = 1 # t == 1
decoder_output_data[1]['n'] = 1 # t == 2
decoder_output_data[2]['j'] = 1 # t == 3
# ...
decoder_output_data[6:10][' '] = 1 # output padding with spaces, longer by 1 than input padding
因此,这基本上是“为什么要t-1”的答案。
现在“为什么我们需要3个输入数据”?
嗯,这是seq2seq方法的想法:
给定前一个(和初始状态),我们需要解码器学习产生正确的下一个法语字符。这就是为什么它从转移的输出序列中学习的原因。
但是,它首先应该产生什么顺序?嗯,这就是编码器的目的-它产生一个最终状态-通过读取输入序列“记住”的一切。通过我们的训练,我们使这种状态(每个序列2个向量,每个256个浮点数)指导解码器产生输出序列。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句