本文系qitta的文章翻译而成,由renzhe0009实现。转载请注明以上信息,谢谢合作。

本文主要讲解以recurrent neural network为主,以及使用Chainer和自然语言处理其中的encoder-decoder翻译模型。

并将英中机器翻译用代码实现。

Recurrent Neural Network

最基本的recurrent neural network(RNN),像下面的图一样,最典型的是追加3层神经网络隐含层的反馈。
 
这是非常简单的模型,本文接下来介绍的翻译模型就是由RNN作成。RNN是比以前的N - gram模型精度性能更加优越的模型。
上图写成式子的话就是

在chainer(本次实现所使用的程序库)中,我们就使用上面的式子。
在这里暂且先是考虑“输入单词ID,预测下一个单词ID”的RNN语言模式吧。
首先定义模型。模式是学习可能的参数的集合,上图的W∗∗就是这个意思。这个场合W∗∗是全部线性算子(矩阵),所以使用chainer . functions内的Linear吗EmbedID。EmbedID是输入方面在one-hot向量的情况的Linear,代替vector。
 
  1. from chainer import FunctionSet
  2. from chainer.functions import *
  3.  
  4. model = FunctionSet(
  5. w_xh = EmbedID(VOCAB_SIZE, HIDDEN_SIZE), # 输入层(one-hot) -> 隐藏层
  6. w_hh = Linear(HIDDEN_SIZE, HIDDEN_SIZE), # 隐藏层 -> 隐藏层
  7. w_hy = Linear(HIDDEN_SIZE, VOCAB_SIZE), # 隐藏层 -> 输出层
  8. )
  1. VOCAB_SIZE是单词的数量、HIDDEN_SIZE是隐藏层的维数
    然后,定义实际的解析函数forward。在这里基本是按照上图的网络结构来再现模型的定义和实际的输入数据,最终进行求值计算。语言模型的情况下,是用下面的式表示句子的结合概率。

以下是代码的例子。

  1. import math
  2. import numpy as np
  3. from chainer import Variable
  4. from chainer.functions import *
  5.  
  6. def forward(sentence, model): # sentence是strの排列结果。
  7. sentence = [convert_to_your_word_id(word) for word in sentence] # 单词转换为ID
  8. h = Variable(np.zeros((1, HIDDEN_SIZE), dtype=np.float32)) # 隐藏层的初值
  9. log_joint_prob = float(0) # 句子的结合概率
  10.  
  11. for word in sentence:
  12. x = Variable(np.array([[word]], dtype=np.int32)) # 下一次的输入层
  13. y = softmax(model.w_hy(h)) # 下一个单词的概率分布
  14. log_joint_prob += math.log(y.data[0][word]) #结合概率的分布
  15. h = tanh(model.w_xh(x) + model.w_hh(h)) #隐藏层的更新
  16.  
  17. return log_joint_prob #返回结合概率的计算结果

这样就可以求出句子的概率了。但是,上面并没有计算损失函数。所以我们使用softmax函数来进行计算。

也就是用chainer.functions.softmax_cross_entropy

  1. def forward(sentence, model):
  2. ...
  3.  
  4. accum_loss = Variable(np.zeros((), dtype=np.float32)) # 累计损失的初値
  5. ...
  6.  
  7. for word in sentence:
  8. x = Variable(np.array([[word]], dtype=np.int32)) #下次的输入 (=现在的正确值)
  9. u = model.w_hy(h)
  10. accum_loss += softmax_cross_entropy(u, x) # 累计损失
  11. y = softmax(u)
  12. ...
  13.  
  14. return log_joint_prob, accum_loss # 累计损失全部返回

现在就可以进行学习了。

  1. from chainer.optimizers import *
  2. ...
  3.  
  4. def train(sentence_set, model):
  5. opt = SGD() # 使用梯度下降法
  6. opt.setup(model) # 学习初期化
  7. for sentence in sentence_set:
  8. opt.zero_grad(); # 勾配の初期化
  9. log_joint_prob, accum_loss = forward(sentence, model) # 损失的计算
  10. accum_loss.backward() # 误差反向传播
  11. opt.clip_grads(10) # 剔除过大的梯度
  12. opt.update() # 参数更新

那么基本上chainer的RNN代码就是这样实现的了。

Encoder-decode翻译模型

encoder-decoder是现在广泛使用的利用神经网络的翻译模型。

和过去的方法相比也能够达到很高精度,现在深受NLP研究者们喜爱的翻译模型。

encoder-decoder有很多种,以下是我在本文中实现的模型。

  1.  

很简单的想法,准备输入方面(encoder)和输出方面(decoder)的2个RNN,在中间节点上连接。

这个模型的有趣之处在于,为了在输出方面一起生成终端符号,翻译的结束是由模型自己决定的。但是反过来讲,为了不生成无限的单词死循环,实际处理的时候,做一些限制还是有必要的。

i和j是embedding(词向量)层。

整个模型的计算式如下

对隐藏层p和q的位移,使用了LSTM神经网络。但是encoder方面实质的损失的计算位置y的距离很远,一般的传递函数很难进行学习。

所以LSTM神经网络的长距离时序依存关系的优点就能够体现出来。

上式的位移W∗∗一共有8种。用以下的代码来定义。

  1. model = FunctionSet(
  2. w_xi = EmbedID(SRC_VOCAB_SIZE, SRC_EMBED_SIZE), #输入层(one-hot) -> 输入词向量层
  3. w_ip = Linear(SRC_EMBED_SIZE, 4 * HIDDEN_SIZE), # 输入词向量层-> 输入隐藏层
  4. w_pp = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), # 输入隐藏层 -> 输入隐藏层
  5. w_pq = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), # 输入隐藏层-> 输出隐藏层
  6. w_yq = EmbedID(TRG_VOCAB_SIZE, 4 * HIDDEN_SIZE), #输出层(one-hot) -> 输出隐藏层
  7. w_qq = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), #输出隐藏层 -> 输出隐藏层
  8. w_qj = Linear(HIDDEN_SIZE, TRG_EMBED_SIZE), # 输出隐藏层 -> 输出词向量层
  9. w_jy = Linear(TRG_EMBED_SIZE, TRG_VOCAB_SIZE), # 输出隐藏层 -> 输出隐藏层
  10. )

接下来是forward函数。

因为LSTM带有内部结构,注意p和q的计算需要多一个Variable

  1. # src_sentence: 需要翻译的句子 e.g. ['他', '在', '走']
  2. # trg_sentence: 正解的翻译句子 e.g. ['he', 'runs']
  3. # training: 机械学习的预测。
  4. def forward(src_sentence, trg_sentence, model, training):
  5.  
  6. # 转换单词ID
  7. # 对正解的翻訳追加终端符号
  8. src_sentence = [convert_to_your_src_id(word) for word in src_sentence]
  9. trg_sentence = [convert_to_your_trg_id(word) for wprd in trg_sentence] + [END_OF_SENTENCE]
  10.  
  11. # LSTM内部状态的初期値
  12. c = Variable(np.zeros((1, HIDDEN_SIZE), dtype=np.float32))
  13.  
  14. # encoder
  15. for word in reversed(src_sentence):
  16. x = Variable(np.array([[word]], dtype=np.int32))
  17. i = tanh(model.w_xi(x))
  18. c, p = lstm(c, model.w_ip(i) + model.w_pp(p))
  19.  
  20. # encoder -> decoder
  21. c, q = lstm(c, model.w_pq(p))
  22.  
  23. # decoder
  24. if training:
  25. # 学习时使用y作为正解的翻译、forward结果作为累计损失来返回
  26. accum_loss = np.zeros((), dtype=np.float32)
  27. for word in trg_sentence:
  28. j = tanh(model.w_qj(q))
  29. y = model.w_jy(j)
  30. t = Variable(np.array([[word]], dtype=np.int32))
  31. accum_loss += softmax_cross_entropy(y, t)
  32. c, q = lstm(c, model.w_yq(t), model.w_qq(q))
  33. return accum_loss
  34. else:
  35. # 预测时翻译器生成的y作为下次的输入,forward的结果作为生成了的单词句子
  36. # 选择y中最大概率的单词、没必要用softmax。
  37. hyp_sentence = []
  38. while len(hyp_sentence) < 100: # 剔除生成100个单词以上的句子
  39. j = tanh(model.w_qj(q))
  40. y = model.w_jy(j)
  41. word = y.data.argmax(1)[0]
  42. if word == END_OF_SENTENCE:
  43. break # 生成了终端符号,结束。
  44. hyp_sentence.append(convert_to_your_trg_str(word))
  45. c, q = lstm(c, model.w_yq(y), model.w_qq(q))
  46. return hyp_sentence

稍微有点长,这段代码和之前的图结合起来读就会明白了。

最终结果如下:

第一次epoch的结果。

第100次epoch的结果。

src是英文原文。trg是正确译文。hyp是预测译文。

因为现在手头只有笔记本电脑,内存不足,所以把参数都调低了,不然无法执行。你们懂的。

看起来还不赖吧。参数调高必然能取得更好的效果。

Have fun!

Ps:过阵子回学校再把代码整理下发布。

  1.  

RNN神经网络和英中机器翻译的实现的更多相关文章

  1. 3. RNN神经网络-LSTM模型结构

    1. RNN神经网络模型原理 2. RNN神经网络模型的不同结构 3. RNN神经网络-LSTM模型结构 1. 前言 之前我们对RNN模型做了总结.由于RNN也有梯度消失的问题,因此很难处理长序列的数 ...

  2. [论文阅读] RNN 在阿里DIEN中的应用

    [论文阅读] RNN 在阿里DIEN中的应用 0x00 摘要 本文基于阿里推荐DIEN代码,梳理了下RNN一些概念,以及TensorFlow中的部分源码.本博客旨在帮助小伙伴们详细了解每一步骤以及为什 ...

  3. 从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化

    从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化 神经网络在训练过程中,为应对过拟合问题,可以采用正则化方法(regularization),一种常用的正则化方法是L2正则化. 神经网络中 ...

  4. 从MAP角度理解神经网络训练过程中的正则化

    在前面的文章中,已经介绍了从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化,本次我们从最大后验概率点估计(MAP,maximum a posteriori point estimate)的 ...

  5. 一文看懂NLP神经网络发展历史中最重要的8个里程碑!

    导读:这篇文章中作者尝试将 15 年的自然语言处理技术发展史浓缩为 8 个高度相关的里程碑事件,不过它有些偏向于选择与当前比较流行的神经网络技术相关的方向.我们需要关注的是,本文中介绍的许多神经网络模 ...

  6. PyTorch基础——使用神经网络识别文字中的情感信息

    一.介绍 知识点 使用 Python 从网络上爬取信息的基本方法 处理语料"洗数据"的基本方法 词袋模型搭建方法 简单 RNN 的搭建方法 简单 LSTM 的搭建方法 二.从网络中 ...

  7. RNN神经网络产生梯度消失和梯度爆炸的原因及解决方案

    1.RNN模型结构 循环神经网络RNN(Recurrent Neural Network)会记忆之前的信息,并利用之前的信息影响后面结点的输出.也就是说,循环神经网络的隐藏层之间的结点是有连接的,隐藏 ...

  8. Deep Learning入门视频(下)之关于《感受神经网络》两节中的代码解释

    代码1如下: #深度学习入门课程之感受神经网络(上)代码解释: import numpy as np import matplotlib.pyplot as plt #matplotlib是一个库,p ...

  9. 《TensorFlow实战》中AlexNet卷积神经网络的训练中

    TensorFlow实战中AlexNet卷积神经网络的训练 01 出错 TypeError: as_default() missing 1 required positional argument: ...

随机推荐

  1. 排序小结(C版)

    一.快速排序(C源码) #include <stdlib.h> #include <stdio.h> int adjust(int a[],int start,int end) ...

  2. JS三元

    ((productDatas[i].Img.indexOf("http") == -1) ? ("/upload/190-160/" + productData ...

  3. Day6 google Geocoding API

    在看机器学习实战中K-means一章,练习中需要调用Yahoo PlaceFinder API 为地点添加经纬度,语言是python.申请到了appid但调用好像还要收费,要填写银行卡号才能用,没管那 ...

  4. Oracle的内存结构

    备注:本图片截图自“炼数成金” Oracle的体系结构分为内存结构.进程,磁盘文件. 内存结构分为SGA, PGA.SGA是系统全局区,是所有的用户共享区,PGA是某个用户的私有区. SGA分为sha ...

  5. 黑马程序员——【Java高新技术】——JDK1.5新特性:静态导入、可变参数、增强型for循环、自动装箱拆箱、枚举

    ---------- android培训.java培训.期待与您交流! ---------- 一.静态导入 1.import和import static区别: (1)import 是导入一个类或某个包 ...

  6. checkbox 全选,反选 ,全不选

    在表格或者列表中经常会遇到要全选或者反选等交互,今天总结了一下代码,保留着以后直接拿来用 原理: 1. 全选:当全选checkbox被点击(不管点击之前是什么状态)后,获取其checked状态.然后对 ...

  7. c/c++ 函数指针 指针函数 数组的引用 指针数组 数组指针

    1.指针数组数组指针 引用数组 数组的引用 int *a[10] 指针数组 每一个元素都是一个指针 Int (*a)[10] 数组指针 P指向一个含有10个元素的数组 Int (&a)[10] ...

  8. php建立MySQL数据表

    <?php $connect = mysql_connect("127.0.0.1","root",""); mysql_select ...

  9. LintCode Binary Tree Maximum Path Sum

    Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. ...

  10. 【转载】IIS7.5(经典模式)访问静态资源(.css和.js文件)提示:未能执行 URL

    IIS7.5(经典模式)静态资源(.css和.js文件)提示:未能执行 URL “/”应用程序中的服务器错误. 未能执行 URL. 说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪 ...