热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

神经网络机器翻译的实现

本文系qitta的文章翻译而成,由renzhe0009实现。转载请注明以上信息,谢谢合作。本文主要讲解以recurrentneuralnetwork为主,以及使用Chainer和自
本文系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。
 

from chainer import FunctionSet
from chainer.functions import *
model
= FunctionSet(
w_xh
= EmbedID(VOCAB_SIZE, HIDDEN_SIZE), # 输入层(one-hot) -> 隐藏层
w_hh = Linear(HIDDEN_SIZE, HIDDEN_SIZE), # 隐藏层 -> 隐藏层
w_hy = Linear(HIDDEN_SIZE, VOCAB_SIZE), # 隐藏层 -> 输出层
)

VOCAB_SIZE是单词的数量、HIDDEN_SIZE是隐藏层的维数
然后,定义实际的解析函数forward。在这里基本是按照上图的网络结构来再现模型的定义和实际的输入数据,最终进行求值计算。语言模型的情况下,是用下面的式表示句子的结合概率。

《神经网络机器翻译的实现》

 

以下是代码的例子。

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

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

也就是用chainer.functions.softmax_cross_entropy

def forward(sentence, model):
...
accum_loss
= Variable(np.zeros((), dtype=np.float32)) # 累计损失的初値
...
for word in sentence:
x
= Variable(np.array([[word]], dtype=np.int32)) #下次的输入 (=现在的正确值)
u = model.w_hy(h)
accum_loss
+= softmax_cross_entropy(u, x) # 累计损失
y = softmax(u)
...
return log_joint_prob, accum_loss # 累计损失全部返回

现在就可以进行学习了。

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

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

 

Encoder-decode翻译模型

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

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

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

 《神经网络机器翻译的实现》

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

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

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

整个模型的计算式如下

《神经网络机器翻译的实现》

 

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

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

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

model = FunctionSet(
w_xi
= EmbedID(SRC_VOCAB_SIZE, SRC_EMBED_SIZE), #输入层(one-hot) -> 输入词向量层
w_ip = Linear(SRC_EMBED_SIZE, 4 * HIDDEN_SIZE), # 输入词向量层-> 输入隐藏层
w_pp = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), # 输入隐藏层 -> 输入隐藏层
w_pq = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), # 输入隐藏层-> 输出隐藏层
w_yq = EmbedID(TRG_VOCAB_SIZE, 4 * HIDDEN_SIZE), #输出层(one-hot) -> 输出隐藏层
w_qq = Linear(HIDDEN_SIZE, 4 * HIDDEN_SIZE), #输出隐藏层 -> 输出隐藏层
w_qj = Linear(HIDDEN_SIZE, TRG_EMBED_SIZE), # 输出隐藏层 -> 输出词向量层
w_jy = Linear(TRG_EMBED_SIZE, TRG_VOCAB_SIZE), # 输出隐藏层 -> 输出隐藏层
)

接下来是forward函数。

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

# src_sentence: 需要翻译的句子 e.g. ['他', '在', '走']
#
trg_sentence: 正解的翻译句子 e.g. ['he', 'runs']
#
training: 机械学习的预测。
def forward(src_sentence, trg_sentence, model, training):
# 转换单词ID
# 对正解的翻訳追加终端符号
src_sentence = [convert_to_your_src_id(word) for word in src_sentence]
trg_sentence
= [convert_to_your_trg_id(word) for wprd in trg_sentence] + [END_OF_SENTENCE]
# LSTM内部状态的初期値
c = Variable(np.zeros((1, HIDDEN_SIZE), dtype=np.float32))
# encoder
for word in reversed(src_sentence):
x
= Variable(np.array([[word]], dtype=np.int32))
i
= tanh(model.w_xi(x))
c, p
= lstm(c, model.w_ip(i) + model.w_pp(p))
# encoder -> decoder
c, q = lstm(c, model.w_pq(p))
# decoder
if training:
# 学习时使用y作为正解的翻译、forward结果作为累计损失来返回
accum_loss = np.zeros((), dtype=np.float32)
for word in trg_sentence:
j
= tanh(model.w_qj(q))
y
= model.w_jy(j)
t
= Variable(np.array([[word]], dtype=np.int32))
accum_loss
+= softmax_cross_entropy(y, t)
c, q
= lstm(c, model.w_yq(t), model.w_qq(q))
return accum_loss
else:
# 预测时翻译器生成的y作为下次的输入,forward的结果作为生成了的单词句子
# 选择y中最大概率的单词、没必要用softmax。
hyp_sentence = []
while len(hyp_sentence) <100: # 剔除生成100个单词以上的句子
j = tanh(model.w_qj(q))
y
= model.w_jy(j)
word
= y.data.argmax(1)[0]
if word == END_OF_SENTENCE:
break # 生成了终端符号,结束。
hyp_sentence.append(convert_to_your_trg_str(word))
c, q
= lstm(c, model.w_yq(y), model.w_qq(q))
return hyp_sentence

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

最终结果如下:

《神经网络机器翻译的实现》

第一次epoch的结果。

《神经网络机器翻译的实现》

 

 第100次epoch的结果。

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

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

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

 

Have fun!

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

 

 

 

 


推荐阅读
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 本文详细介绍了如何使用Python的多进程技术来高效地分块读取超大文件,并将其输出为多个文件。通过这种方式,可以显著提高读取速度和处理效率。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 在机器学习领域,深入探讨了概率论与数理统计的基础知识,特别是这些理论在数据挖掘中的应用。文章重点分析了偏差(Bias)与方差(Variance)之间的平衡问题,强调了方差反映了不同训练模型之间的差异,例如在K折交叉验证中,不同模型之间的性能差异显著。此外,还讨论了如何通过优化模型选择和参数调整来有效控制这一平衡,以提高模型的泛化能力。 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 独家解析:深度学习泛化理论的破解之道与应用前景
    本文深入探讨了深度学习泛化理论的关键问题,通过分析现有研究和实践经验,揭示了泛化性能背后的核心机制。文章详细解析了泛化能力的影响因素,并提出了改进模型泛化性能的有效策略。此外,还展望了这些理论在实际应用中的广阔前景,为未来的研究和开发提供了宝贵的参考。 ... [详细]
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
  • 从2019年AI顶级会议最佳论文,探索深度学习的理论根基与前沿进展 ... [详细]
  • 本文将深入探讨生成对抗网络(GAN)在计算机视觉领域的应用。作为该领域的经典模型,GAN通过生成器和判别器的对抗训练,能够高效地生成高质量的图像。本文不仅回顾了GAN的基本原理,还将介绍一些最新的进展和技术优化方法,帮助读者全面掌握这一重要工具。 ... [详细]
  • 浅层神经网络解析:本文详细探讨了两层神经网络(即一个输入层、一个隐藏层和一个输出层)的结构与工作原理。通过吴恩达教授的课程,读者将深入了解浅层神经网络的基本概念、参数初始化方法以及前向传播和反向传播的具体实现步骤。此外,文章还介绍了如何利用这些基础知识解决实际问题,并提供了丰富的实例和代码示例。 ... [详细]
author-avatar
小帅
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有