【深度学习】⑤--自然语言处理的相关应用
作者:互联网
【深度学习】⑤--自然语言处理的相关应用
王小草 浪尖聊大数据
恩恩,关注我好了
1. 自然语言处理(NLP)的常见任务
先来看看在工业界对于自然语言处理的一些常见需求与任务。
自动摘要
这个在搜索引擎中非常常用。指计算机能自动去阅读一篇文章然后去提取这篇文章的摘要。
指代消解
比如“小明放学了,妈妈去接他”这句话中的“他”指代为“小明”。这个计算机本身并不知道,而我们希望计算机能自己去识别这些指代的对象。
机器翻译
这个非常熟悉,比如中英文的互相翻译。我们希望计算机能自动地将一种语言翻译成另一种语言。
词性标注
即计算机能自动去标注出每个词的词性(动词,形容词,副词,名次等等)
分词
即为一个句子去断句,比如“小明/很/难过”,“大水沟/很/难/过”。在前一个句子中“难过”是一个词语,表示一种感情;后一个句子中“难过”表示“难以/通过”。我们人很容易去区分句子中的每个词,但是计算机本身是不知道哪两个字是词语的。另外,英文的分词可以通过空格,而中文却需要建立其他规则,这个为中文分词(日文韩文也是)增加了许多难度。
主题识别
即在一堆文章中去识别各个文章的主题。比如输入1000篇文章,通过某种算法可以知道有100篇文章是在讲同一个主题--“体育”。
文本分类
这是分类问题中的一种,只是现在是对“文本”进行分类,文本的特征不是自带与直观的,需要通过文本中的内容(词)来提取。在工业界(其实我不知道为啥要叫工业界,而不是商业界),经常需要去区分文章的情感类别是负面还是正面,或者区分文章是在属于哪个行业等等。
......
传统的NLP处理方法是基于规则的
现代的处理方法更倾向与统计机器学习,比如HMM,CRF,SVM.LDA,CNN等,”规则“是隐含在模型参数里的。
2. 词向量的传统方法介绍
任何一篇文本都是由“词”组成的。所以对大多数对文本问题的分析,其实最终还是归结于对“词”的分析。这里先不讨论如何“分词”的知识,假设我们已经成功地分好了词。要将自然语言的问题来运用机器学习或深度学习的模型来解决的话,就必须要将这些计算机本身不认识的“词”转化为“数字”,即通过“向量”的形式来表示。如此一来,我们就可以通过对向量的各种统计运算来解决问题了。(这个过程也可以看成是给“词”进行“编码”)
那么问题来了,如何对词进行编码才能更有效呢?
2.1 离散表示--One-hot
假设我们语料库中有以下两句话,按空格进行分词:
可以对每个词进行标注,形成词典,这样每个词都有它唯一和独有的编号或索引。
根据每个词在词典中的索引,可以用One-hot的形式如下表示,在一个向量中,只有在这个词所在的索引处的值为1,其他都为0。
这是一个比较传统的词向量表示法,在很多场景中都仍然被使用。使用这种词向量的缺点是,词在词典中的顺序和在句子中的顺序是没有关联的。而且词和词之间也是无法通过这种方式计算出相似性的。
2.2 离散表示--Bag of words
运用One-hot方法,将一整个文档映射成一个向量的时候可以将各个词的词向量表示加和。如下:
通过文档的向量我们可以运用TF-IDF算法去求取每个词在文档中的重要程度。
TF值--> 求每个文档中的各个词出现的频数,频数越大则说明这个词在该篇文档中的重要性越大。
IDF值--> 另一个角度,如果一个词在所有文章中出现得都很多,那么可能是停用词,比如“的”,“啊”等,说明越不重要
只有在某篇文章中出现地很多,但在其他文件中出现得少的词才是对这篇文章重要的词,那么这个词的权重应该比较高。基于这样的理论,我们将TF*IDF来表示词对某篇文章的重要值。
将第一句话用TF-IDF来表示:
图片
另一种粗暴的方式是Binary weighting。在计算“短文本相似性”可以使用。
即只要TF-IDF值大于0,则标注为1,否则为0.
2.3 离散表示--Bi-gram 和 N-gram
为2-gram建索引如下:
即从第一个词开始,取出所有相邻的两个词对(保持两个词的先后顺序),并对他们建立索引。这样的话之前的两句话的文档向量可以如下便是
这个方法考虑了词的顺序,但是缺点是词表的膨胀。下表罗列了当n-gram中的n增大,模型的参数数量也指数膨胀。
离散表示存在的问题
1.无法衡量词向量之间的关系
比如下面三个词,酒店,宾馆,旅社,应该是三个近义词,但是他们在用离散方式表示出来的词向量中完全无从得知他们是否是相似的。
2.词表维度随着语料库的增长而不断膨胀。
3.n-gram词序列随语料库膨胀更快。
4.存在数据稀疏问题。
2.4 分布式表示--distribued representation
由于分散表示存在诸多问题,所以人们开始想能不能用分布式的方式来表示呢?
1957年就有学者提出“用一个词附近的其他词来表示该词”
基于以上理论,我们来讲一讲“共现矩阵(Cocurrence matrix)
共现矩阵现在主要用于发现主题(topic),比如LAS(Latent Semantic Analysis)
假设我们现在有以下三个文档(分别是是三句话)
将window length设置为1,即对任意一个词,在其左右两边相隔1个词之内的才可以看作是这个词的相近词。(窗口长度一般设为5-10之间)
基于窗口大小为1,可以转换成如下矩阵(共现矩阵)。比如当I出现的时候,1个长度的窗口内,like出现了2次,enjoy出现了1次。如果两个词共同出现的次数越多则说明这两个词越相似。
将共现矩阵的行或列作为词向量也存在着一些问题:
1.向量维数随着词典大小线性增长,即词越多,则向量维度也随之越大。
2.存储整个词典的空间消耗非常大。
3.一些模型如文本分类模型会面临稀疏性问题
4.模型会欠稳定。当有新的文档进来之后,整个矩阵要重新计算。
2.5 SVD降维
因为共现矩阵的存在维度大又稀疏的问题,于是人们考虑着使用某种方法将其降维。最直接的想法就是用SVD对贡献句子向量做降维。
下面贴上了一份python代码用来做词向量的降维。
SVD其实就是矩阵分解,将原来的稀疏矩阵分成三个稠密矩阵。
S是一个对角矩阵。每个元素就是一个主成分,我们可以提取出主成分比较高的一些元素。
SVD降维也存在一些问题:
1.计算量随着语料库和词典的增长膨胀太快。
2.难以为慈溪店中新加入的词分配词向量。
3.与其他深度学习模型框架差异大。
3. 神经网络语言模型NNLM
NNLM全称Neural Network Language model,直接从语言模型出发,将模型最优化过程转化为求词向量表示的过程。
既然离散的表示有辣么多缺点,于是有小伙伴就尝试着用模型最优化的过程去转换词向量了。
3.1 目标函数
NNLM的目标函数如下:
比如”我/是/中国/人“这句话,Wt是“人”,是“人”前面的词,前面的词的长度我们叫前向窗口函数,窗口长度为n-1,因为只有前面的词,所以是非对称的前向窗口函数。也就是说目标函数求的是,当“我”“是”“中国”这几个词出现的时候,后面出现“人”的概率的最大值。
这个窗口会滑动遍历整个语料库并且求和,计算量正比与语料库的大小。
概率P满足归一化条件,这样不同位置t处的概率才能相加,即:
3.2 NNLM的结构
首先,不要方。
然后,请看左边的神经网络图,解读这个NNLM的神经网络总共可以分成4步:
第一步:模型的输入
最底层的小绿方块是输入的数据,每一个输入是一个词,但不是一个文本形式的词,而是一个One-hot的词向量,即一个向量中,只有这个词所在的索引处为1,其他位置都为0。假设我们又40000个词,那么就有40000个词向量的输入。
第二步:词嵌入
从最后一层的小绿到最后第二层的过程叫做word-embedding,词嵌入。
是这样的,首先我们要自己初始化一个投影矩阵C(用稠密响亮表示)。这个投影矩阵的行数是“维度”一般设置为500,列数是输入的词向量的大小,40000。(500*40000)
矩阵中的权值w是可以事先人为初始化,在训练模型的时候会找到最优的w值的,所以初始化的时候随意。
将输入的每个One-hot词向量都分别乘以投影矩阵C,因为每个词向量上只有自己的索引处为1,所以相乘后C中只会有对应的一列被保留,这一列就是导数第二层所得到的数据。此时One-hot的向量变成了一个5001的向量。也就是说整一个词嵌入层有5001*40000维。
第三步:隐藏层
将词嵌入向量输入隐藏层。这里隐藏层和我们之前学的神经网络中的隐藏层是一样的,同时也是个全链接。如果隐藏层有100个神经元,那么权重θ的个数就是50040000100。在进行线性转换后输入激励函数tanh,激励函数的输出为隐藏层的输出。
第四步:输出层
最上面的一层是输出层,输出层的个数与输入的词的个数相同,为40000。
从激励层出来进过softmax转换,就会有40000个输出结果,每个结果是一个向量,对应一个词,向量里是这个词属于每个词的概率,如果效果好的话,应该是one-hot向量里本来是1的位置,在输出的概率向量里,应该是概率越大越接近于1才好(语无伦次了。。。)。
以上就是NNLM的结构了。然后根据上面提到的目标函数求解最大值,利用BP+SGD去寻找最优的权重θ和投影矩阵中的W值。
最后,NNLM就做好了。。。
3.3 计算复杂度
计算的复杂度如下计算
N D + N D H + H V
N是输入的词的个数,D是投影矩阵的维度,H是隐藏层的维度,V是词数
可以看出,计算的复杂度相当高啊,而且语料库中的词越多的话复杂度越大,这么逆天的复杂度要让工业界实战的小伙伴分分钟泪崩的。谷歌的高智商童鞋们肯定耐不住寂寞,于是的于是有了接下来要讲的内容。
4. Word2vec -- CBOM(连续词袋)
4.1 结构
由于NNLM的计算复杂度,谷歌的小伙伴们提出了word2vec的两个方法,一个是CBOM,中文一般叫连续的词袋。
计算量最大的应该是从词嵌入层到隐藏层的这一步,因为词嵌入层的输出是50040000,隐藏层如果有100维的话,权重的数量就达到了50040000100个了,于是小伙伴们就想能不能压缩这个词嵌入层呢?再于是,他们将40000个维度相加成了1个维度,也就是将50040000压缩成了5001,现在词嵌入后的输出就变成了500维,隐藏层的计算复杂度就减小到了500100了。
但是这样的复杂度还是没有达到完美主义学者的要求,他们又将原来的隐藏层也去掉了,直接将词嵌入的结果相加降维后输入了softmax到达输出层。这样计算的维度就从500100 + 100 40000变成了500*40000了。
除了以上两个变化,CBOM还有一些特殊特性。CBOM不再采用之前NNLM的前向窗口函数,而是使用双向上下文窗口,比如“我/是/中国/人”中的“中国”的概率是由左右两边的词共同影响的:P(中国/我,是,人),并且是没有顺序的:P(中国/我,是,人) = P(中国/是,我,人)
4.2 目标函数
仍然是通过求目标函数的最大值来获取最优的参数。
第一个公式,w是某个词,context(w)是w的上下文,也就是左右的词,词数根据设置的窗口大小而定。
第二个公式是由第一个公式转化而来,在求最优化时我们一般将它转化成log的形式。并且带入了降维后的词嵌入矩阵到输出层的运算公式。
第三个公式是第二个公式转化而来,因为一个词的出现有多个上下文词,所以用j去遍历。
4.3 层次Softmax
虽然通过以上若干的改进,CBOM已经比NNLM要简化与优化很多了。但是虽然通过去隐层,求和等方式将维度将至了500*40000,但是好不容易降到了500,在最后一步又上升到了40000,让人内心略感不爽。所以,之后就提出了两种解决办法来降低最后一步的计算复杂度。首先介绍一下“层次Softmax”
我们来看output layer的这一步,这里使用了Huffman树。如果要找到“足球”这个词的输出结果,只需要沿着这棵树的根,一直下来走4步就到了“足球”的叶子节点。如果按照之前的方法,我们需要去对40000个词都平铺计算一遍才能获得“足球”这个词的输出概率向量。
霍夫曼树上的每个节点其实可以看成是一个分类器,“足球”这个词就是经过了4个二分类的分类器计算出来的。通过这种方式,只需要计算路径傻瓜所有非叶子结点词向量的贡献即可。计算量降为树的深度:V => log_2(V)
下面是层次Softmax的目标函数:
4.4 负例采样
负例采样是另一种改进输出层的方式。
在原来的输出层中,会输出40000个向量,每个向量又会有40000个维度,然后只有一个维度是正样本,V-1个(39999)为负样本,但其实我们要得到的只是哪一个正样本,所以对于那么多的负样本我们没有必要全部去计算,只需要通过某种方式去采样然后计算即可。
它的目标函数是:对语料库中所有词W求和
词典中的每个词对应一条线段。这些线段组成了[0,1]这个区间。
现在将[0,1]划分成M=10^8等分,每次随机生成[1,M-1]间的整数,看看这些整数落在哪个词对应的部分上。
5 Word2vec -- Skip-Gram 模型
这是 Word2vec的另一个模型(Spark mmlib中提供的方法包就是依赖于这个模型的)
与CBOM不同的地方只有一个。CBOM是通过上下文去求中心词的最大概率。而Skip-Gram是通过中心词去求上下文词的最大概率。
目标函数是:
概率密度有Softmax给出:
因为其他过程与CBOM一致,故再次不赘述了。
Word2Vec存在的问题:
1.对每个local context window单独训练,没有利用包含在global cocurrence矩阵中的统计信息。
2.对多义词无法很好的表示和处理,因为使用了唯一的词向量。
6 GloVe
基于Word2Vec的局部性的缺陷,后来提出了GloVe予以解决。
关于GloVe的详细讲解,后续再附文详说。
从小就错别字多。。改不掉了。。
标签:--,NNLM,矩阵,40000,深度,维度,自然语言,向量 来源: https://blog.51cto.com/15127544/2663185