fastText
英语单词通常有其内部结构和形成方式。如"dog"“dogs”“dogcatcher”,这些词都有同一个词根dog,但使用不同的后缀来改变词的含义。且此关联可以推广至其他词汇。
在word2vec中并没有利用到构词学中的信息。无论是在跳字模型还是连续词袋模型中,都将形态不同的单词用不同的向量表示且模型中,如"dog""dogs"分别用两个不同的向量表示,而模型中并未直接表达这两个向量之间的关系。鉴于此,fastText提出了子词嵌入(subword embedding)的方法,从而试图将构词信息引入word2vec中的CBOW。一般情况下,使用fastText进行文本分类的同时也会产生词的embedding,即embedding是fastText分类的产物。
n-gram表示单词
word2vec把语料库中的每个单词当成原子的,他会为每个单词生成一个向量。这忽略了单词内部的形态特征,如"book",“books”,“阿里巴巴”,“阿里”。这两个例子中,两个单词都有较多公共字符,即它们的内部形态类似,但是传统的word2vec中,这种单词内部形态信息因为它们被转换成不同的id丢失了。
为解决此问题,fastText使用了字符级的n-grams来表示一个单词,对于单词book,假设n的取值为3,则它的trigram有:
“<bo”, “boo”, “ook”, “ok>”
其中<表示前缀,>表示后缀。于是可以使用trigram来表示"book"这个词,进一步,我们可以用这4个trigram的向量叠加来表示"apple"的词向量。
带来两点好处:
- 对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
- 对于训练词库之外的单词,仍可以构建它们的词向量。我们可以叠加它们字符级n-gram向量。
fastText模型架构
fastText模型架构与word2vec的CBOW模型架构非常相似。fastText模型架构如下图:
Figure:model architecture of fastText for a sentence with N ngrams features
x 1 , x 2 , . . . , x N {{x}_{1}},{{x}_{2}},...,{{x}_{N}} x1,x2,...,xN. The features are embedded and averaged to form the hidden variable.
注意:此架构图没有展示词向量的训练过程。可以看到,和CBOW一样,fastText模型也只有三层:输入层、隐含层、输出层,输入都是多个经向量表示的单词,输出都是一个特定的target,隐含层都是对多个词向量的叠加平均。
不同之处在于:
- CBOW的输入是目标单词的上下文,fastText的输入是多个单词及其n-gram特征,这些特征用来表示单个文档;
- CBOW的输入单词被one-hot编码过,fastText的输入特征是被embedding过;
- CBOW的输入是目标词汇,fastText的输出是文档对应的类标。
值得注意的是:fastText在输入时,将单词的字符级别的n-gram向量作为额外的特征;在输出时,fastText采用了分层softmax,大大降低了模型训练的时间。
核心思想
仔细观察模型的后半部分,即从隐含层输出到输出层输出结果时,会发现它就是一个softmax线性多类分类器,分类器的输入时一个用来表征当前文档的向量。
模型的前半部分,即从输入层到隐含层输出的部分主要在做一件事:生成用来表征文档的向量。**原理:叠加构成这篇文档的所有词及n-gram的词向量,然后取平均。**叠加词向量背后的思想就是传统的词袋法,即将文档看成一个由词构成的集合。
**核心思想:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。**此中涉及两个技巧:字符级n-gram特征的引入以及分层Softmax分类。
在传统的文本分类器中,用来表征以下这两段文本的向量可能差距非常大。
肚子 饿了 我 要 吃饭
肚子 饿了 我 要 吃东西
在传统文本分类中需要计算出每个词的权重,比如TF-IDF值,“吃饭”与“吃东西”计算出的TF-IDF值相差可能会比较大,其他词类似,于是,VSM(向量空间模型)中用来表征这两段文本的文本向量差别比较大。
但在fastText中,它是用单词的embedding叠加获得的文本向量,词向量的重要特点就是向量的距离可以用来衡量单词间的语义相似度,于是在fastText模型中,这两段文本向量非常相似。使用embedding而非词本身作为特征,这是fastText效果好的一个原因;另一个原因就是字符级n-gram特征的引入对分类效果会有一些提升。
fatText与word2vec的异同
相同点:
- 图模型结构很像,都是采用embedding向量的形式,得到word的隐向量表达。
- 都采用很多相似的优化方法,比如使用Hierarchical softmax优化训练和预测中的打分速度。
CBOW的叶子节点是词和词频;fastText叶子节点是类标和类标的频数。
word2vec | fasttext | |
---|---|---|
输入 | one-hot形式的单词的向量 | embedding过的单词的词向量和n-gram向量 |
输出 | 对应的是每一个term,计算term概率最大 | 对应的是分类的标签 |
本质的不同,体现在softmax的使用:
word2vec的目的是得到词向量,该词向量最终是在输入层得到的,输出层对应的h-softmax也会生成一系列的向量,但是最终都被抛弃,不会使用。
fastText则充分利用了h-softmax的分类功能,遍历分类树的所有叶节点,找到概率最大的label
fastTest优点:
- 适合大型数据+高效的训练速度
- 支持多语言表达
- 专注于文本分类
Softmax回归
Softmax Regression 又称作多项逻辑回归multinomial logistic regression,它是逻辑回归在处理多类别任务上的推广。
在逻辑回归中,我们有m个被标注的样本: { ( x ( 1 ) , y ( 1 ) ) , . . . , ( x ( m ) , y ( m ) ) } \{({{x}^{(1)}},{{y}^{(1)}}),...,({{x}^{(m)}},{{y}^{(m)}})\} {(x(1),y(1)),...,(x(m),y(m))},其中
x ( i ) ∈ R n {{x}^{(i)}}\in {{R}^{n}} x(i)∈Rn。因为类标是二元的,所以我们有 y ( i ) ∈ { 0 , 1 } {{y}^{(i)}}\in \{0,1\} y(i)∈{0,1}。我们的假设hypothesis有如下形式:
h θ ( x ) = 1 1 + e − θ T x {{h}_{\theta }}(x)=\frac{1}{1+{{e}^{-{{\theta }^{T}}x}}} hθ(x)=1+e−θTx1
代价函数cost function如下:
J ( θ ) = − [ ∑ i = 1 m y ( i ) log h θ ( x ( i ) ) + ( 1 − y ( i ) ) log ( 1 − h θ ( x ( i ) ) ) ] J(\theta )=-\left[ \sum\limits_{i=1}^{m}{{{y}^{(i)}}\log {{h}_{\theta }}({{x}^{(i)}})+(1-{{y}^{(i)}})\log (1-{{h}_{\theta }}({{x}^{(i)}}))} \right] J(θ)=−[i=1∑my(i)loghθ(x(i))+(1−y(i))log(1−hθ(x(i)))]
在Softmax回归中,类标是大于2的,因此在我们的训练集 { ( x ( 1 ) , y ( 1 ) ) , . . . , ( x ( m ) , y ( m ) ) } \{({{x}^{(1)}},{{y}^{(1)}}),...,({{x}^{(m)}},{{y}^{(m)}})\} {(x(1),y(1)),...,(x(m),y(m))}中, y ( i ) ∈ { 1 , 2 , . . . , K } {{y}^{(i)}}\in \{1,2,...,K\} y(i)∈{1,2,...,K}
给定一个测试输入x,我们假设应该输出一个K维的向量,向量中每个元素的值表示x属于当前类别的概率。具体地:假设 h θ ( x ) {{h}_{\theta }}(x) hθ(x)
h θ ( x ) = [ P ( y = 1 ∣ x ; θ ) P ( y = 2 ∣ x ; θ ) ⋮ P ( y = K ∣ x ; θ ) ] = 1 ∑ j = 1 K e θ ( j ) T x [ e θ ( 1 ) T x e θ ( 2 ) T x ⋮ e θ ( K ) T x ] {{h}_{\theta }}(x)=\left[ \begin{matrix} P(y=1|x;\theta ) \\ P(y=2|x;\theta ) \\ \vdots \\ P(y=K|x;\theta ) \\ \end{matrix} \right]=\frac{1}{\sum\nolimits_{j=1}^{K}{{{e}^{\theta {{(j)}^{T}}x}}}}\left[ \begin{matrix} {{e}^{\theta {{(1)}^{T}}x}} \\ {{e}^{\theta {{(2)}^{T}}x}} \\ \vdots \\ {{e}^{\theta {{(K)}^{T}}x}} \\ \end{matrix} \right] hθ(x)=⎣⎢⎢⎢⎡P(y=1∣x;θ)P(y=2∣x;θ)⋮P(y=K∣x;θ)⎦⎥⎥⎥⎤=∑j=1Keθ(j)Tx1⎣⎢⎢⎢⎢⎡eθ(1)Txeθ(2)Tx⋮eθ(K)Tx⎦⎥⎥⎥⎥⎤
代价函数如下:
J ( θ ) = − [ ∑ i = 1 m ∑ k = 1 K 1 { y ( i ) = k } log e θ ( K ) T x ( i ) ∑ j = 1 K e θ ( j ) T x ( i ) ] J(\theta )=-\left[ \sum\limits_{i=1}^{m}{\sum\limits_{k=1}^{K}{1\{{{y}^{(i)}}=k\}\log \frac{{{e}^{\theta {{(K)}^{T}}{{x}^{(i)}}}}}{\sum\nolimits_{j=1}^{K}{{{e}^{\theta {{(j)}^{T}}{{x}^{(i)}}}}}}}} \right] J(θ)=−[i=1∑mk=1∑K1{y(i)=k}log∑j=1Keθ(j)Tx(i)eθ(K)Tx(i)]其中,1{.}是指示函数,即1=1,1=0
既然我们说Softmax回归是逻辑回归的推广,那么我们是否能够在代价函数上推导出它们的一致性?于是:逻辑回归是softmax回归在K=2时的特例。
分层Softmax
在标准的Softmax回归中,要计算y=j时的Softmax概率: P ( y = j ) P(y=j) P(y=j),我们需要对所有的K个概率做归一化,这在y很大时非常耗时。于是分层Softmax诞生了,其基本思想是:使用树的层级结构替代扁平化的标准Softmax,使得在计算 P ( y = j ) P(y=j) P(y=j)时,只需计算一条路径上的所有节点的概率值,无需在意其它的节点。
下图是一个分层Softmax示例:
树的结构是根据类标的频数构造的霍夫曼树。K个不同的类标组成所有的叶子节点,k-1个内部节点作为内部参数,从根节点到某个叶子节点经过的节点和边形成一条路径,路径长度被表示为 L ( y j ) L({{y}_{j}}) L(yj)。于是, P ( y j ) P({{y}_{j}}) P(yj)可被写成:
P ( y j ) = ∏ l = 1 L ( y j ) − 1 σ ( [ n ( y j , l + 1 ) = L C ( n ( y j , l ) ) ] ⋅ θ n ( y j , l ) T X ) P({{y}_{j}})=\prod\limits_{l=1}^{L({{y}_{j}})-1}{\sigma \left( \left[ n({{y}_{j}},l+1)=LC(n({{y}_{j}},l)) \right]\cdot \theta _{n({{y}_{j}},l)}^{T}X \right)} P(yj)=l=1∏L(yj)−1σ([n(yj,l+1)=LC(n(yj,l))]⋅θn(yj,l)TX)
其中: σ ( ⋅ ) \sigma (\centerdot ) σ(⋅)表示sigmoid函数; L C ( n ) LC(n) LC(n)表示n节点的左孩子; [ x ] \left[ x \right] [x]是一个特殊的函数,被定义为:
[ x ] = { 1 i f : x = = t r u e − 1 o t h e r w i s e \left[ x \right]=\left\{ \begin{matrix} 1 & if:x==true \\ -1 & otherwise \\ \end{matrix} \right. [x]={1−1if:x==trueotherwise
θ n ( y j , l ) \theta _{n({{y}_{j}},l)}^{{}} θn(yj,l)是中间节点 n ( y j , l ) n({{y}_{j}},l) n(yj,l)的参数;X是Softmax层的输入。
上图中,高亮的节点和边是从根节点到 y 2 y_2 y2的路径,路径长度 L ( y 2 ) = 4 L({{y}_{2}})=4 L(y2)=4
P ( y 2 ) = P ( n ( y 2 , 1 ) , l e f t ) ⋅ P ( n ( y 2 , 2 ) , l e f t ) ⋅ P ( n ( y 2 , 3 ) , r i g h t ) = σ ( θ n ( y 2 , 1 ) T X ) ⋅ σ ( θ n ( y 2 , 2 ) T X ) ⋅ σ ( − θ n ( y 2 , 3 ) T X ) P({{y}_{2}})=P(n({{y}_{2}},1),left)\cdot P(n({{y}_{2}},2),left)\cdot P(n({{y}_{2}},3),right)=\sigma (\theta _{n({{y}_{2}},1)}^{T}X)\cdot \sigma (\theta _{n({{y}_{2}},2)}^{T}X)\cdot \sigma (-\theta _{n({{y}_{2}},3)}^{T}X) P(y2)=P(n(y2,1),left)⋅P(n(y2,2),left)⋅P(n(y2,3),right)=σ(θn(y2,1)TX)⋅σ(θn(y2,2)TX)⋅σ(−θn(y2,3)TX)
于是,从根节点走到叶子节点 y 2 y_2 y2,实际上是做了三次二分类的逻辑回归。通过分层的Softmax,计算复杂度从 ∣ K ∣ |K| ∣K∣降低到 l o g ∣ K ∣ log|K| log∣K∣.
pickle.load()
cdot \sigma (-\theta {n({{y}{2}},3)}^{T}X)$
于是,从根节点走到叶子节点 y 2 y_2 y2,实际上是做了三次二分类的逻辑回归。通过分层的Softmax,计算复杂度从 ∣ K ∣ |K| ∣K∣降低到 l o g ∣ K ∣ log|K| log∣K∣.