下面对文本表示方法进行梳理,一般称为词嵌入(Word Embedding)方法。词嵌入这个说法其实很形象,我们的做法就是把文本中的词嵌入到文本空间中,用一个向量来表示它。
离散表示 One-hot One-hot表示很容易理解。在一个语料库中,给每个字/词编码一个索引,根据索引进行one-hot表示。
John likes to watch movies. Mary likes too. John also likes to watch football games. 如果只需要表示出上面两句话中的单词,可以只对其中出现过的单词进行索引编码:
{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also":6, "football": 7, "games": 8, "Mary": 9, "too": 10} 其中的每个单词都可以用one-hot方法表示:
John: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] likes: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0] ... 当语料库非常大时,需要建立一个很大的字典对所有单词进行索引编码。比如100W个单词,每个单词就需要表示成100W维的向量,而且这个向量是很稀疏的,只有一个地方为1其他全为0。还有很重要的一点,这种表示方法无法表达单词与单词之间的相似程度,如beautiful和pretty可以表达相似的意思但是ont-hot法无法将之表示出来。
Bag of Words 词袋表示,也称为计数向量表示(Count Vectors)。文档的向量表示可以直接用单词的向量进行求和得到。
John likes to watch movies. Mary likes too. -->> [1, 2, 1, 1, 1, 0, 0, 0, 1, 1] John also likes to watch football games. -->> [1, 1, 1, 1, 0, 1, 1, 1, 0, 0] 横向来看我们把每条文本表示成了一个向量,纵向来看,不同文档中单词的个数又可以构成某个单词的词向量。如上文中的"John"纵向表示成[1,1]。
其具体实现可以采用sklearn中的CountVectorizer。
count_vect = CountVectorizer(analyzer='word') count_vect.fit(trainDF['text']) #假定已经读进来了DataFrame,'text'列为文本列, #每行为一条文本。此句代码基于所有语料库生成单词的词典。 xtrain_count = count_vect.transform(train_x) Bi-gram和N-gram 与词袋模型原理类似,Bi-gram将相邻两个单词编上索引,N-gram将相邻N个单词编上索引。
为 Bi-gram建立索引:
{"John likes”: 1, "likes to”: 2, "to watch”: 3, "watch movies”: 4, "Mary likes”: 5, "likes too”: 6, "John also”: 7, "also likes”: 8, "watch football": 9, "football games": 10} 这样,原来的两句话就可以表示为:
John likes to watch movies. Mary likes too. -->> [1, 1, 1, 1, 1, 1, 0, 0, 0, 0] John also likes to watch football games. -->> [0, 1, 1, 0, 0, 0, 1, 1, 1, 1] 这种做法的优点是考虑了词的顺序,但是缺点也很明显,就是造成了词向量的急剧膨胀。
TF-IDF 上面的词袋模型和Bi-gram、N-gram模型是基于计数得到的,而TF-IDF则是基于频率统计得到的。TF-IDF的分数代表了词语在当前文档和整个语料库中的相对重要性。TF-IDF 分数由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。其中计算语料库中文档总数除以含有该词语的文档数量,然后再取对数就是逆文档频率。
TF(t)= 该词语在当前文档出现的次数 / 当前文档中词语的总数 IDF(t)= log_e(文档总数 / 出现该词语的文档总数) 根据公式可以看出,TF 判断的是该字/词语是否是当前文档的重要词语,但是如果只用词语出现频率来判断其是否重要可能会出现一个问题,就是有些通用词可能也会出现很多次,如:a、the、at、in等。当然我们对文本进行预处理的时候一般会去掉这些所谓的stopwords,即停用词,但仍然会有很多通用词无法避免地出现在很多文档,而其实它们不是那么重要。
逆文档频率(IDF)用于判断是否在很多文档中都出现了此词语,即很多文档或所有文档中都出现的就是通用词。出现该词语的文档越多,IDF越小,其作用是抑制通用词的重要性。
将上述求出的 TF 和 IDF 相乘记得到词语在当前文档和整个语料库中的相对重要性。TF-IDF与一个词在当前文档中的出现次数成正比,与该词在整个语料库中的出现次数成反比
TF-IDF算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。
可以使用sklearn中的TfidfVectorizer生成TF-IDF特征。
word level tf-idf
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000) tfidf_vect.fit(trainDF['text']) xtrain_tfidf = tfidf_vect.transform(train_x)
ngram level tf-idf
tfidf_vect_ngram = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', ngram_range=(2,3), max_features=5000) tfidf_vect_ngram.fit(trainDF['text']) xtrain_tfidf = tfidf_vect.transform(train_x) 共现矩阵 (Cocurrence matrix) 首先解释下“共现”,即共同出现,如一句话中共同出现,或一篇文章中共同出现。这里给共同出现的距离一个规范——窗口,如果窗口宽度是2,那就是在当前词的前后各2个词的范围内共同出现。可以想象,其实是一个总长为5的窗口依次扫过所有文本,同时出现在其中的词就说它们共现。
John likes to watch movies. John likes to play basketball. 上面两句话设窗口宽度为1,则共现矩阵如下:
可以看到,当前词与自身不存在共现,共现矩阵实际上是对角矩阵。
实际应用中,我们用共现矩阵的一行(列)作为某个词的词向量,其向量维度还是会随着字典大小呈线性增长,而且存储共生矩阵可能需要消耗巨大的内存。一般配合PCA或SVD将其进行降维,如将原来 m×n 的矩阵降为 m×r的矩阵,其中 r<n,即将词向量的长度进行缩减。
下面是奇异值分解的步骤。
分布式表示 离散表示虽然能够进行词语或者文本的向量表示,进而用模型进行情感分析或是文本分类之类的任务,但其不能表示词语间的相似程度或者词语间的类比关系。比如前面提到的beautiful和pretty,它们表达相近的意思,所以我们希望它们在整个文本的表示空间内挨得很近。一般认为词向量/文本向量之间的夹角越小,两个词相似度越高。
离散表示如one-hot表示法无法表示上面的关系,引入分布式表示方法,其主要思想是用周围的词表示该词。
NNLM(Neural Network Language model) 2003年提出了A Neural Probabilistic Language Model,其用前n-1个词预测第n个词的概率,并用神经网络搭建模型。
目标函数:
使用非对称的前向窗口,长度为n-1,滑动窗口遍历整个语料库求和,使得目标概率最大化,其计算量正比于语料库大小。同时,预测所有词的概率总和应为1。
下面是NNLM的网络结构:
样本的一组输入是第n个词的前n-1个词的one-hot表示,目标是预测第n个词,输出层的大小是语料库中所有词的数量,然后sotfmax回归,使用反向传播不断修正神经网络的权重来最大化第n个词的概率。当神经网络学得到权重能够很好地预测第n个词的时候,输入层到映射层,即 这层,其中的权重Matrix C 被称为投影矩阵,输入层各个词的ont-hot表示法只在其对应的索引位置为1,其他全为0,在与Matrix C 矩阵相乘时相当于在对应列取出列向量投影到映射层。
此时的向量就是原词的分布式表示,其是稠密向量而非原来one-hot的稀疏向量了。
在后面的隐藏层将这n-1个稠密的词向量进行拼接,如果每个词向量的维度为D,则隐藏层的神经元个数为 (n-1)×D,然后接一个所有待预测词数量的全连接层,最后用softmax进行预测。
可以看到,在隐藏层和分类层中间的计算量应该是很大的,word2vec算法从这个角度出发对模型进行了简化。word2vec不是单一的算法,而是两种算法的结合:连续词袋模型(CBOW)和跳字模型(Skip-gram)。
CBOW 先来看下论文中给出的CBOW和Skip-gram模型的原理示意:
截自word2vec论文
连续词袋模型在NNLM基础上有以下几点创新:
取消了隐藏层,减少了计算量 采用上下文划窗而不只是前文划窗,即用上下文的词来预测当前词 投影层不再使用各向量拼接的方式,而是简单的求和平均 其目标函数为:
可以看到,上面提到的取消隐藏层,投影层求和平均都可以一定程度上减少计算量,但输出层的数量在那里,比如语料库有500W个词那么隐藏层就要对500W个神经元进行全连接计算,这依然需要庞大的计算量。word2vec算法又在这里进行了训练优化。
www.analyticsvidhya.com/blog/2017/0…
层级softmax
先来了解下霍夫曼树。霍夫曼树是一棵特殊的二叉树,了解霍夫曼树之前先给出几个定义:
路径长度:在二叉树路径上的分支数目,其等于路径上结点数-1 结点的权:给树的每个结点赋予一个非负的值 结点的带权路径长度:根结点到该结点之间的路径长度与该节点权的乘积 树的带权路径长度:所有叶子节点的带权路径长度之和 霍夫曼树的定义为:在权为 的 个叶子结点所构成的所有二叉树中,带权路径长度最小的二叉树称为最优二叉树或霍夫曼树。
可以看出,结点的权越小,其离树的根结点越远。
word2vec算法利用霍夫曼树,将平铺型softmax压缩成层级softmax,不再使用全连接。具体做法是根据文本的词频统计,将词频赋给结点的权。
在霍夫曼树中,叶子结点是待预测的所有词,在每个子结点处,用sigmoid激活后得到往左走的概率p,往右走的概率为1-p。最终训练的目标是最大化叶子结点处预测词的概率。
层级softmax的实现有点复杂,暂时先搞清楚大致原理~
负例采样 Negative Sampling 负例采样的想法比较简单,假如有m个待预测的词,每次预测一个正样本词,其他的m-1个词均为负样本。一方面正负样本数差别太大,另一方面负样本中可能有很多不常用或者的词预测时概率基本为0,我们不想在计算它们的概率上面消耗资源。
比如现在待预测词有100W个,正常情况下我们分类的全连接层需要100W个神经元,我们可以根据词语的出现频率进行负例采样,一个正样本加上采样出的比如说999个负样本,组成1000个新的分类全连接层。
采样尽量保持了跟原样本一样的分布,具体做法是将[0,1]区间均分108份,然后根据词出现在语料库中的次数赋予每个词不同的份额。
然后在[0,1]区间掷骰子,落在哪个区间内就采样哪个样本。实际上,最终效果证明上式中取counter(w)的3/4次方效果最好,所以在应用中也是这么做的。
Skip-gram skip-gram模型与CBOW模型相反,它是用当前词来预测上下文的词。也是用当前词的one-hot向量经过投影矩阵得到其稠密表示,然后预测其周围词的one-hot向量,即网络的输出有多个,但是投影层到分类层的权重。具体实现时,(暂时想法)搭好一个输出的网络之后,如果要预测周围的4个词,可以将y的one-hot表示分别作为输出,进行四次网络的正向传播,然后使其loss之和最小。
www.analyticsvidhya.com/blog/2017/0…
fasttext fasttext的模型与CBOW类似,实际上,fasttext的确是由CBOW演变而来的。CBOW预测上下文的中间词,fasttext预测文本标签。与word2vec算法的衍生物相同,稠密词向量也是在训练神经网络的过程中得到的。
截自fasttext论文
fasttext的输入是一段词的序列,即一篇文章或一句话,输出是这段词序列属于某个类别的概率,所以fasttext是用来做文本分类任务的(暂时了解来看是这样~~)。
fasttext中采用层级softmax做分类,这与CBOW相同。fasttext算法中还考虑了词的顺序问题,即采用N-gram,与之前介绍离散表示时的做法相同。如:今天天气非常不错,Bi-gram的表示就是:今天、天天、天气、气非、非常、常不、不错。
fasttext做文本分类对文本的存储方式有要求:
__label__1, It is a nice day. __label__2, I am fine,thank you. __label__3, I like play football. 其中的__label__为实际类别的前缀,也可以自己定义。
fasttext有python实现:github.com/salestock/f…
classifier = fasttext.supervised(input_file, output, label_prefix='label') result = classifier.test(test_file) print(result.precision,result.recall) 其中,input_file是已经按上面的格式要求做好的训练集txt,output后缀为.model,是我们保存的二进制文件,label_prefix可以自定义我们的类别前缀。当然还有其他参数,这里不一一介绍了。
# 更多面试题可以关注星空智能对话机器人的Gavin的公开课
## 以往公开课选段视频如下:
GavinNLP星空对话机器人Transformer课程片段2--数学内幕、注意力机制代码实现、及Transformer可视化
星空智能对话机器人的Gavin认为Transformer是拥抱数据不确定性的艺术。
Transformer的架构、训练及推理等都是在Bayesian神经网络不确定性数学思维下来完成的。Encoder-Decoder架构、Multi-head注意力机制、Dropout和残差网络等都是Bayesian神经网络的具体实现;基于Transformer各种模型变种及实践也都是基于Bayesian思想指导下来应对数据的不确定性;混合使用各种类型的Embeddings来提供更好Prior信息其实是应用Bayesian思想来集成处理信息表达的不确定性、各种现代NLP比赛中高分的作品也大多是通过集成RoBERTa、GPT、ELECTRA、XLNET等Transformer模型等来尽力从最大程度来对抗模型信息表示和推理的不确定性。
从数学原理的角度来说,传统Machine Learning及Deep learning算法训练的目标函数一般是基于Naive Bayes数学原理下的最大似然估计MLE和最大后验概率MAP来实现,其核心是寻找出最佳的模型参数;而Bayesian的核心是通过计算后验概率Posterior的predictive distribution,其通过提供模型的不确定来更好的表达信息及应对不确定性。对于Bayesian架构而言,多视角的先验概率Prior知识是基础,在只有小数据甚至没有数据的时候是主要依赖模型Prior概率分布(例如经典的高斯分布)来进行模型推理,随着数据的增加,多个模型会不断更新每个模型的参数来更加趋近真实数据的模型概率分布;与此同时,由于(理论上)集成所有的模型参数来进行Inference,所以Bayesian神经网络能够基于概率对结果的提供基于置信度Confidence的分布区间,从而在各种推理任务中更好的掌握数据的不确定性。
当然,由于Bayesian模型因为昂贵的CPU、Memory及Network的使用,在实际工程实践中计算Bayesian神经网络中所有概率模型分布P(B)是棘手的甚至是Intractable的几乎不能实现事情,所以在工程落地的时候会采用Sampling技术例如MCMC的Collapsed Gibbs Sampling、Metropolis Hastings、Rejection Sampling及Variational Inference的Mean Field及Stochastic等方法来降低训练和推理的成本。Transformer落地Bayesian思想的时候权衡多种因素而实现最大程度的近似估计Approximation,例如起使用了计算上相对CNN、RNN等具有更高CPU和内存使用性价比的Multi-head self-attention机制来完成更多视角信息集成的表达,在Decoder端训练时候一般也会使用多维度的Prior信息完成更快的训练速度及更高质量的模型训练,在正常的工程落地中Transformer一般也会集成不同来源的Embeddings,例如星空智能对话机器人的Transformer实现中就把One-hot encoding、Word2vec、fastText、GRU、BERT等encoding集成来更多层级和更多视角的表达信息。
拥抱数据不确定性的Transformer基于Bayesian下共轭先验分布conjugate prior distribution等特性形成了能够整合各种Prior知识及多元化进行信息表达、及廉价训练和推理的理想架构。理论上讲Transformer能够更好的处理一切以 “set of units” 存在的数据,而计算机视觉、语音、自然语言处理等属于这种类型的数据,所以理论上讲Transformer会在接下来数十年对这些领域形成主导性的统治力。
基于此,我们开发了全新一代围绕Transformer的自然语言处理课程:
NLP on Transformers 101
(基于Transformer的NLP智能对话机器人实战课程)
本课程以Transformer架构为基石、萃取NLP中最具有使用价值的内容、围绕手动实现工业级智能业务对话机器人所需要的全生命周期知识点展开,学习完成后不仅能够从算法、源码、实战等方面融汇贯通NLP领域NLU、NLI、NLG等所有核心环节,同时会具备独自开发业界领先智能业务对话机器人的知识体系、工具方法、及参考源码,成为具备NLP硬实力的业界Top 1%人才。
课程特色:
101章围绕Transformer而诞生的NLP实用课程 5137个围绕Transformers的NLP细分知识点 大小近1200个代码案例落地所有课程内容 10000+行纯手工实现工业级智能业务对话机器人 在具体架构场景和项目案例中习得AI相关数学知识 以贝叶斯深度学习下Attention机制为基石架构整个课程 五大NLP大赛全生命周期讲解并包含比赛的完整代码实现