使用RNNs进行机器翻译——介绍RNN和LSTM网络及其应用

[复制链接]
505860917a 发表于 2019-3-13 18:07:52 | 显示全部楼层 |阅读模式
来源:https://www.toutiao.com/group/6667024196603740685/
若内容不全,可点击上述链接查看来源网页,在网页中点击红色双层向下的箭头阅读全文


循环神经网络

RNNs是一种特殊类型的神经网络,具有允许信息在网络中的不同步骤中持续存在的循环

循环神经网络的循环

循环使神经网络返回并检查所有先前单词中发生的事情,然后再确定当前单词的实际含义。RNN可以被看作是重复地复制粘贴同一网络,每次新的复制粘贴添加的信息比前一个更多。

展开的循环神经网络

RNN的应用与传统的NN有很大的不同,因为它们没有一个具体的输出和输入集,而是以序列作为输入或输出。

那么我们可以用RNN干什么?

  • 自然语言处理
  • 股票市场数据(时间序列分析)
  • 图像/视频字幕
  • 翻译
  • 等等等等

RNN也有不同的模型可供遵循。

1.固定到序列

RNN接收固定大小的输入并输出序列。

对图像进行分析后生成文本

2.序列到固定

RNN接收输入序列并输出固定大小。

情绪分析,其中给定的句子被分类为表达积极或消极情绪

3.序列到序列

RNN接收输入序列并输出序列。

机器翻译:RNN用一种语言读取一个句子,然后在另一种语言中输出

这可以帮助您高度了解RNNs!

消失的梯度问题

在使用基于梯度的优化技术的任何网络中都会出现此问题当计算反向传播(计算相对于权重的损失梯度)时,随着反向传播算法在网络中移动,梯度变得非常小。这会导致较早的层比以后的层学习速度慢。这降低了RNNs的有效性,因为它们通常无法充分考虑长序列。随着所需信息之间的差距变大,RNN的效率越来越差。

现在这个问题的一个常见解决方案是使用不会导致梯度消失的激活函数,例如RELU,而不是其他激活函数,如sigmoid或hyperbolictangent。更好的解决方案是使用长短期记忆网络!

长、短期记忆

LSTM网络的设计只有一个目的——解决传统RNNs所具有的长期依赖性问题。

LSTM中的重复模块包含4层,而RNN中只有一层

LSTMs运行良好的原因主要是由于网络中存在的单元状态。这是您在图中的网络顶部看到的行。信息很容易流经这个单元状态而不会被改变。连接到单元状态的门可以在需要时添加或删除信息。

神经机器翻译

由于我们对LSTMs和RNNs有了基本的了解,让我们尝试将其中的一部分用于使用Keras开发机器翻译模型。

这将演示如何使用序列到序列LSTM网络将文本从英语翻译成法语。

from__future__importprint_functionfromkeras.modelsimportModelfromkeras.layersimportInput,LSTM,Denseimportnumpyasnpbatch_size=64#Batchsizefortraining.epochs=100#Numberofepochstotrainfor.latent_dim=256#Latentdimensionalityoftheencodingspace.num_samples=10000#Numberofsamplestotrainon.#Pathtothedatatxtfileondisk.data_path='fra-eng/fra.txt'

我们从Keras导入LSTM层并在此处设置几个重要变量。

input_texts=[]target_texts=[]input_characters=set()target_characters=set()withopen(data_path,'r',encoding='utf-8')asf:lines=f.read().split('\n')forlineinlines[:min(num_samples,len(lines)-1)]:input_text,target_text=line.split('\t')#Weuse"tab"asthe"startsequence"character#forthetargets,and"\n"as"endsequence"character.target_text='\t'+target_text+'\n'input_texts.append(input_text)target_texts.append(target_text)forcharininput_text:ifcharnotininput_characters:input_characters.add(char)forcharintarget_text:ifcharnotintarget_characters:target_characters.add(char)input_characters=sorted(list(input_characters))target_characters=sorted(list(target_characters))num_encoder_tokens=len(input_characters)num_decoder_tokens=len(target_characters)max_encoder_seq_length=max([len(txt)fortxtininput_texts])max_decoder_seq_length=max([len(txt)fortxtintarget_texts])

现在我们需要将文本向量化为数字格式,使神经网络更容易处理。

encoder_inputs=Input(shape=(None,num_encoder_tokens))encoder=LSTM(latent_dim,return_state=True)encoder_outputs,state_h,state_c=encoder(encoder_inputs)#Wediscard`encoder_outputs`andonlykeepthestates.encoder_states=[state_h,state_c]#Setupthedecoder,using`encoder_states`asinitialstate.decoder_inputs=Input(shape=(None,num_decoder_tokens))#Wesetupourdecodertoreturnfulloutputsequences,#andtoreturninternalstatesaswell.Wedon'tusethe#returnstatesinthetrainingmodel,butwewillusethemininference.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)#Definethemodelthatwillturn#`encoder_input_data`&`decoder_input_data`into`decoder_target_data`model=Model([encoder_inputs,decoder_inputs],decoder_outputs)

现在我们需要创建我们的模型。由于它是序列到序列的模型,我们需要有两个部分—编码器和解码器。编码器输出隐藏状态,其中包含作为输入获得的所有信息。然后解码器获取此信息,然后以指定的格式生成输出(在本例中,它是法语)。

在此之后,只需训练模型并使用它。如下所示:

'''#SequencetosequenceexampleinKeras(character-level).Thisscriptdemonstrateshowtoimplementabasiccharacter-levelsequence-to-sequencemodel.WeapplyittotranslatingshortEnglishsentencesintoshortFrenchsentences,character-by-character.Notethatitisfairlyunusualtodocharacter-levelmachinetranslation,asword-levelmodelsaremorecommoninthisdomain.**Datadownload**[EnglishtoFrenchsentencepairs.](http://www.manythings.org/anki/fra-eng.zip)[Lotsofneatsentencepairsdatasets.](http://www.manythings.org/anki/)'''from__future__importprint_functionfromkeras.modelsimportModelfromkeras.layersimportInput,LSTM,Denseimportnumpyasnpbatch_size=64#Batchsizefortraining.epochs=100#Numberofepochstotrainfor.latent_dim=256#Latentdimensionalityoftheencodingspace.num_samples=10000#Numberofsamplestotrainon.#Pathtothedatatxtfileondisk.data_path='fra-eng/fra.txt'#Vectorizethedata.input_texts=[]target_texts=[]input_characters=set()target_characters=set()withopen(data_path,'r',encoding='utf-8')asf:lines=f.read().split('\n')forlineinlines[:min(num_samples,len(lines)-1)]:input_text,target_text=line.split('\t')#Weuse"tab"asthe"startsequence"character#forthetargets,and"\n"as"endsequence"character.target_text='\t'+target_text+'\n'input_texts.append(input_text)target_texts.append(target_text)forcharininput_text:ifcharnotininput_characters:input_characters.add(char)forcharintarget_text:ifcharnotintarget_characters:target_characters.add(char)input_characters=sorted(list(input_characters))target_characters=sorted(list(target_characters))num_encoder_tokens=len(input_characters)num_decoder_tokens=len(target_characters)max_encoder_seq_length=max([len(txt)fortxtininput_texts])max_decoder_seq_length=max([len(txt)fortxtintarget_texts])print('Numberofsamples:',len(input_texts))print('Numberofuniqueinputtokens:',num_encoder_tokens)print('Numberofuniqueoutputtokens:',num_decoder_tokens)print('Maxsequencelengthforinputs:',max_encoder_seq_length)print('Maxsequencelengthforoutputs:',max_decoder_seq_length)input_token_index=dict([(char,i)fori,charinenumerate(input_characters)])target_token_index=dict([(char,i)fori,charinenumerate(target_characters)])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')fori,(input_text,target_text)inenumerate(zip(input_texts,target_texts)):fort,charinenumerate(input_text):encoder_input_data[i,t,input_token_index[char]]=1.fort,charinenumerate(target_text):#decoder_target_dataisaheadofdecoder_input_databyonetimestepdecoder_input_data[i,t,target_token_index[char]]=1.ift>0:#decoder_target_datawillbeaheadbyonetimestep#andwillnotincludethestartcharacter.decoder_target_data[i,t-1,target_token_index[char]]=1.#Defineaninputsequenceandprocessit.encoder_inputs=Input(shape=(None,num_encoder_tokens))encoder=LSTM(latent_dim,return_state=True)encoder_outputs,state_h,state_c=encoder(encoder_inputs)#Wediscard`encoder_outputs`andonlykeepthestates.encoder_states=[state_h,state_c]#Setupthedecoder,using`encoder_states`asinitialstate.decoder_inputs=Input(shape=(None,num_decoder_tokens))#Wesetupourdecodertoreturnfulloutputsequences,#andtoreturninternalstatesaswell.Wedon'tusethe#returnstatesinthetrainingmodel,butwewillusethemininference.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)#Definethemodelthatwillturn#`encoder_input_data`&`decoder_input_data`into`decoder_target_data`model=Model([encoder_inputs,decoder_inputs],decoder_outputs)#Runtrainingmodel.compile(optimizer='rmsprop',loss='categorical_crossentropy')model.fit([encoder_input_data,decoder_input_data],decoder_target_data,batch_size=batch_size,epochs=epochs,validation_split=0.2)#Savemodelmodel.save('s2s.h5')#Next:inferencemode(sampling).#Here'sthedrill:#1)encodeinputandretrieveinitialdecoderstate#2)runonestepofdecoderwiththisinitialstate#anda"startofsequence"tokenastarget.#Outputwillbethenexttargettoken#3)Repeatwiththecurrenttargettokenandcurrentstates#Definesamplingmodelsencoder_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)#Reverse-lookuptokenindextodecodesequencesbackto#somethingreadable.reverse_input_char_index=dict((i,char)forchar,iininput_token_index.items())reverse_target_char_index=dict((i,char)forchar,iintarget_token_index.items())defdecode_sequence(input_seq):#Encodetheinputasstatevectors.states_value=encoder_model.predict(input_seq)#Generateemptytargetsequenceoflength1.target_seq=np.zeros((1,1,num_decoder_tokens))#Populatethefirstcharacteroftargetsequencewiththestartcharacter.target_seq[0,0,target_token_index['\t']]=1.#Samplingloopforabatchofsequences#(tosimplify,hereweassumeabatchofsize1).stop_condition=Falsedecoded_sentence=''whilenotstop_condition:output_tokens,h,c=decoder_model.predict([target_seq]+states_value)#Sampleatokensampled_token_index=np.argmax(output_tokens[0,-1,:])sampled_char=reverse_target_char_index[sampled_token_index]decoded_sentence+=sampled_char#Exitcondition:eitherhitmaxlength#orfindstopcharacter.if(sampled_char=='\n'orlen(decoded_sentence)>max_decoder_seq_length):stop_condition=True#Updatethetargetsequence(oflength1).target_seq=np.zeros((1,1,num_decoder_tokens))target_seq[0,0,sampled_token_index]=1.#Updatestatesstates_value=[h,c]returndecoded_sentenceforseq_indexinrange(100):#Takeonesequence(partofthetrainingset)#fortryingoutdecoding.input_seq=encoder_input_data[seq_index:seq_index+1]decoded_sentence=decode_sequence(input_seq)print('-')print('Inputsentence:',input_texts[seq_index])print('Decodedsentence:',decoded_sentence)

结论

RNNs和LSTMs网络今天提供了非常酷的用例,我们看到它在大量技术中使用。

循环神经网络与传统的ANNs不同,因为它们不需要固定的输入/输出大小,并且它们也使用先前的数据进行预测。

LSTM网络专门用于解决RNNs中的长期依赖性问题,并且通过使用单元状态,它们非常善于利用不久前的数据(其本质上是固有的)。