本文目录一览:

第二篇: 词向量之Spark word2vector实战

word2vector 是google开源的一个生成词向量的工具,以语言模型为优化目标,迭代更新训练文本中的词向量,最终收敛获得词向量。词向量可以作为文本分析中重要的特征,在分类问题、标注问题等场景都有着重要的应用价值。本文总结下了spark word2vector使用过程中遇到的问题,以及给出word2vector使用所需的参数配置,希望能够减少新手在使用过程中遇到的坑,希望有所帮助。

from pyspark.ml.feature import Word2Vec

from pyspark.sql import SQLContext

from pyspark import SparkConf, SparkContext

from pyspark.sql import Row

conf = (SparkConf().set("spark.driver.maxResultSize","2g"))

sc = SparkContext(conf=conf)

sqlContext = SQLContext(sc)

text = sc.textFile("yourfilepath")

documentDF = text.map(lambda x : Row(text=x.split(" "))).toDF()

word2Vec = Word2Vec(vectorSize=200, minCount=5, numPartitions=100,inputCol="text", outputCol="result")

model = word2Vec.fit(documentDF)

vector_model = model.getVectors()

vector_model.saveAsParquetFile("modelpath")

spark-submit

--master yarn-client

--executor-cores 2

--executor-memory 14g

--queue your-queue

--num-executors 100

--driver-memory 10g

--conf spark.ui.port=$RANDOM

--conf spark.shuffle.manager=SORT

--conf spark.shuffle.memoryFraction=0.2

--conf spark.yarn.executor.memoryOverhead=2048

--conf spark.core.connection.ack.wait.timeout=300

--conf spark.akka.frameSize=600 ./word2vector_training.py

One-hot与Word2Vec

one-hot是文本向量化最常用的方法之一。

1.1 one-hot编码

什么是one-hot编码?one-hot编码,又称独热编码、一位有效编码。其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都有它独立的寄存器位,并且在任意时候,其中只有一位有效。举个例子,假设我们有四个样本(行),每个样本有三个特征(列),如图:

上图中我们已经对每个特征进行了普通的数字编码:我们的feature_1有两种可能的取值,比如是男/女,这里男用1表示,女用2表示。那么one-hot编码是怎么搞的呢?我们再拿feature_2来说明:

这里feature_2 有4种取值(状态),我们就用4个状态位来表示这个特征,one-hot编码就是保证每个样本中的单个特征只有1位处于状态1,其他的都是0。

对于2种状态、三种状态、甚至更多状态都是这样表示,所以我们可以得到这些样本特征的新表示:

one-hot编码将每个状态位都看成一个特征。对于前两个样本我们可以得到它的特征向量分别为

1.2 one-hot在提取文本特征上的应用

one hot在特征提取上属于词袋模型(bag of words)。关于如何使用one-hot抽取文本特征向量我们通过以下例子来说明。假设我们的语料库中有三段话:

我爱中国

爸爸妈妈爱我

爸爸妈妈爱中国

我们首先对预料库分离并获取其中所有的词,然后对每个此进行编号:

1 我; 2 爱; 3 爸爸; 4 妈妈;5 中国

然后使用one hot对每段话提取特征向量:

此我们得到了最终的特征向量为

我爱中国  - 1,1,0,0,1

爸爸妈妈爱我-1,1,1,1,0

爸爸妈妈爱中国-0,1,1,1,1

优缺点分析

优点:一是解决了分类器不好处理离散数据的问题,二是在一定程度上也起到了扩充特征的作用(上面样本特征数从3扩展到了9)

缺点:在文本特征表示上有些缺点就非常突出了。首先,它是一个词袋模型,不考虑词与词之间的顺序(文本中词的顺序信息也是很重要的);其次,它假设词与词相互独立(在大多数情况下,词与词是相互影响的);最后,它得到的特征是离散稀疏的。

sklearn实现one hot encode

from sklearn import preprocessing 

enc = preprocessing.OneHotEncoder()  # 创建对象enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]])  # 拟合array = enc.transform([[0,1,3]]).toarray()  # 转化print(array)

1

2

3

4

5

6

word2vec得到词向量

word2vec是如何得到词向量的?这个问题比较大。从头开始讲的话,首先有了文本语料库,你需要对语料库进行预处理,这个处理流程与你的语料库种类以及个人目的有关,比如,如果是英文语料库你可能需要大小写转换检查拼写错误等操作,如果是中文日语语料库你需要增加分词处理。这个过程其他的答案已经梳理过了不再赘述。得到你想要的processed corpus之后,将他们的one-hot向量作为word2vec的输入,通过word2vec训练低维词向量(word embedding)就ok了。不得不说word2vec是个很棒的工具,目前有两种训练模型(CBOW和Skip-gram),两种加速算法(Negative Sample与Hierarchical Softmax)。于是我主要理解word2vec如何将corpus的one-hot向量(模型的输入)转换成低维词向量(模型的中间产物,更具体来说是输入权重矩阵),真真切切感受到向量的变化,不涉及加速算法。

1 Word2Vec两种模型的大致印象

刚才也提到了,Word2Vec包含了两种词训练模型:CBOW模型和Skip-gram模型。

CBOW模型根据中心词W(t)周围的词来预测中心词 

Skip-gram模型则根据中心词W(t)来预测周围词

抛开两个模型的优缺点不说,它们的结构仅仅是输入层和输出层不同。请看:

CBOW模型 

Skip-gram模型

这两张结构图其实是被简化了的,读者只需要对两个模型的区别有个大致的判断和认知就ok了。接下来我们具体分析一下CBOW模型的构造,以及词向量是如何产生的。理解了CBOW模型,Skip-gram模型也就不在话下啦。

2 CBOW模型的理解

其实数学基础及英文好的同学可以参照 斯坦福大学Deep Learning for NLP课堂笔记 。

当然,懒省事儿的童鞋们就跟随我的脚步慢慢来吧。

先来看着这个结构图,用自然语言描述一下CBOW模型的流程:

CBOW模型结构图

(花括号内{}为解释内容.)

输入层:上下文单词的onehot. {假设单词向量空间dim为V,上下文单词个数为C}

所有onehot分别乘以共享的输入权重矩阵W. {V*N矩阵,N为自己设定的数,初始化权重矩阵W}

所得的向量 {因为是onehot所以为向量} 相加求平均作为隐层向量, size为1*N.

乘以输出权重矩阵W’ {N*V}

得到向量 {1*V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维斗代表着一个单词},概率最大的index所指示的单词为预测出的中间词(target word)

与true label的onehot做比较,误差越小越好

所以,需要定义loss function(一般为交叉熵代价函数),采用梯度下降算法更新W和W’。训练完毕后,输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),这个矩阵(所有单词的word embedding)也叫做look up table(其实聪明的你已经看出来了,其实这个look up table就是矩阵W自身),也就是说,任何一个单词的onehot乘以这个矩阵都将得到自己的词向量。有了look up table就可以免去训练过程直接查表得到单词的词向量了。

这回就能解释题主的疑问了!如果还是觉得我木有说明白,别着急!跟我来随着栗子走一趟CBOW模型的流程!

3 CBOW模型流程举例

假设我们现在的Corpus是这一个简单的只有四个单词的document: 

{I drink coffee everyday} 

我们选coffee作为中心词,window size设为2 

也就是说,我们要根据单词”I”,”drink”和”everyday”来预测一个单词,并且我们希望这个单词是coffee。

假设我们此时得到的概率分布已经达到了设定的迭代次数,那么现在我们训练出来的look up table应该为矩阵W。即,任何一个单词的one-hot表示乘以这个矩阵都将得到自己的word embedding。

在我的新闻分类中由于使用的是自带的60000多词训练出的embedding层而有9000多个词并不在里面所以效果没有达到最佳,值得改进

word2vec模型之Skip-Gram Model

  本文介绍一种基于神经网络结构的Word2Vec模型,Word2Vec是目前NLP领域的基础知识,这里仅对Word2Vec模型中的Skip-Gram模型进行详细介绍。

  Skip-Gram神经网络模型是一种非常简单的神经网络结构,是一个仅有一个Hidden Layer的神经网络结构。Skip-Gram模型的训练过程可以视作一个“Fake Task(伪任务)”,为何称之为“Fake Task”?是因为训练该模型的目的并不是将训练好的模型用于任何的分类任务,而是为了学习得到隐层的权重矩阵,而通过这些矩阵我们会得到想要的单词的特征向量,总体框架入下图所示。下面详细介绍这个Skip-Gram模型的训练过程。

  给定一个特定的word作为输入,我们从该word的附近随机挑选一个word,该网络模型会告诉我们词汇表中的每个单词出现在“附近”的概率。这里的“附近”指的是在特定window size范围内。输出概率与在输入词附近找到每个单词的可能性有关。这里,我们使用文本中指定window size内的word pair(inputword,outputword)来训练神经网络模型。word pairs的获取方式如下图所示。

  这里详细介绍一下Skip-Gram模型的训练过程。首先,神经网络模型只接受数值型的输入,故不能直接将每个单词直接输入到一个神经网络中,故而需要一种针对神经网络模型的单词表示方式,为此需要针对训练集中的所有不同的单词构建一个词汇表(vocabulary),然后将词汇表中的每个单词以 One-Hot编码 的方式进行表示。比如,现在有一个大小为10000的词汇表,我们需要为每个单词构建一个One-Hot向量,要求每个单词对应的当前单词的位置为1,其他所有位置为0,因此我们会得到10000个长度为10000的向量,其中每个向量都只有一个位置为1。神经网络的输出是一个10000维的向量,表示针对输入单词,词汇表中所有的单词出现在输入单词附近的预测概率。如下图所示:

  上述的神经网络结构隐层中的神经元没有激活函数,但输出层的每个神经元使用了softmax函数。训练的过程使用word pair(inputword,outputword),输入是一个One-Hot的向量,输出的也是一个表示输出单词的One-Hot的向量。但是当在一个输入词在训练好的网络上计算时,输出的向量实际上是一个概率分布,并不是一个One-Hot向量。因为每个输出的单元使用了 Softmax ,且没有激活函数。

  同样的针对上述问题,有10000个单词,假设需要为每个单词学习一个300维的向量,那么隐层可以由一个10000*300的矩阵来表示(300个神经元,每个神经元都有一个10000维的权重向量),如下图所示。

  竖着看这个隐层的权重矩阵,每一列对应一个神经元中的参数向量,而如果横着看这个权重矩阵,每一行就是一个300维的向量,而这这就是我们需要通过学习得来的词向量!也就是说,10000个单词的向量表示就是这个10000*300的矩阵,每行对应一个单词的向量表示。那么Skip-Gram最终的目的就是学习这个隐层的权重矩阵。而为什么针对词汇表里的单词要进行One-Hot编码,这里解释一下。如下图所示,如果我们用一个One-Hot向量乘以这个权重矩阵,那么得出的向量结果就是对应单词的特征表示。这意味着这个模型的隐层实际上只是作为一个查找表,而隐层的输出则是输入的单词的“词向量(word vector)”。

  输出层为softmax回归分类器,每个输出神经元(词汇表中的每个单词都有一个对应的输出神经元)将产生0到1之间的输出,所有这些输出值的总和将等于1。具体来说,每个输出神经元都有一个权重向量,它将权重向量与隐层中的向量相乘,然后将指数函数应用于结果。最后,为了使输出之和达到1,我们将这个结果除以来自所有10,000个输出节点的结果之和。如下图所示:

  如果两个不同的单词有非常相似的“上下文”(也就是说,它们周围可能出现什么单词),那么该模型应当为这两个单词输出非常相似的结果。网络输出这两个单词相似上下文预测的一种表达形式就是这两个单词的单词向量相似。换言之,如果两个单词有相似的上下文,那么该网络就有能力为这两个单词出学习相似的单词向量!

  以上部分介绍了Skip-Gram模型的具体实现思路,接下来会针对Skip-Gram在实际训练中的一些问题进行优化。通过分析上述的Skip-Gram神经网络模型,可以发现一个问题,由于需要为每个单词学习一个固定长度的向量表示,因此以上面的例子为例,当需要训练10000个单词的300维的向量表示时,我们需要计算出300万个权重值。而在更大的数据集上,这样的训练过程是十分缓慢的,基本上不可行,因此Skip-Gram的作者针对这个问题提出了几种解决方案。常用的方案有Subsampling frequent words和Negative Sampling,接下来会详细介绍这两种解决方案。

  Subsampling主要目的是通过削减训练集的训练样本数来降低训练代价。由于在文本中,许多单词出现的频率很高,这就导致了这个单词对应的word pair (inputword,outputword)在训练集中的数量会非常多,因此需要针对这些高频词进行二次采样以降低这些高频词在训练集中的规模。具体采样策略如下:

假设 w i 表示词汇表中的第 i 个单词, z(w i ) 表示该词在语料库中出现的频率。例如一个单词 w i 在大小为10000的语料库中出现的次数为100,那么 z(w i ) =0.01。知道了每个单词在语料库中的出现频率之后,那么对于每个单词 w i 的subsampling采样率如下:

该函数有一些有趣的点:

  Subsampling虽然能明显地缩小训练神经网络模型时的训练集大小,但是并不能从根本上解决隐层矩阵规模大而带来的计算问题。也就是说,对于训练集中的每个样本,每次训练都需要更新隐层中的所有参数,因此Skip-Gram模型的作者又提出了另外一种方式来优化计算问题。

  由于训练神经网络模型为了达到更高的精度,需要通过训练样本中每次细微地调整每个神经元的权重参数,因此每个训练每个训练样本都会微调神经网络中的所有参数。由于SubSampling在极限情况下,对训练集的削减程度不会低于原规模的3.3%,然而 ,这种程度的削减对于一个字典特别大的训练场景的影响是微弱的。为此作者又提出了一种Negative Sampling的方式。

Negative Sampling通过让每个训练样本只修改一小部分权重(而不是网络中的全部权重)来解决计算量特别大的问题。接下来可以看一下Negative Sampling的工作原理。

  正常情况下,我们对每个单词语料训练神经网络模型,模型的输出是一个one-hot的向量。在Negative Sampling时,我们随机选择若干个(假设5个)negative word去更新对应的权重,(这里Negative word 对应的时One-Hot向量中值为0的单词,而我们的目标单词可以理解为Positive word,即对应One-Hot向量中值为1的单词)。

  回想一下,我们的模型输出层有个300×10000的权重矩阵,如果每个训练样本只更新5个negative word和当前的positive word对应的权重,那么每次训练对应输出层只需要更新6*300个权重,此时更新比例只有6/10000=0.06%。

  上面提到了,针对不同的数据集,Negative Sampling会选择2-20个negative word,下面介绍一下如何挑选这个Negative word。首先针对一个语料库,每次Negative Sampling挑选出的样本的可能性取决于该样本在语料库中出现的频数。

  其中 f ( w i )表示单词 w i 在语料库中出现的频数。作者在他们的论文中指出,他们尝试了这个公式的一些变体,其中表现最好的是将每个单词出现的频数提高到3/4次方。如下所示:

  处理一些样本之后会发现,与简单的公式相比,这个公式有增加不太频繁单词的概率和减少更频繁单词的概率的趋势。以上就是对Negative Sampling的一些简单描述。

  Word Pairs and “Phrases”的主要思想是将经常成对出现或者某个短语当成一个Word,以此来降低整个训练过程中的计算复杂度。该方法在自然语言处理中有很大的应用场景。

参考:

1.

2.

Word2vec原理详细解读

Softmax函数:

哈夫曼树(Huffman Tree)

     从图1可以看出Skip-gram就是用当前中心词 (banking)预测附近的词,图1中将窗口大小设为2,即需要预测左边的2个词和右边的2个词。

     对于每个位置 ,预测窗口大小为 的上下文,设当前中心词为 ,那么目标为最大化:

                                                                               (1)

其中 为模型的参数。

     为了将最大化转为最小化,可对 取负数,为了简化计算,可取对数:

                               (2)  

      现在问题的关键是如何计算 ,我们使用两个向量表示: 为中心词的表示, 为上下文词的表示。那么,计算中心词 c 和上下文词 o 的出现概率为:

                                                                                       (3)

其中,V为整个词表大小, 为中心词向量表示。其实式3就是softmax函数。

      图2展示了Skip-gram的计算过程,从图中可以看出Skip-gram预测的是 , , ,由于只预测前后两个单词,因此窗口大小为2。

输入层到隐藏层 :输入层的中心词 用one-hot向量表示(维度为V*1,V为整个词表大小),输入层到隐藏层的权重矩阵为中心词矩阵W(维度为V*d,d为词向量维度),设隐含向量为 (维度为d*1),那么:

                                                                                                             (4)

隐藏层到输出层: 隐藏层到输出层的上下文权重矩阵为U(维度为d*V),输出层为y(维度为V*1),那么:

                                                                                          (5)

注意 ,输出层的向量 y 与输出层的向量 虽然维度一样,但是 y 并不是one-hot向量,并且向量 y 的每一个元素都是有意义的。如,假设训练样本只有一句话”I like to eat apple”,此时我们正在使用eat去预测to,输出层结果如图3所示。

     向量y中的每个元素表示用 I、like、eat、apple 四个词预测出来的词是对应的词的概率,比如是like的概率为0.05,是to的概率是0.80。由于我们想让模型预测出来的词是to,那么我们就要尽量让to的概率尽可能的大,所以我们将式子(1)作为最大化函数。

Continuous Bag-of-Words(CBOW),的计算示意图如图4所示。从图中可以看出,CBOW模型预测的是 ,由于目标词 只取前后的两个词,因此窗口大小为2。假设目标词 前后各取 个词,即窗口大小为 ,那么CBOW模型为:

                         (6)

输入层到隐藏层: 如图4所示,输入层为4个词的one-hot向量表示,分别为 , , , (维度都为V*1,V为整个词表大小),记输入层到隐藏层的上下文词的权重矩阵为W(维度为V*d,d是词向量维度),隐藏层的向量h(维度为d*1),那么:

                                          (7)

这里就是把各个上下文词的向量查找出来,再进行简单的加和平均。

隐藏层到输出层: 记隐藏层到输出层的中心词权重矩阵为U(维度d*V),输出层的向量y(维度V*1),那么:

                                                                                                    (8)

注意 ,输出层的向量 与输入层的 虽然维度一样,但是 并不是one-hot向量,并且向量 的每个元素都是有意义的。CBOW的目标是最大化函数:

     (9)

由于softmax的分母部分计算代价很大,在实际应用时,一般采用层次softmax或者负采样替换掉输出层,降低计算复杂度。

层次softmax(Hierarchical Softmax)是一棵哈夫曼树,树的叶子节点是训练文本中所有的词,非叶子节点是一个逻辑回归二分类器,每个逻辑回归分类器的参数都不同,分别用 表示,假定分类器的输入为向量h,记逻辑回归分类器输出的结果为 将向量h传递给节点的左孩子概率为 ,否则传递给节点的右孩子概率为 。重复这个传递流程直到叶子节点。

从图5和图6可以看出,我们就是将隐藏层的向量h直接传递到了层次softmax,层次softmax的复杂度为O(log(V)),层次softmax采样到每个词的概率如下:

对于CBOW或者skip-gram模型,如果要预测的词是to,那么我们就让 尽量大,所以我们将任务转换成训练V-1个逻辑分类器。CBOW模型和skip-gram模型训练目标函数和之前形式一样,为:

                                                             (10)

  (11)

负采样实际上是采样负例来帮助训练的手段,其目的与层次softmax一样,是用来提升模型的训练速度。我们知道,模型对正例的预测概率是越大越好,模型对负例的预测概率是越小越好。负采样的思路就是根据某种负采样的策略随机挑选一些负例,然后保证挑选的这部分负例的预测概率尽可能小。所以,负采样策略是对模型的效果影响很大,word2vec常用的负采样策略有均匀负采样、按词频率采样等等。

以“I like to eat apple”为例子,假设窗口的大小是2,当中心词为like时,即我们会用 I to 来预测like,所以在这里我们就认为(I,like)和(to,like)都是正例,而(I,apple)、(to,apple)就是负例,因为(I,apple)、(to,apple)不出现在当前正例中。用NEG(w)表示负样本,有:

                                                                   (12)

                (13)

这里的 是词*的中心词向量表示,h为隐藏层的输出向量。我们只需要最大化目标函数:

                      (14)

这个损失函数的含义就是让正例概率更大,负例的概率更小。

以“I like to eat apple”为例子,假设窗口的大小是1,即我们会用 like 来预测 I to,所以在这里我们就认为(like,I)和(like,to)都是正例,而(like,apple)就是负例,因为(like,apple)不会出现在正例中。那么,对于给定的正样本(w,context(w))和采样出的负样本(w,NEG(w)),有:

                                                                                  (15)

                                                        (16)

这里的 是词*的中心词向量表示,h为隐藏层的输出向量。我们只需要最大化目标函数:

                                         (17)

word2vec常用的负采样策略有均匀负采样、按词频率采样等等。比较常用的采样方法是一元分布模型的3/4次幂。该方法中,一个词被采样的概率,取决于这个词在语料中的词频 ,其满足一元分布模型(Unigram Model).

                                                                                         (18) 

其中V为整个词表大小,    为词 的词频。

至于为什么选择3/4呢?其实是由论文作者的经验所决定的。

假设由三个词,,”我“,”和平“,”觊觎“ 权重分别为 0.9 ,0.01,0.003;经过3/4幂后:

我: 0.9^3/4 = 0.92

和平:0.01^3/4 = 0.03

觊觎:0.003^3/4 = 0.012

对于”觊觎“而言,权重增加了4倍;”和平“增加3倍;”我“只有轻微增加。

可以认为:在保证高频词容易被抽到的大方向下,通过权重3/4次幂的方式, 适当提升低频词、罕见词被抽到的概率 。如果不这么做,低频词,罕见词很难被抽到,以至于不被更新到对应的Embedding。

QuestionAnswer

Question1:  如图7中,skip-gram模型中,从隐藏层到输出层,因为使用权值共享,所以会导致输出的几个上下文词向量总是完全一样,但网络的目的是要去预测上下文会出现的词,而实际中给定中心词的情况下上下文的词会五花八门。怎么解释skip gram的这种输出形式?

Answer1: 网络的目的不是要预测上下文会出现啥词,这只是一个fake task。实际上这个loss就是降不下来的,所以本来就不能用于真正预测上下文,而初衷也不是用于预测上下文,只是利用上下文信息去实现嵌入。

       如果你的100W个句子都是”I really love machine learning and deep learning“,加上权值共享,结果就是给定machine以后,它输出really,love,learning,and这四个词的概率完全相同,这就意味着这四个词的词向量也是差不多的。正因为这样,语义相近的词,他们在空间上的映射才会接近。

Question2 : Word2Vec哪个矩阵是词向量?

Answer2: 如图7所示,中心词矩阵W,上下文矩阵W' 可以任意选一个作为词向量矩阵。但是,如果采用优化后(层次softmax)的模型,那么将不存在W',这种情况下只能选矩阵W。

三千多字,码字不易,如果大家发现我有地方写得不对或者有疑问的,麻烦评论, 我会回复并改正 。对于重要问题,我会持续更新至 QuestionAnswer。

参考:

[1] skip-gram的关键术语与详细解释

[2] 一篇浅显易懂的word2vec原理讲解

[3] CS224n:深度学习的自然语言处理(2017年冬季)1080p

[4] Stanford  CS224N: NLP with Deep Learning | Winter 2019 | Lecture 2 – Word Vectors and

Word Senses

[5] 关于skip gram的输出?

[6] Le, Quoc V , and T. Mikolov . "Distributed Representationsof Sentences and Documents." (2014).

[7] Mikolov, T. . "Distributed Representations of Words andPhrases and their Compositionality." Advances in Neural InformationProcessing Systems 26(2013):3111-3119.

[8] Mikolov, Tomas , et al."Efficient Estimation of Word Representations in Vector Space." Computerence (2013).

[9] Goldberg, Yoav , and O. Levy . "word2vec Explained:deriving Mikolov et al.'s negative-sampling word-embedding method." arXiv(2014).

word2vec负采样中softmax的应用

word2vec可以说是整个embedding理论的基础,几乎所有的embedding方法,最终都会把序列用skip-gram或者是CBOW训练一把得到embedding。

word2vec的原理并不复杂,精妙的思想在于如何减少输出层softmax的计算量,相关的基础文章王喆大神都列出来了,最近在阅读,经常会有一些让人眼前一亮的点,做一个简单的记录。

word2vec理论提出的文章中,Mikolov et al,写得并不是很好懂,好在有几篇explained,比如这篇: word2vec Explained: Deriving Mikolov et al.’s Negative-Sampling Word-Embedding Method ,另外一篇更详细一些,JinRong教授写的。

在计算输出矩阵时,激活函数是这样的:

(1)

进一步可以写成对数形式:

(2)

这里就有一个很尴尬的问题,当 ,也就是我们的字典(vocabulary)的size很大的时候,这个softmax算的就会非常慢。

解决这个问题官方是有两种方案,1)层次softmax;2)负采样。

关于这两种方法刘建平大神以及其他各种ml博主都有写,我也写不了他们那么好,就不用多说了。但是为了说下面的东西,简单说一说负采样。

其实负采样一言以蔽之,就是把公式(1)中分母的 干掉。引入了这样的思想:只考察两个词 和 ,怎么能描述他们的关系呢?还是用上面的余弦距离。当我们认为 的embedding,也就是 是直接从输入矩阵中拿到的,这时候要学习的就是 的表示 ,这时候论文中直接给出了一个softmax的表达:

(3)

光从这个公式上理解,还是可以接受的,当两个embedding接近的时候,余弦距离大, ,反之

这里就有两个问题,感觉如果搞清楚这两点,负采样基本上就捋顺了:

回答了这两个问题,其实接下去的事情就比较简单,或者说通畅。我们直接把公式(3)的softmax激活写成一个通用的激活形式 ,最后的损失函数就可以写成:

题外话可以说说softmax和lr的关系,设想这样的一个简单的逻辑回归问题,用线性函数拟合对数几率的废话不多说,公式如下:

(4)

但是当我们把它当成是一个多分类问题的时候,写成softmax的样子,可以有:

把下面的公式稍微变化一下就写成:

也就是说,当softmax是一个二分类问题的时候,其实没有必要训练两组参数,本质上就是一个逻辑回归问题,优化过程中,我们只关注 而不是这两组参数分别是多少。事实上,我们确实也无法求出他们准确的值来,或者说他们可以任意的数,因为在求偏导的时候 恒成立,迭代中只会优化它俩的差值。