吾尝终日而思矣,不如须臾之所学也!
最近在学Yandex公开的NLP课程,在这做一些笔记,方便查询和交流,如有理解错误欢迎指正。
If it is a good model, it probably can predict what happens next given some description of “context”, i.e., the current state of things.
A good model would simulate the behavior of the real world: it would “understand” which events are in better agreement with the world, i.e., which of them are more likely.
Language Models (LMs) estimate the probability of different linguistic units: symbols, tokens, token sequences.
If a language model is good, it will assign a larger probability to a correct option.
我们的目标是去估计文本片段(多为句子)的概率,我们希望这个概率能反映语言中的一些知识/含义。特别是在特定条件下语言中更容易出现的文本片段,我们希望它能在语言模型中拥有更高的概率。
那么怎么去估计这个概率呢?一种方式是采用简单的“盒子摸球”式估计,即此时盒子为text corpus,而小球对应sentence。但这种做法会有一个很大的隐患是无法找到一个text corpus去包含所有的sentences。这会导致很多sentence本身对应的probability差距很大,实际model却都为0的情况,故这种办法不太可取。
在句子层面上不行,便考虑将其划分到更小的层面——比如token。
we estimate the probability of all seen so far tokens. We don’t want any computations not to be in vain (no way!), so we won’t throw away previous probability once a new word appears: we will update it to account for a new word.
并且在计算时不抛弃之前已计算过token的概率:
p ( y 1 , y 2 , . . , y n ) = p ( y 1 ) p ( y 2 ∣ y 1 ) . . . p ( y n ∣ y 1 , . . , y n − 1 ) = ∏ t = 1 n p ( y t ∣ y < t ) p(y_1,y_2,..,y_n)=p(y_1)p(y_2|y_1)...p(y_n|y_1,..,y_{n-1})=\prod_{t=1}^np(y_t|y
这种framework通常被称为standard left-to-right language model——N-gram and neural language models便是基于此,唯一差别是它们计算条件概率的方法。
We need to: define how to compute the conditional probabilities P ( y t ∣ y 1 , … , y t − 1 ) P(y_t|y_1,…,y_{t−1}) P(yt∣y1,…,yt−1)。我们使用count global statistics from a text corpus,即“盒子摸球”式估计,不过此时是的小球是token。n-gram LMs的有两个关键成分:马尔可夫性质和光滑性。
一个很直接的计算:
p ( y n ∣ y 1 , . . , y n − 1 ) = N ( y 1 , y 2 , . . , y n − 1 , y n ) N ( y 1 , y 2 , . . , y n − 1 ) p(y_n|y_1,..,y_{n-1})=\frac{N(y_1,y_2,..,y_{n-1},y_n)}{N(y_1,y_2,..,y_{n-1})} p(yn∣y1,..,yn−1)=N(y1,y2,..,yn−1)N(y1,y2,..,yn−1,yn)
这里 N ( y 1 , … , y k ) N(y_1,…,y_k) N(y1,…,yk) 代表tokens组成的句子$ (y_1,…,y_k)$ 出现在text corpus中的次数。根据前述文本概率部分分析,corpus里不可能包含所有包含tokens: ( y 1 , . . , y k ) (y_1,..,y_k) (y1,..,yk)组成的句子。为解决这个问题,有了 independence assumption (assume that the Markov property holds):The probability of a word only depends on a fixed number of previous words. 即词出现的概率仅与它相邻几个词有关系。
考虑一个例子,当我们使用4-gram model的时候, p ( m a t ∣ I s a w a c a t o n a ) = N ( c a t o n a m a t ) N ( c a t o n a ) p(mat|I\ saw\ a\ cat\ on\ a)=\frac{N(cat\ on\ a\ mat)}{N(cat\ on\ a)} p(mat∣I saw a cat on a)=N(cat on a)N(cat on a mat),但是有一个问题是,如果短语 cat on a \textbf{cat on a} cat on a并没有出现在corpus中,那么该式的分母将会为0,从而无法计算。因此,提出了平滑的trick。
trick1:Backoff
trick2:Linear interpolation
更明智的做法是“都要“,即需要一些正的权重 λ i \lambda_i λi,满足 ∑ i λ i = 1 \sum_i\lambda_i=1 ∑iλi=1,可以通过交叉验证来选取,将在Evaluation部分讨论。
故概率的估计变为 p ^ ( m a t ∣ c a t o n a ) ≈ λ 3 p ^ ( m a t ∣ c a t o n a ) + λ 2 p ^ ( m a t ∣ o n a ) + λ 1 p ^ ( m a t ∣ a ) + λ 0 p ^ ( m a t ) \hat p(mat|cat\ on\ a)\approx \lambda_3\hat p(mat|cat\ on\ a)+\lambda_2\hat p(mat|on\ a)+\lambda_1\hat p(mat| a)+\lambda_0\hat p(mat) p^(mat∣cat on a)≈λ3p^(mat∣cat on a)+λ2p^(mat∣on a)+λ1p^(mat∣a)+λ0p^(mat)
同样,分母也可能出现0的情况,这里介绍一种方法
p ^ ( m a t ∣ c a t o n a ) = δ + N ( c a t o n a m a t ) δ ⋅ ∣ V ∣ + N ( c a t o n a ) \hat p(mat|cat\ on\ a)=\frac{\delta +N(cat\ on\ a\ mat)}{\delta\cdot|V|+N(cat\ on\ a)} p^(mat∣cat on a)=δ⋅∣V∣+N(cat on a)δ+N(cat on a mat)
procedure:给定当前的context,生成一个概率分布去预测下一个token,将这个token加入到context,并重复。
n-gram model主要缺点:不能使用长文本,可能导致生成的句子不流畅。并且如果采用greedy的策略去解码的时候,结尾符会有很高的概率,且很多text容易生成相同短语。
与N-gram基于global corpus statistics计算概率不同,neural models 训练一个 network 去预测这些概率。主要做俩件事情:(1)encode context (2)生成下一个token的概率分布。我们也可以认为neural language models 是 neural classifiers,这里分类数classes为 ∣ V ∣ |V| ∣V∣,即词汇库里tokens的数量。
由于可以认为是一个 neural classifiers,故对于不同的模型框架,general pipeline都是一致的:
除了使用线性变换使得dim(h)变为dim(output),还有一个有意思的做法是:
Applying the final linear layer is equivalent to evaluating the dot product between text representation h and each of the output word embeddings.
这里通常采用的优化目标为cross-entropy,具体不再赘述。
L o s s ( p ∗ , p ) = − ∑ i = 1 ∣ V ∣ p i ∗ log ( p i ) Loss(p^*,p)=-\sum_{i=1}^{|V|}p_i^*\log (p_i) Loss(p∗,p)=−∑i=1∣V∣pi∗log(pi)
值得注意的一点是,当target的分布为one-hot的时候,即 p ∗ = o n e − h o t ( y t ) p^*=one_{-}hot(y_t) p∗=one−hot(yt)
L o s s ( p ∗ , p ) = − log ( p y t ) = − log ( p ( y t ∣ y < t ) ) = D K L ( p ∗ ∣ ∣ p ) Loss(p^*,p)=-\log (p_{yt})=-\log (p(y_t|y_{
与文本分类中使用的CNNs相比,language models有一些不同:
我们知道,CNN处理图像时候如果没有池化层,那么参数量将是巨大的,而在文本预测中如果需要堆叠许多层且不删除位置信息,那将是很难训练的,故提出了剩余连接的trick。
Residual connections are very simple: they add input of a block to its output. In this way, the gradients over inputs will flow not only indirectly through the block, but also directly through the sum.
其中Highway connection的gate类似于LSTM的gates(即还可以学习哪些features需要为每个token传递,哪些不需要)。
一个convolutional network with residual connections:
正如我们前面看到的,要使用语言模型生成文本,您只需要从模型预测的概率分布中抽样标记。但通常希望生成的文本具有:一致性(生成的文本必须有意义)与多样性(模型必须能够产生非常不同的样本)。
最标准的生成序列的方法是使用模型预测的分布,而不做任何修改。
这存在一个问题是,当 τ \tau τ接近0的时候,几乎所有的token对应概率变为0,这会失去多样性;而当 τ \tau τ很大的时候,几乎所有的token对应概率都很接近,这又会失去一致性。
选取Top-K可以避免很多不可能的tokens出现,但同样也有问题,比如:
覆盖很小一部分的总概率质量(在比较平的分布中)
包含非常不可能的token(在比较尖的分布中),比如一些停用词
A more reasonable strategy is to consider not top-K most probable tokens, but top-p% of the probability mass: this solution is called Nucleus sampling.
假设我们有了一个held-out text: y 1 : M = { y 1 , y 2 , . . , y M } y_{1:M}=\{y_1,y_2,..,y_M\} y1:M={y1,y2,..,yM}
通常在模型中的两个embedding matrices是不相同的,一个用来输入文本内容,一个用来在预测前得到概率分布,即两者参数是不同的。当想让两矩阵相同时候,一种方法是Weight Tying。
Weight Tying的效果类似于正则化,它迫使模型不仅给目标标记提供高概率,而且给嵌入空间中接近目标的单词提供高概率。更多细节参考Tying Word Vectors and Word Classifiers: a Loss Framework for Language Modeling。
https://lena-voita.github.io/nlp_course/language_modeling.html