一、前言
在上篇文章中,我们介绍了Word2Vec以及它的作用,总的来说:
-
Word2Vec是我们理解NLP的第一站
-
Word2Vec将词变成了“向量”—— 终于可以用机器理解词语的相似度
-
我们获得了例如“国王 - 男人 + 女人 ≈ 女王” 的类比能力
-
我们可以将Word2Vec这种算法能力,应用到各种创新场景,例如基于Graph的推荐系统,后续如果小伙伴有需要,可以一起深入交流。
但同时也指出了它的不足:
-
一个词=一个固定向量(静态词向量)
-
上下文无感知:“苹果”无论是手机还是水果,向量相同
-
是词的映射,不是对语言的理解
那如果让我们来设计下一代的算法,什么最重要?
——我们需要“能读懂句子”的模型。
接下来我们一步步实现,直至引出bert。
二、Word2Vec是怎么工作的?
在上文,我们介绍到Word2Vec使用周围词预测中间词来获取词向量能力,这个被称为CBOW,同理也可以用中间词预测周围词,这个称为Skip-Gram。本质来讲,Word2Vec是一个浅层神经网络,结构如下:
from torch import nn
class Word2VecModel(nn.Module):def __init__(self, vocab_size, embedding_dim):"""vocab_size:词总数embedding_dim:超参,词对应的向量维度,例如64、128"""super().__init__()self.embed = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)
最终可训练部分是self.embed部分。
三、我们需要一个分词器
在前文中,我们输入的都是一个一个分好的词,但是呢,有几个问题:
- 怎么分词的?
- 分词的目的是什么?
- 中文怎么分词?英文怎么分词?其他语言怎么分词?
- 分词在对整句语义理解上的重要程度是怎样的?
1. 怎么分词的?
我们平时写作时,不像英文每个单词中间有空格,而是一个字一个字连着写直至整句话完成。例如“今天你真漂亮”,我们希望分成 今天 你 真 漂亮。
在中文分词研究历史中,有着比较漫长的过程。整体可认为是统计概率建模的过程,比如建立一个巨大的词表,然后通过一堆的算法,例如隐马尔克夫链,建立前词和当前词的转移概率。蹭蹭蹭,我们获得了一个分词模型。哈哈,此处我们不做具体原理讲解。如果需要,最近可着重看HMM和CRF,再往前推,有基于最长词的分词算法。总的来说,统计概率建模,就是获取所有影响分词结果的因素,对其进行建模以及学习其权重。例如针对CRF,本质是学习状态转移概率矩阵、发射概率矩阵,最终形成一个有向词网,节点为词,获取最大概率那条路径,就是分词结果。
现在也有一堆基于神经网络的分词工具,整体都可认为是命名实体标注任务,如果有需要小伙伴,可以一起交流。
如果只是为了工程应用,可使用jieba、HanLP、LAC等。
2. 分词的目的是什么?
我们为什么要分词?不分词行不行,直接一句/段话直接输入给模型不就行了。这里牵扯到对语言建模输入最小粒度问题,可以将“今天你真漂亮”切分成一个一个字,也可以切分成上面的结果,以这个结果作为网络的输入。
OOV(Out-of-Vocabulary)问题,这个小伙伴在体验Word2Vec能力时可能已经发现,针对一些俚语,会发现这个词不在Word2Vec表内。那就导致无法获取这个词的词向量。
3. 中文怎么分词?英文怎么分词?其他语言怎么分词?
有没有一个统一算法,可以支持任意一种语言的分词。有!这个就是大名鼎鼎Bert用到的WordPiece。
注意,如前面所说,分词更偏向是中文领域一个特定的任务,而对于英文,可能就直接按照空格就完成了分词任务。所以,请将分词概念延伸至Tokenization概念,分的词被称为Token,分词的动作称之为Tokenizer。
WordPiece是一种将词分解成更小单元的方法。
具体如何实现此处不涉及。以及现在也有其他tokenizer方法,例如BPE等。
4. 分词在对整句语义理解上的重要程度是怎样的?
严格意义上来讲这里有提升空间,包括目前大模型所使用到的。为什么这么讲,因为分词作为最初输入,其准确率影响后续的计算结果。“南京市长江大桥结婚了。”,这句话是不是没有任何语义歧义,不像“白天鹅在湖中游”,“大学生活好”,“黑暗的夜总会迎来黎明”吧。
至此,模型的输入我们搞定啦。
四、我们需要设计训练任务
在Word2Vec的CBOW模型中,是用周围词预测中心词。我们可以将这个条件延伸下:
-
预测中心词这个事,我们将中心词掩盖掉这个事情称为[MASK]。
-
为什么非要预测中心词呢?我们完全可以随机掩盖掉一句话中某个词。
例如输入一句话“今天天气真不错”,经过上面tokenizer后,变成了“今天 天气 真 不错”,随机掩盖掉某个词(例如真),变成了“今天 天气 [MASK] 不错”,那我们的目标是预测[MASK]部分的标签是“真”,由此我们获得了输入与输出。
五、我们需要一个强大的网络
在Word2Vec中,我们的网络结构只有一个nn.Embedding,即词和向量的映射表,整个结构还太简单。那我们再引入一个新的算法架构——Transformer。
有的小伙伴可能提前已经了解过一些深度学习算法,例如LSTM,那会问LSTM不能处理这种序列问题吗?当然,完全可以,至此我们做到了,每个token都有一个上下文相关的向量表示。
到这里我们发明了Masked Language Model(MLM)。
当然bert的预训练不止mask这一个任务,还有被称为NSP(Next Sentence Prediction)任务,即给定两句话A和B,让模型判断B是否是A的下一句。
当然这个任务在后面的研究(例如Roberta)中被证明此任务作用并不大,不过我们知道下就行了。
关于BERT更具体原理讲解,有需要的话后面可一步步实现。
特点 | Word2Vec | BERT |
---|---|---|
向量类型 | 静态 | 动态(与上下文相关) |
模型结构 | 浅层神经网络 | 多层 Transformer |
能否理解语境 | 否 | 是 |
预训练目标 | 预测词 | Mask + NSP |
六、BERT模型有什么用?
这是一个好问题,上面蹭蹭说到了一堆似乎和应用无关的东西,总而言之,BERT的出现:
- 我们获得了一个通用的语义理解模型,基于这个模型,我们可以和更多现实应用建立起桥梁。
- 降低了算法训练与应用难度,BERT作为一个预训练模型,由于其本身已经获取到通用语言场景下的语义理解能力,那么相关的NLP任务都更为容易做成。例如文本分类、情感分析、命名实体识别、搜索等。
七、如何应用?
Bert作为预训练模型,其本身并不能做太多事情,例如MASK和NSP。我们一般会在Bert模型之后再接一些其他的Layer来做具体任务。下面我放几个应用截图,这些都是Bert可以做到的。如果有感兴趣的我可以一步步实现哦。
與情分析
命名实体/情感分析