Susan Li作家Huiyuan Zhuo、思源到场

初学Python神经板滞翻译,这是一篇十分精简的实战指南

板滞翻译(MT)是一项极具挑衅性的义务,其研讨怎样运用盘算机将文本或是语音从一种言语翻译成另一种言语。本文借帮 Keras 葱☆基本的文本加载与数据预处理开端,并议论了轮回神经收集与编码器解码器框架下怎样才干构修一个可承受的神经翻译系统,本教程所有的代码已 GitHub 开源。

古板原理上来说,板滞翻译一般运用高度繁杂的言语常识开辟出的大型统计模子,可是近来许众研讨运用深度模子直接对翻译进程修模,并只供应原语数据与译文数据的状况下主动进修须要的言语常识。这种基于深度神经收集的翻译模子目前曾经取得了最佳效果。

项目地址:https://github.com/susanli2016/NLP-with-Python/blob/master/machine_translation.ipynb

接下来,我们将运用深度神经收集来办理板滞翻译题目。我们将展现怎样开辟一个将英文翻译成法文的神经收集板滞翻译模子。该模子将接纳英文文本输入同时返回法语译文。更确实地说,我们将构修 4 个模子,它们是:

  • 一个简单的 RNN;

  • 一个带词嵌入的 RNN;

  • 一个双向 RNN;

  • 一个编码器—解码器模子。

教练和评估深度神经收集是一项盘算鳞集型的义务。作家运用 AWS EC2 实例来运转所有代码。假如你方案照着本文做,你得拜访 GPU 实例。

加载库

importcollections
importhelper
importnumpyasnp
importproject_testsastests
fromkeras.preprocessing.textimportTokenizer
fromkeras.preprocessing.sequenceimportpad_sequences
fromkeras.modelsimportModel
fromkeras.layersimportGRU,Input,Dense,TimeDistributed,Activation,RepeatVector,Bidirectional
fromkeras.layers.embeddingsimportEmbedding
fromkeras.optimizersimportAdam
from keras.losses import sparse_categorical_crossentropy

作家运用 help.py 加载数据,同时运用 project_test.py 测试函数。

数据

该数据集包罗一个相对较小的词汇外,此中 small_vocab_en 文献包罗英文语句,small_vocab_fr 包罗对应的法文翻译。

数据集下载地址:https://github.com/susanli2016/NLP-with-Python/tree/master/data

加载数据

english_sentences=helper.load_data('data/small_vocab_en')
french_sentences=helper.load_data('data/small_vocab_fr')
print('Dataset Loaded')
  • 语句样本

small_vocab_en 中的每行包罗一个英文语句,同时其法文翻译位于 small_vocab_fr 中对应的每行。

forsample_iinrange(2):
print('small_vocab_enLine{}:{}'.format(sample_i+1,english_sentences[sample_i]))
print('small_vocab_frLine{}:{}'.format(sample_i+1,french_sentences[sample_i]))

  • 词汇外

题目的繁杂性取决于词汇外的繁杂性。一个更繁杂的词汇外意味着一个更繁杂的题目。关于将要处理的数据集,让我们看看它的繁杂性。

english_words_counter=collections.Counter([wordforsentenceinenglish_sentencesforwordinsentence.split()])
french_words_counter=collections.Counter([wordforsentenceinfrench_sentencesforwordinsentence.split()])
print('{}Englishwords.'.format(len([wordforsentenceinenglish_sentencesforwordinsentence.split()])))
print('{}uniqueEnglishwords.'.format(len(english_words_counter)))
print('10MostcommonwordsintheEnglishdataset:')
print('"'+'""'.join(list(zip(*english_words_counter.most_common(10)))[0])+'"')
print()
print('{}Frenchwords.'.format(len([wordforsentenceinfrench_sentencesforwordinsentence.split()])))
print('{}uniqueFrenchwords.'.format(len(french_words_counter)))
print('10MostcommonwordsintheFrenchdataset:')
print('"'+'""'.join(list(zip(*french_words_counter.most_common(10)))[0])+'"')

预处理

我们将运用以下预处理方法将文本转化为整数序列:

1. 将词转化为 id 外达;

2. 到场 padding 使得每个序列相同长。

Tokensize(标记字符串)

运用 Keras 的 Tokenizer 函数将每个语句转化为一个单词 id 的序列。运用该函数来标记化英文语句和法文语句。

函数 tokenize 返回标记化后的输入和类。

deftokenize(x):
x_tk=Tokenizer(char_level=False)
x_tk.fit_on_texts(x)
returnx_tk.texts_to_sequences(x),x_tk
text_sentences=[
'Thequickbrownfoxjumpsoverthelazydog.',
'ByJove,myquickstudyoflexicographywonaprize.',
'Thisisashortsentence.']
text_tokenized,text_tokenizer=tokenize(text_sentences)
print(text_tokenizer.word_index)
print()
forsample_i,(sent,token_sent)inenumerate(zip(text_sentences,text_tokenized)):
print('Sequence{}inx'.format(sample_i+1))
print('Input:{}'.format(sent))
print('Output:{}'.format(token_sent))

Padding

通过运用 Keras 的 pad_sequences 函数每个序列着末添加零以使得所有英文序列具有相同长度,所有法文序列具有相同长度。

defpad(x,length=None):
iflengthisNone:
length=max([len(sentence)forsentenceinx])
returnpad_sequences(x,maxlen=length,padding='post')
tests.test_pad(pad)
#PadTokenizedoutput
test_pad=pad(text_tokenized)
forsample_i,(token_sent,pad_sent)inenumerate(zip(text_tokenized,test_pad)):
print('Sequence{}inx'.format(sample_i+1))
print('Input:{}'.format(np.array(token_sent)))
print('Output:{}'.format(pad_sent))

预处理流程

完成预处理函数:

defpreprocess(x,y):
preprocess_x,x_tk=tokenize(x)
preprocess_y,y_tk=tokenize(y)
preprocess_x=pad(preprocess_x)
preprocess_y=pad(preprocess_y)
#Keras'ssparse_categorical_crossentropyfunctionrequiresthelabelstobein3dimensions
preprocess_y=preprocess_y.reshape(*preprocess_y.shape,1)
returnpreprocess_x,preprocess_y,x_tk,y_tk
preproc_english_sentences,preproc_french_sentences,english_tokenizer,french_tokenizer=\
preprocess(english_sentences,french_sentences)

max_english_sequence_length=preproc_english_sentences.shape[1]
max_french_sequence_length=preproc_french_sentences.shape[1]
english_vocab_size=len(english_tokenizer.word_index)
french_vocab_size=len(french_tokenizer.word_index)
print('DataPreprocessed')
print("MaxEnglishsentencelength:",max_english_sequence_length)
print("MaxFrenchsentencelength:",max_french_sequence_length)
print("Englishvocabularysize:",english_vocab_size)
print("Frenchvocabularysize:",french_vocab_size)

模子

本节中,我们将实验种种神经收集构造。我们将教练 4 个相对简单的构造举措开端:

  • 模子 1 是一个简单的 RNN;

  • 模子 2 是一个带词嵌入的 RNN;

  • 模子 3 是一个双向 RNN;

  • 模子 4 是两个 RNN 构成的编码器—解码器架构。

实验了 4 种简单的构造之后,我们将构修一个更深的模子,其功用要优于以上 4 种模子。

id 从头转化为文本

神经收集将输入转化为单词 id,但这不是我们最终念要的方式,我们念要的是法文翻译。logits_to_text 函数补偿了从神经收集输出的 logits 到法文翻译之间的缺口,我们将运用该函数更好地舆解神经收集的输出。

deflogits_to_text(logits,tokenizer):
index_to_words={id:wordforword,idintokenizer.word_index.items()}
index_to_words[0]='<PAD>'
return''.join([index_to_words[prediction]forpredictioninnp.argmax(logits,1)])
print('`logits_to_text` function loaded.')

模子 1:RNN

我们构修一个根底的 RNN 模子,该模子是将英文翻译成法文序列的精良基准

defsimple_model(input_shape,output_sequence_length,english_vocab_size,french_vocab_size):
learning_rate=1e-3
input_seq=Input(input_shape[1:])
rnn=GRU(64,return_sequences=True)(input_seq)
logits=TimeDistributed(Dense(french_vocab_size))(rnn)
model=Model(input_seq,Activation('softmax')(logits))
model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])

returnmodel
tests.test_simple_model(simple_model)
tmp_x=pad(preproc_english_sentences,max_french_sequence_length)
tmp_x=tmp_x.reshape((-1,preproc_french_sentences.shape[-2],1))
#Traintheneuralnetwork
simple_rnn_model=simple_model(
tmp_x.shape,
max_french_sequence_length,
english_vocab_size,
french_vocab_size)
simple_rnn_model.fit(tmp_x,preproc_french_sentences,batch_size=1024,epochs=10,validation_split=0.2)
#Printprediction(s)
print(logits_to_text(simple_rnn_model.predict(tmp_x[:1])[0],french_tokenizer))

根底 RNN 模子的验证集准确度是 0.6039。

模子 2:词嵌入

词嵌入是 n 维空间中近义词间隔临近的向量外示,此中 n 外示嵌入向量的大小。我们将运用词嵌入来构修一个 RNN 模子。

fromkeras.modelsimportSequential
defembed_model(input_shape,output_sequence_length,english_vocab_size,french_vocab_size):
learning_rate=1e-3
rnn=GRU(64,return_sequences=True,activation="tanh")

embedding=Embedding(french_vocab_size,64,input_length=input_shape[1])
logits=TimeDistributed(Dense(french_vocab_size,activation="softmax"))

model=Sequential()
#emcanonlybeusedinfirstlayer-->KerasDocumentation
model.add(embedding)
model.add(rnn)
model.add(logits)
model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])

returnmodel
tests.test_embed_model(embed_model)
tmp_x=pad(preproc_english_sentences,max_french_sequence_length)
tmp_x=tmp_x.reshape((-1,preproc_french_sentences.shape[-2]))
embeded_model=embed_model(
tmp_x.shape,
max_french_sequence_length,
english_vocab_size,
french_vocab_size)
embeded_model.fit(tmp_x,preproc_french_sentences,batch_size=1024,epochs=10,validation_split=0.2)
print(logits_to_text(embeded_model.predict(tmp_x[:1])[0],french_tokenizer))

嵌入式模子的验证集准确度是 0.8401。

模子 3:双向 RNN

defbd_model(input_shape,output_sequence_length,english_vocab_size,french_vocab_size):

learning_rate=1e-3
model=Sequential()
model.add(Bidirectional(GRU(128,return_sequences=True,dropout=0.1),
input_shape=input_shape[1:]))
model.add(TimeDistributed(Dense(french_vocab_size,activation='softmax')))
model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])
returnmodel
tests.test_bd_model(bd_model)
tmp_x=pad(preproc_english_sentences,preproc_french_sentences.shape[1])
tmp_x=tmp_x.reshape((-1,preproc_french_sentences.shape[-2],1))
bidi_model=bd_model(
tmp_x.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)
bidi_model.fit(tmp_x,preproc_french_sentences,batch_size=1024,epochs=20,validation_split=0.2)
#Printprediction(s)
print(logits_to_text(bidi_model.predict(tmp_x[:1])[0],french_tokenizer))

双向 RNN 模子的验证集准确度是 0.5992。

模子 4:编码器—解码器框架

编码器构修一个语句的矩阵外示,而解码器将该矩阵举措输入并输出预测的翻译。

defencdec_model(input_shape,output_sequence_length,english_vocab_size,french_vocab_size):

learning_rate=1e-3
model=Sequential()
model.add(GRU(128,input_shape=input_shape[1:],return_sequences=False))
model.add(RepeatVector(output_sequence_length))
model.add(GRU(128,return_sequences=True))
model.add(TimeDistributed(Dense(french_vocab_size,activation='softmax')))

model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])
returnmodel
tests.test_encdec_model(encdec_model)
tmp_x=pad(preproc_english_sentences)
tmp_x=tmp_x.reshape((-1,preproc_english_sentences.shape[1],1))
encodeco_model=encdec_model(
tmp_x.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)
encodeco_model.fit(tmp_x,preproc_french_sentences,batch_size=1024,epochs=20,validation_split=0.2)
print(logits_to_text(encodeco_model.predict(tmp_x[:1])[0],french_tokenizer))

编码器—解码器模子的验证集准确度是 0.6406。

模子 5:自定义深度模子

构修一个将词嵌入和双向 RNN 兼并到一个模子中的 model_final。

至此,我们需求需求做少许实行,比如将 GPU 参数改为 256,将进修率改为 0.005,对模子教练众于(或少于)20 epochs 等等。

defmodel_final(input_shape,output_sequence_length,english_vocab_size,french_vocab_size):

model=Sequential()
model.add(Embedding(input_dim=english_vocab_size,output_dim=128,input_length=input_shape[1]))
model.add(Bidirectional(GRU(256,return_sequences=False)))
model.add(RepeatVector(output_sequence_length))
model.add(Bidirectional(GRU(256,return_sequences=True)))
model.add(TimeDistributed(Dense(french_vocab_size,activation='softmax')))
learning_rate=0.005

model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])

returnmodel
tests.test_model_final(model_final)
print('Final Model Loaded')

预测

deffinal_predictions(x,y,x_tk,y_tk):
tmp_X=pad(preproc_english_sentences)
model=model_final(tmp_X.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)

model.fit(tmp_X,preproc_french_sentences,batch_size=1024,epochs=17,validation_split=0.2)

y_id_to_word={value:keyforkey,valueiny_tk.word_index.items()}
y_id_to_word[0]='<PAD>'
sentence='hesawaoldyellowtruck'
sentence=[x_tk.word_index[word]forwordinsentence.split()]
sentence=pad_sequences([sentence],maxlen=x.shape[-1],padding='post')
sentences=np.array([sentence[0],x[0]])
predictions=model.predict(sentences,len(sentences))
print('Sample1:')
print(''.join([y_id_to_word[np.argmax(x)]forxinpredictions[0]]))
print('Ilavuunvieuxcamionjaune')
print('Sample2:')
print(''.join([y_id_to_word[np.argmax(x)]forxinpredictions[1]]))
print(''.join([y_id_to_word[np.max(x)]forxiny[0]]))
final_predictions(preproc_english_sentences, preproc_french_sentences, english_tokenizer, french_tokenizer)

我们取得了语句完美的翻译同时验证集准确度是 0.9776!

原文链接:https://medium.com/@actsusanli/neural-machine-translation-with-python-c2f0a34f7dd

初学Python板滞翻译
10
相关数据
基准技能

一种简单的模子或启示法,用作比较模子效果时的参考点。基准有帮于模子开辟者针对特定题目量化最低预期效果。

词嵌入技能

词嵌入是自然言语处理(NLP)中言语模子与外征进修技能的统称。看法上而言,它是指把一个维数为所有词的数目标高维空间嵌入到一个维数低得众的延续向量空间中,每个单词或词组被映照为实数域上的向量。

参数技能

数学和统计学裡,参数(英语:parameter)是运用通用变量来修立函数和变量之间联系(岛镶种联系很难用方程来阐述时)的一个数目。

进修率技能

运用差别优化器(比如随机梯度下降,Adam)神经收集相关教练中,进修速率举措一个超参数掌握了权重更新的幅度,以及教练的速率和精度。进修速率太大容易导致目标(价钱)函数摆荡较大从而难以找到最优,而弱进修速率修立太小,则会导致收敛过慢耗时太长

验证集技能

验证数据集是用于调解分类器超参数(即模子构造)的一组数据集,它有时也被称为开辟集(dev set)。

板滞翻译技能

板滞翻译(MT)是应用板滞的力气「主动将一种自然言语(源言语)的文本翻译成另一种言语(目标言语)」。板滞翻译方法一般可分成三大类:基于规矩的板滞翻译(RBMT)、统计板滞翻译(SMT)和神经板滞翻译(NMT)。

神经收集技能

(人工)神经收集是一种根源于 20 世纪 50 年代的监视式板滞进修模子,那时分研讨者念象了「感知器(perceptron)」的念法。这一范畴的研讨者一般被称为「勾结主义者(Connectionist)」,因为这种模子模拟了人脑的功用。神经收集模子一般是通过反向传达算法运用梯度下降教练的。目前神经收集有两大主要类型,它们都是前馈神经收集:卷积神经收集(CNN)和轮回神经收集(RNN),此中 RNN 又包罗好坏期记忆(LSTM)、门控轮回单位(GRU)等等。深度进修是一种主要运用于神经收集帮帮其取得更好结果的技能。尽管神经收集主要用于监视进修,但也有少许为无监视进修计划的变体,比如主动编码器和生成对立收集(GAN)。

引荐作品
暂无评论
暂无评论~