如何在 Keras 中实现 RNN 序列到序列学习?本文中,作者将尝试对这一问题做出简短解答;本文预设你已有一些循环网络和 Keras 的使用经验。
公司主营业务:成都做网站、网站制作、成都外贸网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联公司是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联公司推出始兴免费做网站回馈大家。
GitHub:https://github.com/fchollet/keras/blob/master/examples/lstm_seq2seq.py
什么是序列到序列学习?
序列到序列学习(Seq2Seq)是指训练模型从而把一个域的序列(比如英语语句)转化为另一个域的序列(比如法语中的对应语句)。
- "the cat sat on the mat"->[Seq2Seqmodel]->"le chat etait assis sur le tapis"
Seq2Seq 可用于机器翻译或者省去问题回答——通常来讲,它可以随时生成文本。完成这一任务有很多方式,比如 RNN 或一维卷积。本文只介绍 RNN。
次要案例:当输入序列和输出序列长度相同
当输入序列和输出序列长度相同时,你可以通过 Keras LSTM 或者 GRU 层(或者其中的堆栈)简单地实现模型。这一实例脚本中的案例展示了如何教会 RNN 学习添加被编码为字符串的数字:
一般案例:标准的 Seq2Seq
一般情况下,输入序列和输出序列有不同的长度(比如机器翻译)。这就需要一个更高级的设置,尤其在没有进一步语境的「序列到序列模型」时。下面是其工作原理:
在推理模式中,即当要解码未知的输入序列,我们完成了一个稍微不同的处理:
相同的处理也可被用于训练没有「teacher forcing」的 Seq2Seq 网络,即把解码器的预测再注入到解码器之中。
Keras 实例
让我们用实际的代码演示一下这些想法。
对于实例实现,我们将使用一对英语语句及其法语翻译的数据集,你可以从
http://www.manythings.org/anki/下载它,文件的名称是 fra-eng.zip。我们将会实现一个字符级别的序列到序列模型,逐个字符地处理这些输入并生成输出。另一个选择是单词级别的模型,它对机器学习更常用。在本文最后,你会发现通过嵌入层把我们的模型转化为单词级别模型的一些注释。
这是实例的全部脚本:
https://github.com/fchollet/keras/blob/master/examples/lstm_seq2seq.py。
下面是这一过程的总结:
1. 把语句转化为 3 个 Numpy 数组 encoder_input_data、decoder_input_data、decoder_target_data:
2. 在给定 encoder_input_data 和 decoder_input_data 的情况下,训练一个基本的基于 LSTM 的 Seq2Seq 模型以预测 decoder_target_data。我们的模型使用 teacher forcing。
3. 解码一些语句以检查模型正在工作。
由于训练过程和推理过程(解码语句)相当不同,我们使用了不同的模型,虽然两者具有相同的内在层。这是我们的模型,它利用了 Keras RNN 的 3 个关键功能:
- fromkeras.models importModel
- fromkeras.layers importInput,LSTM,Dense
- # 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]
- # 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)
我们用这两行代码训练模型,同时在 20% 样本的留存集中监测损失。
- # Run training
- model.compile(optimizer='rmsprop',loss='categorical_crossentropy')
- model.fit([encoder_input_data,decoder_input_data],decoder_target_data,
- batch_sizebatch_size=batch_size,
- epochsepochs=epochs,
- validation_split=0.2)
大约 1 小时后在 MacBook CPU 上,我们已准备好做推断。为了解码测试语句,我们将重复:
编码输入语句,检索初始解码器状态。
用初始状态运行一步解码器,以「序列开始」为目标。输出即是下一个目标字符。
附加预测到的目标字符并重复。
这是我们的推断设置:
- encoder_model =Model(encoder_inputs,encoder_states)
- decoder_state_input_h =Input(shape=(latent_dim,))
- decoder_state_input_c =Input(shape=(latent_dim,))
- decoder_states_inputs =[decoder_state_input_h,decoder_state_input_c]
- decoder_outputs,state_h,state_c =decoder_lstm(
- decoder_inputs,initial_state=decoder_states_inputs)
- decoder_states =[state_h,state_c]
- decoder_outputs =decoder_dense(decoder_outputs)
- decoder_model =Model(
- [decoder_inputs]+decoder_states_inputs,
- [decoder_outputs]+decoder_states)
我们使用它实现上述推断循环(inference loop):
- defdecode_sequence(input_seq):
- # Encode the input as state vectors.
- states_value =encoder_model.predict(input_seq)
- # Generate empty target sequence of length 1.
- target_seq =np.zeros((1,1,num_decoder_tokens))
- # Populate the first character of target sequence with the start character.
- target_seq[0,0,target_token_index['t']]=1.
- # Sampling loop for a batch of sequences
- # (to simplify, here we assume a batch of size 1).
- stop_condition =False
- decoded_sentence =''
- whilenotstop_condition:
- output_tokens,h,c =decoder_model.predict(
- [target_seq]+states_value)
- # Sample a token
- sampled_token_index =np.argmax(output_tokens[0,-1,:])
- sampled_char =reverse_target_char_index[sampled_token_index]
- decoded_sentence +=sampled_char
- # Exit condition: either hit max length
- # or find stop character.
- if(sampled_char =='n'or
- len(decoded_sentence)>max_decoder_seq_length):
- stop_condition =True
- # Update the target sequence (of length 1).
- target_seq =np.zeros((1,1,num_decoder_tokens))
- target_seq[0,0,sampled_token_index]=1.
- # Update states
- states_value =[h,c]
- returndecoded_sentence
我们得到了一些不错的结果——这在意料之中,因为我们解码的样本来自训练测试。
- Inputsentence:Benice.
- Decodedsentence:Soyezgentil !
- -
- Inputsentence:Dropit!
- Decodedsentence:Laisseztomber !
- -
- Inputsentence:Getout!
- Decodedsentence:Sortez !
这就是我们的十分钟入门 Keras 序列到序列模型教程。完整代码详见 GitHub:
https://github.com/fchollet/keras/blob/master/examples/lstm_seq2seq.py。
常见问题
1. 我想使用 GRU 层代替 LSTM,应该怎么做?
这实际上变简单了,因为 GRU 只有一个状态,而 LSTM 有两个状态。这是使用 GRU 层适应训练模型的方法:
- encoder_inputs =Input(shape=(None,num_encoder_tokens))
- encoder =GRU(latent_dim,return_state=True)
- encoder_outputs,state_h =encoder(encoder_inputs)
- decoder_inputs =Input(shape=(None,num_decoder_tokens))
- decoder_gru =GRU(latent_dim,return_sequences=True)
- decoder_outputs =decoder_gru(decoder_inputs,initial_state=state_h)
- decoder_dense =Dense(num_decoder_tokens,activation='softmax')
- decoder_outputs =decoder_dense(decoder_outputs)
- model =Model([encoder_inputs,decoder_inputs],decoder_outputs)
2. 我想使用整数序列的单词级别模型,应该怎么做?
如果你的输入是整数序列(如按词典索引编码的单词序列),你可以通过 Embedding 层嵌入这些整数标记。方法如下:
- # Define an input sequence and process it.
- encoder_inputs =Input(shape=(None,))
- x =Embedding(num_encoder_tokens,latent_dim)(encoder_inputs)
- x,state_h,state_c =LSTM(latent_dim,
- return_state=True)(x)
- encoder_states =[state_h,state_c]
- # Set up the decoder, using `encoder_states` as initial state.
- decoder_inputs =Input(shape=(None,))
- x =Embedding(num_decoder_tokens,latent_dim)(decoder_inputs)
- x =LSTM(latent_dim,return_sequences=True)(x,initial_state=encoder_states)
- decoder_outputs =Dense(num_decoder_tokens,activation='softmax')(x)
- # Define the model that will turn
- # `encoder_input_data` & `decoder_input_data` into `decoder_target_data`
- model =Model([encoder_inputs,decoder_inputs],decoder_outputs)
- # Compile & run training
- model.compile(optimizer='rmsprop',loss='categorical_crossentropy')
- # Note that `decoder_target_data` needs to be one-hot encoded,
- # rather than sequences of integers like `decoder_input_data`!
- model.fit([encoder_input_data,decoder_input_data],decoder_target_data,
- batch_sizebatch_size=batch_size,
- epochsepochs=epochs,
- validation_split=0.2)
3. 如果我不想使用「teacher forcing」,应该怎么做?
一些案例中可能不能使用 teacher forcing,因为你无法获取完整的目标序列,比如,在线训练非常长的语句,则缓冲完成输入-目标语言对是不可能的。在这种情况下,你要通过将解码器的预测重新注入解码器输入进行训练,就像我们进行推断时所做的那样。
你可以通过构建硬编码输出再注入循环(output reinjection loop)的模型达到该目标:
- fromkeras.layers importLambda
- fromkeras importbackend asK
- # The first part is unchanged
- encoder_inputs =Input(shape=(None,num_encoder_tokens))
- encoder =LSTM(latent_dim,return_state=True)
- encoder_outputs,state_h,state_c =encoder(encoder_inputs)
- states =[state_h,state_c]
- # Set up the decoder, which will only process one timestep at a time.
- decoder_inputs =Input(shape=(1,num_decoder_tokens))
- decoder_lstm =LSTM(latent_dim,return_sequences=True,return_state=True)
- decoder_dense =Dense(num_decoder_tokens,activation='softmax')
- all_outputs =[]
- inputs =decoder_inputs
- for_ inrange(max_decoder_seq_length):
- # Run the decoder on one timestep
- outputs,state_h,state_c =decoder_lstm(inputs,
- initial_state=states)
- outputs =decoder_dense(outputs)
- # Store the current prediction (we will concatenate all predictions later)
- all_outputs.append(outputs)
- # Reinject the outputs as inputs for the next loop iteration
- # as well as update the states
- inputs =outputs
- states =[state_h,state_c]
- # Concatenate all predictions
- decoder_outputs =Lambda(lambdax:K.concatenate(x,axis=1))(all_outputs)
- # Define and compile model as previously
- model =Model([encoder_inputs,decoder_inputs],decoder_outputs)
- model.compile(optimizer='rmsprop',loss='categorical_crossentropy')
- # Prepare decoder input data that just contains the start character
- # Note that we could have made it a constant hard-coded in the model
- decoder_input_data =np.zeros((num_samples,1,num_decoder_tokens))
- decoder_input_data[:,0,target_token_index['t']]=1.
- # Train model as previously
- model.fit([encoder_input_data,decoder_input_data],decoder_target_data,
- batch_sizebatch_size=batch_size,
- epochsepochs=epochs,
- validation_split=0.2)
原文:
https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html
【本文是专栏机构“机器之心”的原创译文,微信公众号“机器之心( id: almosthuman2014)”】
戳这里,看该作者更多好文
当前题目:十分钟搞定Keras序列到序列学习(附代码实现)
链接URL:http://www.36103.cn/qtweb/news36/34636.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联