使用tensorflow实现seq2seq
上篇文章记录了seq2seq和attention机制的基本原理,这篇文章趁热打铁看看如何自己写代码实现。
tf2的一些API操作
推荐一个学习tensorflow的教程:https://github.com/lyhue1991/eat_tensorflow2_in_30_days
1 | import tensorflow as tf |
连接操作(tf.concat)
1 | t1 = [[1, 2, 3], [4, 5, 6]] # 2, 3 |
`长路漫漫,唯剑作伴`
上篇文章记录了seq2seq和attention机制的基本原理,这篇文章趁热打铁看看如何自己写代码实现。
推荐一个学习tensorflow的教程:https://github.com/lyhue1991/eat_tensorflow2_in_30_days
1 | import tensorflow as tf |
连接操作(tf.concat)
1 | t1 = [[1, 2, 3], [4, 5, 6]] # 2, 3 |
Seq2Seq
Seq2Seq
结构用于多个输入和多个输出的模型,但是输入和输出的大小可能并不一致,其本质上也是RNN
网络的一个扩展,常见的应用场景包括:机器翻译、语音识别、文本摘要等。
常见的seq2seq
的输出的计算方法包括以下两种:
注意这里C到y1、y2、y3
的计算,虽然有两种方式,但是C本质上是前半部分的最终输出状态,并非每个时间步的输出,这里搞清楚对于后续的注意力机制的理解也有帮助。
在seq2seq
结构中,通常将整个模型分为encoder和decoder两个核心组件,连接两个组件的就是context vector,即Encoder组件生成的上下文向量。
之前有一篇文章已经初步介绍过RNN
的原理,里面其实已经介绍的比较清晰易懂了,这篇文章再来回顾和拓展一下:https://forchenxi.github.io/2021/04/23/nlp-rnn/
首先要知道RNN
是一个带有内部环的神经网络,上面的这篇文章中的图描述的更形象,这里再来简单回顾下,使用tensorflow
来实现(实际也是用keras
来实现的)。
这里的Word2Vec借助 gensim 库实现,首先安装pip install gensim==3.8.3
1 | from gensim.models.word2vec import Word2Vec |
参数说明:
Word2Vec
在自然语言发展的早期阶段,词的表示经历了不断地发展和改进,直到后来有一种word vector的思想被提出以及后续的实现,才极大地促进了NLP
的发展。
word vector的核心思想:
为每个单词构建一个密集向量,选择后的向量与出现在类似上下文中的单词向量相似。
注:word vectors 也叫 word embeddings 或者 (neural) word representations,它们是分布式表示的。
这样的思想确实很好,可是如何实现是一个难点,实际上在2003年,Neural Probabilistic Language Model就实现了符合这种需求的词向量,不过它的本意是训练一个语言模型,词向量的生成只不过是一个附属物,并且鉴于此模型中只使用了有限的前文信息,并且计算量过大,在2013年 Mikolov
等人提出一个改进模型,用于学习词向量的表示。该模型的核心技术包括以下几点 。
本文代码部分参考github项目:
https://github.com/BSlience/search-engine-zerotohero/tree/main/public/bert_wwm_pretrain
本文的主要内容是基于huggingface transformer的chinese-bert-wwm模型,在自己的语料集上进行finetune的整体步骤和代码实现。
关于chinese-bert-wwm:
https://huggingface.co/hfl/chinese-bert-wwm
https://github.com/ymcui/Chinese-BERT-wwm
主要步骤包括:预处理和训练两个部分
预处理(pre-processing)
步骤1的下载地址:https://huggingface.co/hfl/chinese-bert-wwm/tree/main
如果生成的语料集比较大,为了后续加载方便可以存储至内存型的数据库中(比如Redis)
训练(train)
关于data collator的实现可以查看我的上一篇文章whole word mask;
步骤3加载的预训练权重文件就是上述预处理步骤1下载的,不过要注意把config.json和pytorch_model.bin放在同一个目录下,然后加载这个目录即可。
本文代码部分参考github项目:
https://github.com/BSlience/search-engine-zerotohero/tree/main/public/bert_wwm_pretrain
Whole Word Masking (wwm),暂翻译为全词Mask或整词Mask,是谷歌在2019年5月31日发布的一项BERT的升级版本,主要更改了原预训练阶段的训练样本生成策略。我们先看下BERT原文的遮蔽语言模型。
在BERT之前,标准的条件语言模型只能从左到右或从右到左进行训练,因为双向条件作用将允许每个单词在多层上下文中间接地看到自己,为了训练深度双向表示,BERT采用了一种简单的方法,即随机遮蔽一定比例的输入标记,然后仅预测那些被遮蔽的标记,这一过程被称为遮蔽语言模型(MLM, masked language model),尽管在文献中它通常被称为完型填词任务。
在这种情况下,就像在标准语言模型中一样,与遮蔽标记相对应的最终隐藏向量被输入到与词汇表对应的输出 softmax 中(也就是要把被遮蔽的标记对应为词汇表中的一个词语)。在所有的实验中,BERT在每个序列中随机遮蔽 15% 的标记。
虽然这确实允许我们获得一个双向预训练模型,但这种方法有两个缺点。第一个缺点是,我们在预训练和微调之间造成了不匹配,因为 [MASK] 标记在微调期间从未出现过。为了缓和这种情况,我们并不总是用真的用 [MASK] 标记替换被选择的单词。而是,训练数据生成器随机选择 15% 的标记,例如,在my dog is hairy 这句话中,它选择 hairy。然后执行以下步骤:
Transformer 编码器不知道它将被要求预测哪些单词,或者哪些单词已经被随机单词替换,因此它被迫保持每个输入标记的分布的上下文表示。另外,因为随机替换只发生在 1.5% 的标记(即,15% 的10%)这似乎不会损害模型的语言理解能力。
第二个缺点是,使用 Transformer 的每批次数据中只有 15% 的标记被预测,这意味着模型可能需要更多的预训练步骤来收敛。在 5.3 节中,我们证明了 Transformer 确实比从左到右的模型(预测每个标记)稍微慢一点,但是 Transformer 模型的实验效果远远超过了它增加的预训练模型的成本。
项目地址:https://github.com/huggingface/transformers
文档地址:https://huggingface.co/docs/transformers/pipeline_tutorial
Transformers 提供了数以千计的预训练模型,支持 100 多种语言的文本分类、信息抽取、问答、摘要、翻译、文本生成。
从这里:https://huggingface.co/models 可以查找你要的模型,可以根据任务、语言、框架、数据集等筛选。
这里我们想要进行基于中文的ner任务,筛选出这个模型: bert-base-chinese-ner
打开之后,通过介绍我们发现这是一个基于繁体中文的模型,对应的github地址是:
https://github.com/ckiplab/ckip-transformers
有需要的小伙伴可以尝试。
我们继续筛选,找到了这个模型:uer/roberta-base-finetuned-cluener2020-chinese