目的:为了更系统的学习,在这里总结了NLP文本表示的若干方法,部分代码,仅供参考,欢迎交流。
文本表示
离散表示:代表:词袋模型,one-hot,TF-IDF, N-gram。
分布式表示:词嵌入(word embedding),经典模型:词向量(word2vec)、Glove、ELMo、GPT、BERT。
一. 离散表示
One-hot encoded
one-hot向量不是一个好的选择,one-hot词向量无法表达不同词之间的相似度,例如任何一对词的one-hot向量的余弦相似度为0
Label Encoder标签编码
将离散的数据转换成(0,n-1)之间的数,n表示数据的不同取值,用代码表示以下:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit([1,5,67,100])
le.transform([1,1,100,67,5])
//输出 array([0,0,3,2,1])
缺点:类别数量很大时,特征空间会非常大,比如10000个单词的one-hot编码为一个10000*10000的矩阵。参数非常多。
Binary Encoder二进制编码
二进制编码,用序号给每个类别赋一个ID,根据这个ID对应的二进制编码作为结果。
Bag-of-words模型原理
忽略文本的语法和语序,用一组无序的单词来表达一段文字或一个文档。
John likes to watch movies. Mary likes too.
John also likes to watch football games.
根据上诉两句话中出现的单词,构建一个dict:{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also": 6, "football": 7, "games": 8, "Mary": 9, "too": 10}
该字典包含两句话中全部词语,字典中的顺序与他们出现在句子中的顺序没有关系,根据这个词典上述两句话数字化为:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1] 即John出现1次,likes出现2次。。。
[1, 1, 1, 1, 0, 1, 1, 1, 0, 0]
其中第i个元素表示字典中第i个单词在句子中出现的次数。
使用场景:在一个巨大的文档集合D,里面一共有M个文档,而文档里面的所有单词提取出来后,一起构成一个包含N个单词的词典,利用Bag-of-words模型,每个文档都可以被表示成为一个N维向量。
之后就可以对向量进行一系列的处理。。。
优点:简单
缺点:无法关注词语之间的顺序关系。
TF-IDF(Bag-of-words)
TF:给定词语在该文档(有多个文档)中出现的次数,归一化为(词频除以文章总词数)。
IDF:反应一个词在所有文档中出现的频率,如果一个词在多个文本中出现,那么他的IDF值应该很低,相反一个词在较少了文本中出现,那么IDF值应该很好,如果在每个文本中都出现IDF值为0。
综合TF和IDF值,来判断一个词的重要性。TF-IDF的值,用以评估词对于一个文件集或则语料库的重要程度。字词的重要性随着他在该文档中出现的次数成正比,但同时会随着他在(所有文档)语料库中出现的频率成反比下降。比如“machine learning”在该文档中出现的次数越多,而在其他文档出现频率低,说明该词在该文档的重要性很高。又比如“the,for”等词在该文档出现次数很多,但在所有文档出现的次数都很多,说明该词并不是那么重要。
其中,是某词在该文档中出现的次数,表示该所有文档中的总词数(也可以是该文档的总词数?)。
其中,Y是语料库的文档总数,是包含词条的文档数。
TF-IDF就是将TF-IDF相乘。
根据上述公式,某一特定文档内的高频词汇,同时该词语在整个文档集合中的低文件频率,可以产生高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
N-gram
词袋模型(bag-of-words)不考虑单词的顺序,就想把单词全装到一个袋子里,而接下来的N-gram模型就会考虑句子中单词之间的顺序。
N-gram模型是一种语言模型(Language model, LM),语言模型是一个基于概率的判别模型,它的输入是一句话(单词的顺序序列),输出是这句话的概率,即这些单词的联合概率(joint prpbability)。
如果一个词的出现仅依赖它前面出现的词,称之为Bi-gram。
如果一个词的出现仅依赖它前面出现的两个词,称之为 Tri-gram。
根据上面的Bi-gram公式,我们可以得出句子:<s> I want Chinese food <s>的概率为:
已知,...于是:
于是就算出了“I want chinese food”这句话的概率,同理你可以得到“want i chinese food”的概率值很小,远小于,说明前一个句子更像人话。但有时候这句话会很长,那么概率(都是小于1的常数)的相乘很可能造成数据下溢(downflow),即很多个小于1的常数相乘会约等于0,此时可以使用log概率解决。
N-gram用途
- 词性标注
- 垃圾短信分类
- 分词器:用N-gram实现一个简单的分词器(Tokenizer)
- 机器翻译和语音识别
N-gram的一些方法
N-gram中的N越大,模型的Perplexity越小,模型效果越好,因为依赖的词越多,获得的信息就越多,对未来的预测就越准确,但是当N很大时,会出现稀疏问题。
n-gram最大的问题就是稀疏问题(Sparsity)。例如,在bi-gram中,若词库中有20k个词,那么两两组合就有近2亿个组合。其中的很多组合在语料库中都没有出现,根据极大似然估计得到的组合概率将会是0,从而整个句子的概率就会为0。最后的结果是,我们的模型只能计算零星的几个句子的概率,而大部分的句子算得的概率是0,这显然是不合理的。
因此,要进行数据平滑(data Smoothing),数据平滑的作用:一个是使所有的N-gram的概率之和为1,使所有的n-gram概率都不为0。
具体讲解可看这篇文章
二. 分布式表示 Word Embedding(词嵌入)
Word Embedding(词嵌入)是将文本中从词转换为数字向量的方法,把一个维度很大的词向量嵌入到一个维度低得多的向量空间中,每个单词或词组被映射为实数域上的向量,词嵌入的结果就是生成了词向量。Word2Vec和Glove都是Word Embedding的经典算法。
1. Word2Vec
Word2Vec:词到向量,是word embedding(词嵌入)的一种。只有把词(抽象,符号)转到向量(数值),计算机才能明白。语义相同的词的词向量接近。
1.1 语言模型
如果用一个词语作为输入,来预测他上下文的词汇,这个模型就叫做Skip-gram模型。
如果用一个词语的上下文来作为输入,来预测这个词语本身,这就是CBOW(Continuous Bag-of-words)模型。
用当前词x预测它的下一个词y
这里的x的原始输入只能是数值类型,显然是one-hot encoder,通过输入one-hot格式,得到word2vec格式。
Skip-gram模型(y只有一个词)
即one-hot格式的输入,隐藏层的权重矩阵即为该词的词向量,为输出向量,也是one-hot格式。V即使词语的个数,隐藏层的激活函数是线性的,相当于没有做任何的处理,训练这个神经网络采用反向传播算法。这里的输入和输出维数相同,但在一般情况下输出的维度要远小于V,所以word2vec也是一种降维操作,把词语从one-hot encoder形式的表示降维到word2vec形式表示。
Skip-gram模型(y有多个词)
CBOW的一般情况
使用多个词预测一个词。
1.2 训练策略
前面了解了skip-gram的输入层,隐藏层,输出层。在第二部分,会继续深入讲如何在skip-gram模型上进行高效的训练。
Word2Vec模型是一个超级大的神经网络,10000个单词的词汇表,嵌入到300维的词向量,那么我们的输入-隐层权重矩阵和隐层-输出层的权重矩阵都会有 10000 x 300 = 300万个权重。
Word2Vec的作者在他的第二篇论文中强调了这些问题,提出三点:
- 将常见的单词组合(word pairs) 或者词组作为单个的“words”来处理,减少输入维数。
- 对高频单词进行抽样来减少训练样本的个数。
- 对优化目标采用“negative sampling(负采样)”方法。不仅降低了训练过程中的计算负担,还提高了训练的词向量的质量。
1.2.1 Word pairs and 'phases'
作者指出,一些单词组合(或词组)的含义和拆开以后具有完全不同的意义。比如“New York”,当文章中出现这种词时,我们应该把它作为一个单独的词来训练生成词向量,而不是拆开。
1.2.2 对高频词抽样
训练过程中的高频词,the,for,is等等对训练没有帮助。Word2Vec通过抽样模式解决这种高频词问题,根据在文本中出现的概率,来删除高频词。
抽样率
是一个单词,时这个单词在所有语料中出现的频次,代码中有一个参数交sample,表示一个阈值,这个值越小意味着这个单词被保留下来的概率越小(即词频越容易达到阈值,越容易被删除)。
代表保留某个单词的概率:
可以自己修改这些参数。
1.2.3 负采样(negative sampling)
解决大规模参数的问题
负采样能够提高训练速度,改善得到词向量的质量。以前是对每个样本进行训练更新所有的权重,而负采样每次让一个训练样本仅仅更新一小部分权重。
当我们用训练样本 ( input word: "fox",output word: "quick") 来训练我们的神经网络时,“fox”和“quick”都是经过one-hot编码的。如果我们的vocabulary大小为10000时,在输出层,我们期望对应“quick”单词的那个神经元结点输出1,其余9999个都应该输出0。在这里,这9999个我们期望输出为0的神经元结点所对应的单词我们称为“negative” word。
当采用负采样时,我们将随机选择一小部分的negative words(比如5个),来更新对应的权重,也会对"positive" word进行权重更新。同时更新negative sampling和positive word。(在论文中,作者指出指出对于小规模数据集,选择5-20个negative words会比较好,对于大规模数据集可以仅选择2-5个negative words。)
如何选择negative words
使用“一元模型分布(unigram distribution)”来选择negative words。
一个单词被选作negative word的概率和它出现的频次有关,频次越高越容易被选作negative words。
其中表示单词出现的频次。
Word2Vec(CBOW和Skip-gram)存在的问题
优点:会考虑上下文,比Embedding方法更好;维度更小,速度更快;通用性很强,适用于各种NLP任务
缺点:对多义词无法很好的表示和处理,因为使用了唯一的词向量。Cbow/Skip-Gram 是一个local context window的方法,缺乏了整体的词和词的关系,负样本采用sample的方式会缺失词的关系信息。
2. Glove
Global Vector融合了 矩阵分解(LSA)的全局统计信息 和 local context window(局部窗口)优势。融入全局的先验统计信息,可以加快模型的训练速度,又可以控制词的相对权重。
skip-gram、CBOW每次都是用一个窗口中的信息更新出词向量,但是Glove则是用了全局的信息(共现概率矩阵Co-occurrence Probabilities Matrix),也就是多个窗口进行更新。矩阵中的每一个元素代表单词i和上下文单词j在特定大小的上下文窗口(context window)内共同出现的次数。
构建词向量(Word Vector)和共现矩阵之间的近似关系,通过下面的公式表示:
其中,和是我们最终求解的词向量,和分别是两个词向量的偏执。详细推导这里。
通过公司1就可以得到loss function:
loss function的最简单函数就是MES,只不过在此基础上加上了权重函数。作用
- 经常在一起出现的单词的权重要大于很少在一起出现单词的权重---非递减函数;
- 也不能无限增大,当达到一定程度就不再增加;
- 如果两个单词没有一起出现过即=0;
根据论文取值为0.75,取值100。
缺点:一词多义的问题尚未解决,因此,引出下面的模型。
3. ELMo
在此之前的Word Embedding本质上是一个静态的方式,即训练好的词向量就固定不变了,不论新句子的上下文是什么,这个单词的Word Embedding不会跟着语境变化。
ELMo的本质思想:事先用语言模型在一个大的语料库上学习好词的word embedding,此时的多义词任然无法区分,接着用特定的训练数据来fine-tuning预训练好的ELMo模型。(domain transfer)
1. 预训练
ELMo使用双向LSTM语言模型,由一个前向和后向语言模型构成。语言模型的训练任务是:根据单词的上下文取正确预测。每个编码器的深度都是两层LSTM叠加。
前向LSTM模型计算序列的概率,输入为从左到右顺序的除了的上文:
反向LSTM根据未来的内容预测之前的token,输入为从右到左的逆序的句子的下午:
双向BiLM结合两者,联合最大化log似然函数:其中是token,是softmax层表示。
使用这个网络,利用大量语料预先训练好这个网络,之后输入一个新的句子,句子中的每一个单词都能得到三个Embedding:
- 最底层是单词的word embedding;
- 第一层双向LSTM中对应单词位置的embedding,这层编码单词的句法更多一些;
- 第二层双向LSTM是对应单词位置的Embedding,这层单词编码的语义信息多一些;
2. 下游任务
- 先将句子X作为预训练好的ELMo网络的输入,这样句子X中每个单词在ELMo网络上都能获得三个embedding;
- 给予这三个embedding中每一个embedding权重a,这个权重可以学习得到,也可以累加求和,将三个embedding整合成一个;
- 将整合后的embedding作为X句在自己任务的网络结果中对应单词的输入。
4. OpenAI-GPT
5. BERT
任重道远啊~
参考
NLP自然语言处理:文本表示总结 - 上篇word embedding(基于降维、基于聚类、CBOW 、Skip-gram、 NNLM 、TF-ID、GloVe )