1.介绍
神经机器翻译(NMT)是一种机器翻译方法,它使用人工神经网络来预测一个单词序列的可能性,通常在一个单一的集成模型中建模整个句子。
对于计算机来说,用一个简单的基于规则的系统从一种语言转换成另一种语言是最困难的问题之一,因为它们无法捕捉到过程中的细微差别。不久之后,我们开始使用统计模型,但在进入深度学习之后,这个领域被统称为神经机器翻译,现在已经取得了最先进的成果。
这篇文章是针对于初学者的,所以一个特定类型的架构(Seq2Seq)显示了一个好的开始,这就是我们要在这里实现的。
因此,本文中的序列对序列(seq2seq)模型使用了一种编码器-解码器架构,它使用一种名为LSTM(长短期记忆)的RNN,其中编码器神经网络将输入的语言序列编码为单个向量,也称为上下文向量。
这个上下文向量被称为包含输入语言序列的抽象表示。
然后将这个向量传递到解码器神经网络中,用解码器神经网络一个词一个词地输出相应的输出语言翻译句子。
这里我正在做一个德语到英语的神经机器翻译。但同样的概念可以扩展到其他问题,如命名实体识别(NER),文本摘要,甚至其他语言模型,等等。
2.数据准备和预处理
为了以我们想要的最佳方式获取数据,我使用了SpaCy(词汇构建)、TorchText(文本预处理)库和multi30k dataset,其中包含英语、德语和法语的翻译序列
让我们看看它能做的一些过程,
- 训练/验证/测试分割:将数据分割到指定的训练/验证/测试集。
- 文件加载:加载各种格式(.txt、.json、.csv)的文本语料库。
- 分词:把句子分解成一串单词。
- 从文本语料库生成一个词汇表列表。
- 单词编码:将单词映射为整个语料库的整数,反之亦然。
- 字向量:将字从高维转换为低维(字嵌入)。
- 批处理:生成批次的样品。
因此,一旦我们了解了torch文本可以做什么,让我们谈谈如何在torch text模块中实现它。在这里,我们将利用torchtext下的3个类。
Fields :这是torchtext下的一个类,在这里我们指定如何在我们的数据库里进行预处理。
TabularDataset:我们实际上可以定义以CSV、TSV或JSON格式存储的列数据集,并将它们映射为整数。
BucketIterator:我们可以填充我们的数据以获得近似,并使用我们的数据批量进行模型训练。
这里我们的源语言(SRC - Input)是德语,目标语言(TRG - Output)是英语。为了有效的模型训练,我们还额外增加了两个令牌“序列开始”<sos>和“序列结束”<eos>。
!pipinstalltorchtext==0.6.0--quietimporttorchimporttorch.nnasnnimporttorch.optimasoptimfromtorchtext.datasetsimportMulti30kfromtorchtext.dataimportField, BucketIteratorimportnumpyasnpimportpandasaspdimportspacy, random##LoadingtheSpaCy's vocabulary for our desired languages.!python -m spacy download en --quiet!python -m spacy download de --quietspacy_german = spacy.load("de")spacy_english = spacy.load("en")def tokenize_german(text):return [token.text for token in spacy_german.tokenizer(text)]def tokenize_english(text):return [token.text for token in spacy_english.tokenizer(text)]german = Field(tokenize=tokenize_german, lower=True,init_token="<sos>", eos_token="<eos>")english = Field(tokenize=tokenize_english, lower=True,init_token="<sos>", eos_token="<eos>")train_data, valid_data, test_data = Multi30k.splits(exts = (".de", ".en"),fields=(german, english))german.build_vocab(train_data, max_size=10000, min_freq=3)english.build_vocab(train_data, max_size=10000, min_freq=3)print(f"Unique tokens in source (de) vocabulary: {len(german.vocab)}")print(f"Unique tokens in target (en) vocabulary: {len(english.vocab)}")******************************* OUTPUT *******************************Unique tokens in source (de) vocabulary: 5376Unique tokens in target (en) vocabulary: 4556
在设置了语言预处理标准之后,下一步是使用迭代器创建成批的训练、测试和验证数据。
创建批是一个详尽的过程,幸运的是我们可以利用TorchText的迭代器库。
这里我们使用BucketIterator来有效填充源句和目标句。我们可以使用.src属性访问源(德语)批数据,使用.trg属性访问对应的(英语)批数据。同样,我们可以在标记之前看到数据。
device=torch.device('cuda'iftorch.cuda.is_available() else'cpu') BATCH_SIZE=32train_iterator, valid_iterator, test_iterator=BucketIterator.splits((train_data, valid_data, test_data), batch_size=BATCH_SIZE, sort_within_batch=True, sort_key=lambdax: len(x.src), device=device) #DatasetSneekpeekbeforetokenizingfordataintrain_data: max_len_ger.append(len(data.src)) max_len_eng.append(len(data.trg)) ifcount<10 : print("German - ",*data.src, " Length - ", len(data.src)) print("English - ",*data.trg, " Length - ", len(data.trg)) print() count+=1print("Maximum Length of English Sentence {} and German Sentence {} in the dataset".format(max(max_len_eng),max(max_len_ger))) print("Minimum Length of English Sentence {} and German Sentence {} in the dataset".format(min(max_len_eng),min(max_len_ger))) **************************************************************OUTPUT**************************************************************German-zweijungeweißemännersindimfreienindernähevielerbüsche . Length-13English-twoyoung , whitemalesareoutsidenearmanybushes . Length-11German-einmanningrünhälteinegitarre , währendderanderemannseinhemdansieht . Length-16English-amaningreenholdsaguitarwhiletheothermanobserveshisshirt . Length-15German-einmannlächelteinenausgestopftenlöwenan . Length-8English-amanissmilingatastuffedlionLength-8German-einschickesmädchensprichtmitdemhandywährendsielangsamdiestraßeentlangschwebt . Length-14English-atrendygirltalkingonhercellphonewhileglidingslowlydownthestreet . Length-14German-einefraumiteinergroßengeldbörsegehtaneinemtorvorbei . Length-12English-awomanwithalargepurseiswalkingbyagate . Length-12German-jungentanzenmittenindernachtaufpfosten . Length-9English-boysdancingonpolesinthemiddleofthenight . Length-11MaximumLengthofEnglishSentence41andGermanSentence44inthedatasetMinimumLengthofEnglishSentence4andGermanSentence1inthedataset
我刚刚试验了一批大小为32和样本批如下所示。这些句子被标记成一个单词列表,并根据词汇索引。“pad”标记的索引值为1。
每一列对应一个句子,用数字索引,在单个目标批处理中有32个这样的句子,行数对应于句子的最大长度。短句用1来填充以弥补其长度。
下表包含批处理的数字索引,这些索引稍后被输入到嵌入的单词中,并转换为密集表示,以便进行Seq2Seq处理。
下表包含与批处理的数字索引映射的对应单词。
3.长短期记忆(LSTM)背景知识
上面的图片显示了在单个LSTM单元下的计算。在最后一篇文章中,我将添加一些参考资料来学习更多关于LSTM的知识,以及为什么它适用于长序列。
但简单地说,传统RNN和门控(GRU)是无法捕捉的长期依赖性因其自然消失的梯度设计和遭受严重的问题,这使得权重和偏置值的变化率可以忽略不计,导致器泛化性的降低。
但是LSTM有一些特殊的单元称为门(记忆门,忘记门,更新门),这有助于克服前面提到的问题。
在LSTM细胞内,我们有一堆小型神经网络,在最后一层有sigmoid 和TanH激活和少量矢量加法,连接,乘法操作。
Sigmoid NN→压缩0到1之间的值。说接近0的值表示忘记,而接近1的值表示记住。
EmbeddingNN→将输入的单词索引转换为单词嵌入。
TanH NN→压缩-1和1之间的值。有助于调节矢量值,使其免于爆炸至最大值或缩小至最小值。
隐藏状态和单元状态在此称为上下文向量,它们是LSTM单元的输出。输入则是输入到嵌入NN中的句子的数字索引。