纳勃剌汗-糞皇帝本纪

其实是因为 CS224N 只看了一半捏。剩下一半感觉看不看区别也不是很大捏。

其实也没啥用,放出来给大伙乐呵乐呵。

\[\newcommand{\b}{\boldsymbol} \]

其之一来自于白山黑水

Denotational Semantics: 一个单词所指代的语义。

如何将单词从描述实存着的一组物体变为可被电脑操纵的一些信息?

  • 法一:使用 WordNet 等网站将单词和术语组成同义集或超同义集等。但是其无法意识到细微的差别,且需要大量人力维护。
  • 在传统 NLP 中,单词会被当作 localist 即“局部化”的表达,此时相当于为每个单词建立一个 one-hot 向量。但是不同向量两两正交无法衡量相似性。
  • 使用 WordNet 手动衡量相似性的手段最终失败了。还是来看看 Attention 罢。

Distributional Semantics: 一个单词的语义不仅由其自身决定,也受到周围单词的影响。

一个单词对应的 context 即为其周边一圈的其它文本。我们认为,context 本身应该即包含了一部分单词的 semantics。

在 NLP 中,一个 'token' 是指一个单词(中文中是单字或词语),而其可能在具体语言中有着 embedding,或称 word vectors 或 (neural) word representations。这是一个 distributional semantics 的概念。

第一个赶到战场的是 Word2Vec 算法 (Mikolov et al., 2013)

有一个大的语料库 corpus。

语料库中出现过的每个词都对应着一个向量。

对于每个位置,其有中心词汇 \(c\) 和上下文 \(o\)

通过词向量间相似性,可以根据 \(c\) 预测 \(o\) 或相反,将成功的概率列入最优化的目标。

不断调整词向量以最大化预测概率。

公式:

\[\text{Likelihood}=L(\theta)=\prod_{i=1}^n\prod_{-m\leq j\leq m}\Pr(w_{i+j}\mid w_i,\theta) \]

其中 \(\theta\) 是模型参数。Loss 被如下设计:

\[\text{Loss}=J(\theta)=-\dfrac1n\ln L(\theta)=-\dfrac1n\sum_{i=1}^n\sum_{-m\leq j\leq m}\ln\Pr(w_{i+j}\mid w_i,\theta) \]

如何计算 \(\Pr\)?为每个词赋以两向量:\(\b v_w\) 为 center 的向量,\(\b u_w\) 为 context 的向量,则

\[\Pr(o\mid c)=\dfrac{\exp\b u_o\cdot\b v_c}{\sum\limits_w\exp(\b u_w\cdot\b v_c)} \]

计算法则即为 softmax。

该算法中唯一要调的参数即为全体 \(\b u,\b v\)。于是把它们直接拼接得到一极长向量即为参数向量 \(\theta\),在 \(\theta\) 空间中跑梯度下降即为算法。

验证词向量优秀性质的方法之一是类比任务(analogy task)。例如,我们或许应该认为,有

\[\text{king}-\text{man}+\text{woman}=\text{queen} \]

而优秀的词向量集确实能达到如此的类比效果。

  • 使用 \(\b u,\b v\) 分开的原因之一,是因为全用同一个 embedding 会让算梯度的步骤变得丑陋,例如 center 和 context 中出现同一个单词的场合。

  • 这两个向量会很像但不完全相同,因此实际过程中常常会将它们平均得到唯一的向量作为 embedding。

  • 但是,一词多义的场合又如何呢?

  • “反义词”常常具有相似的 context 地位。我们在一些场合会说这很牛,一些场合会说这很拉,这种相似的地位有可能会导致牛和拉具有相似的向量,但这并非我们想看到的。

  • 例如 'so' 这样的程度词(或称“虚词”,因为它往往没有实际含义)又如何?

  • Word2Vec 没有考虑位置信息?

其之二游走于北海岸畔

Word2Vec 是所谓的“词袋(Bag of Words)”模型:其没有区分 context 中的单词,而是把它们平等对待。

同时,因为选项过多,每个备选项的概率均奇低无比。

  • 梯度下降(Gradient Descent)法非常昂贵,因为参数很多,每次计算成本非常大。因此解法是 SGD(Stochastic Gradient Descent),每次只选择一小批样本,更新其和其周围参数。
  • 但是 SGD 的更新梯度会非常稀疏,只有少量涉及到的参数会被更新。

Aside(旁白):在 Pytorch 中,向量的存储是行向量。

两种 Word2Vec 的变体模型:

  • Skip-Grams(SG) 模型:使用 centre 预测 context。【也即前文所述模型】
  • Continuous Bag of Words(CBOW) 模型:使用 context 预测 center。

同时,以上的概率计算方式是 softmax,但这不牛。更好的方法是 Negative Sampling(NS) 方法,与 SG 结合即得 SGNS。

SGNS:

我们希望 center 与 context 尽量像,同时 context 理应与随机词汇不像。于是有

\[J(\theta)=\ln\sigma(\b u_o\cdot\b v_c)+\sum_{i=1}^k[j\sim (w)]\ln\sigma(-\b u_j\cdot\b v_c) \]

即随机采样 \(j\) 作为中心词,其与 context 应该不像。\(\sigma\) 即为 sigmoid 函数。其中,采样单词的分布取决于该单词在语料库中出现的频率,但并非直接正比于,而是正比于 \(0.75\) 次幂,以遏制那些过于常用的词。实际运用时因为要最小化 \(J\),所以常常取相反数。

定义 co-occurrence 矩阵(共现矩阵)是语料库中每个单词作为 center 时,其它单词在它周围的 context 中出现的次数。想见,该矩阵应是对称矩阵。使用该矩阵的行/列(它们相同)向量作为 embedding 向量,牛吗?

  • 问题:共现矩阵大而稀疏。

如何降维?答曰:SVD。

但是 SVD 不牛,因为有众多出现过多次的常见词与众多出现极少的生僻词。因此可以作如下优化:

  • \(\ln\)
  • 出现次数对某个上界(例如 \(100\))取 \(\min\)
  • 忽略 so 等虚词(functional word)。

此类算法的典型例子如 COALS 模型。

GloVe 模型是结合二者优势的模型:线代方法易训练(纯粹统计学),问题在于对不同单词的重视程度的比例不对,且空间开销很大;Word2Vec 方法相当于用时间换空间,易于拓展语料库,但是对统计学的利用不足。

一个思想是:从卡车到司机,从国王到女王,会有一些“有意义的成分meaning component”,这些成分被表示为共现频率的比率。

例如,“从固体到气体”这个过程是一个有意义的成分;ice 与 solid、water 均常出现,与 gas 不常出现;steam 与 gas, water 常出现,与 solid 不常出现;因此考虑一个词与 ice 和与 steam 频率的比值,则:

  • solid 对应的比值很大;gas 对应的比值很小;water 和随机词汇应该接近 \(1\)

为应用该观察,我们建立“对数双线性模型”,Log-Bilinear Model。

  • \(\b w_i\cdot\b w_j\sim\log P(i\mid j)\)(或是 \(j\mid i\),二者应该对称)
  • \(\b w_x\cdot(\b w_i-\b w_j)\sim\log\dfrac{P(x\mid i)}{P(x\mid j)}\)。(这一点其实直接由上一条就能推得)

令共现矩阵 \(X\),则误差

\[J=\sum_{i,j\in\text{wordlist}}f(X_{i,j})(\b w_i\cdot\b w_j+b_i+\tilde b_j-\ln X_{i,j})^2 \]

其中 \(f\) 是类似于 \(\min(x,t)\) 之类的限制过多出现的权重,而 \(b\) 是偏置。

好的,上面的东西很不错,那我们应该如何评价它呢?

  • Intrinsic 内部的评估:看看它在特定任务上解决成果如何。往往评估很快,但是不一定能描述现实任务。
  • Extrinsic 外部的评估:看看它在真实问题上成果如何。评估很慢。且只有宏观结果,不清楚优化产生的具体原因(是词向量变牛了还是其与其它组件的交互变牛了)

使用 analogy task 可以检验 embedding 的优秀程度。

同样还有人工给出的单词相似度评分。

使用维基百科训练比使用新闻稿牛!或许是因为维基百科总是客观(存疑)地阐述事实。

增加维度可以提高效果!但 2013-2015 左右,维度提高到 \(300\) 效果就几乎不增加了。

  • 最后,我们的词向量能拿来干嘛?

  • 例如,给一段话,找出其中的人名、地名、公司名等“命名实体”。这也是一种好评分的方法。

问题回到一词多义。常见词或历史悠久的词都常常用法众多。

因此常常对于一个词的不同词义构建不同的向量。方法比如说,对于实际例子中的单词,我们将其进行聚类,希望同一个聚类中的单词具有相近的词向量。对于同一个单词在不同聚类中的出现,我们把它当成不同单词看。

这很棒,但是有问题:

  • 训练不是端到端的,要先学词义再学词向量。
  • 切割常常是生硬的,部分含义之间存在的重叠无法处理。
  • 事实上,单一向量已经足够好:它事实上学习的结果被表现为多个向量的比例叠加,比例即为某种词义的出现频率;并且在实际上,因为维数很多,例如 pike 一词同时是长矛和一种鱼,二者关系不大所以单独的语义向量近似垂直,线性组合后,例如和“鱼”点积的结果,则“长矛”分量几乎没有贡献。因此,对于一个词的多个语义(最好差别很大),其实是可以找到与每个语义相近的词,进而还原出其对应的语义分向量。

其之三驰骋于草原戈壁

Named Entity Recognition (NER): 寻找、识别文章中的人名、地名、日期等。

方法:将该词与周围的 context 的 embedding 拼一块跑全连接层分类。

全连接头与词向量部分可以一起训。

数学?谁会想听数学呵!

takeaways:

Hadamard 积 \(\odot\):适用于两个形状相同的矩阵或向量间,得到的结果是对应位置相乘的结果。

其之四忽囿于雠敌之羁轭

the cuddly cat by the door。每个单词都有其词性:determiner(限定词,如 a the my all 等,DET);ADJ;N;P(preposition);DET;N。

单词组成词组 phrase。the cuddly cat 是 NP,the door 是 NP,by the door 是 PP(prepositional phrase),合在一起是一个更大的 NP。

一个 Noun Phrase (NP) 包含一个 DET 和一个 N。更常见的是 DET+ADJ+N+PP,其中 ADJ 和 PP 是 optional 的。形容词可以有多个,因此使用正则表达式的概念,写成

NP->DET+(ADJ)*+N+(PP)。而例如 PP 就是 PP->P+NP。

Dependency Structure 描述文法的方式是一些词汇“修饰”另一些词汇:如果 A 修饰了 B,那么就自 A 连箭头指向 B。

  • Look at the large crate in the kitchen by the door!

箱子修饰 look。the、large 修饰 crate。in the kitchen 修饰 crate。by the door 同样修饰 crate。

因为人读文章时会不自觉地理解文法结构,所以有理由相信波特读文章时想要看懂句子就也要理解文法结构。但是因为歧义的存在,人类自身有纠错机制,波特则需要以概率的方法探索所有可能的方案。

一个例子是介词短语之间互相修饰的方案是树形的,这个树有多种布线方法。

最终,我们有依赖树语法(dependency tree grammar):把全体依赖关系写成一棵树。

treebank 存储了众多人工处理得到的语法树。早期 NLP 处理句子的方式常常是:给定句子,判定其 parse 的结果有多符合 treebank。

dependency parsing 的优势:

  • 双词汇亲和性(bilexical affinity):双向的依赖关系有说服力。
  • dependency distance:dependency 往往发生在临近词句间,很少长距离影响。
  • Intervening material:标点符号/动词两侧成分往往无关。
  • Valency of heads:每个不同词性的元素可能伴随不同修饰“化合价”出现。例如,名词只可能在左侧出现一个 DET,形容词也只可能出现在其左侧。

其有若干限制:

  • 根唯一。
  • 无环。
  • 箭头可以(表现在句子中)交叉(be non projective)吗?【可以的!但是比较少见】出现交叉的场合,CFG 不再适用

建立解释器的若干方法:

  • DP。
  • 因为解释器是树,所以尝试使用 MST。
  • 提出某些不可能满足的限制,不断缩小备选集。
  • Transition based parsing/deterministic dependency parsing(如下)。

Greedy transition based parsing:

有一个栈 \(\sigma\),初始有 \(\sigma=[\text{ROOT}]\)。句子 \(\beta=w_1,\dots,w_n\)\(A=\varnothing\)。之后,每次可以进行如下三操作之一:

  • Shift(入栈):将句子队首弹入栈。
  • Left-Arc(左依赖):取栈顶两个元素,让栈顶下一个元素依赖栈顶元素,将依赖关系放入 \(A\) 然后删除栈顶下一个元素。
  • Right-Arc (右依赖):同上,只不过是让栈顶依赖栈顶下一个元素然后删除栈顶。

最终结束态时,栈中应该仅剩一个元素,这个元素一定是 \(\text{ROOT}\)

模型很不错,但是如何知道应使用三操作中哪一种?

答曰:机器学习,出列!

算法本身会检测每次操作时,栈、队列、依赖关系中的若干新近信息,然后为其分配对应方案。优化过程可以机器学习找到最牛方案。

问题是如何评估算法牛不牛?指标一是对比波特给出的 dependency 集合和答案的集合。指标二是让波特同时为每个单词打标签:名词性宾语、形容词、补足语等,对比标签的正确程度。

其之五起势于微末孤子

GTBP 的问题之一在于特征是稀疏的,问题之二在于完全无法处理训练数据中未出现的信息(没有迁移能力),问题之三在于训练时间很长。

解决方法是把所谓的“配置”,即对每种情况下要干什么这件事的指令,浓缩为一个向量。

CDQ 神经网络法:

  • 首先,为每个词找到 word embedding。
  • 这个 word embedding 里面还存了其它一些信息这些信息不是存在 word embedding 里面,而是由自己独立的 embedding,例如这个词的词性(part of speech)(具体词性,例如 NNS(复数名词)和 NN(单数名词)、nummod(数词修饰)和 adjmod(形容词修饰);如上述指出的,这些词性之间存在一些相似关系,也可以被特征向量描述;同时还 嵌了 不是内嵌,同样是独立存在的 dependency label(即它们通过当前打标签系统是主语还是补足语等的标签)。
  • 现在开始执行算法!某一时刻,我们能看到的信息包括:
    • \(s_1,s_2\):倒数第二和栈顶元素。
    • \(b\):队列头元素。
    • \(lc,rc\)\(s_1,s_2\) 分别联系着的左右弧们。
    • 注意:目前只有 \(lc,rc\) 因为所有 dependency 都已决定所以有 dependency label;其它东西都只能查到词性。
  • 把这所有信息全都拼起来过一个 MLP 分类知道下一步干嘛即可。

Graph Based Dependency Parsers:对于每一个单词对,计算二者存在 dependency 的概率,然后跑 MST。


其它一些神经网络上的细节操作:

  • Regularization:为误差添加一个正则项,例如 \(\lambda\sum\theta_k^2\),即所有参数的平方和(此乃 L2 正则化),可以通过让那些无用的数据为零而遏制过拟合。
  • Dropout:避免 co-adaption,即多个神经元必须协同才能有效果,相当于多个只干了一个的活。实际执行时,每次训练随机干掉 \(\eta\) 的神经元,但是记得在真正跑的时候把所有权值都乘以 \(\eta\) 以弥补不再随机干掉神经元的变动。Dropout 往往被看作一种非均匀正则化。

Laguage Modeling:预测下一个词的任务。

前 DL 时代的解法:n-gram。

  • \(n\)-gram 是文本中出现的所有“\(n\) 个连续单词”的统称。

首先作出 Markov Assumption,即一个单词仅依赖于左侧所有单词,并且丢弃过早期的单词,仅保留当前位置的前 \(n\) 个单词。于是,计算条件概率

\[\Pr(x_{i+1}\mid x_{i-n+1},\dots,x_i) \]

由条件概率定义,其等于

\[\dfrac{\Pr(x_{i-n+1},\dots,x_{i+1})}{\Pr(x_{i-n+1},\dots,x_i)} \]

即一个 \(n+1\)-gram 与一个 \(n\)-gram 的比值。

于是取一个大 corpus,统计里面各种 \(n\)-gram 出现的次数,用次数替代概率即可。若分子上采用的是 \(n\)-gram(此时分母上采用 \(n-1\)-gram),则该模型称作 \(n\)-gram language model。

  • 问题之一:有很多词汇的影响会隔着很多单词传过来。
  • 问题之二(sparsity problem):语料库中有很多东西从来不出现。若分子未出现但分母出现,可以加一个小 \(\delta\) 来 smoothing;如果分母都没出现,可以 backoff,取更短的 \(n'\)-gram 预测。
  • 问题之三:语料库中必须存储所有的 \(n\)-gram,以至于必须在云端计算。

用这玩意可以写话!但是写出来的东西常常是 incoherent,不相干的。


最基础的 NLP 生成就是把基于 \(n\)-gram 的统计换成神经网络罢了:把前方一个窗口中所有东西一起扔到 classifier 里面生成即可。

这个现在解决了 sparsity 和语料库的问题,但是远距离投射的问题还没解决。同时,它现在为不同位置的向量建立完全不同的系数,这训起来不好训,因此我们希望它有一定的共同性但不完全相同(典型反例如 Word2Vec 即完全未考虑位置关系)。

解决方案是 RNN!我们用 hidden state,每次由前一时刻的 hidden state 和本时刻的 vector 共同得到本时刻的 hidden state,然后用 hidden state 过 MLP 预测即可。

新问题:

  • 没法并行!

其之六展露于风霜磨砺

RNN 如何训?把所有前缀扔进 RNN 得到每一时刻的概率分布 \(\hat{\b y}_t\),然后算交叉熵误差

\[-\sum\b y_t(w)\log\hat{\b y}_t(w)=-\log\hat{\b y}_t(x_{t+1}) \]

真正训练时应用 SGD 思想,每次仅提供语料库中被切碎的一小坨语料进去。

现在考虑反向传播:可以推式子得到,每次更新时采用的矩阵 \(W_h\) 在整个周期内的梯度,等于每一时刻的梯度求和的结果;反向传播时,一个朴素的想法是算出最后时刻的梯度,贡献给 \(W_h\),再推到前一时刻,再贡献……此乃 backpropagation through time。因为正向算时,用的都是统一的 \(W_h\),所以反向的时刻的 \(W_h\) 也必须统一,梯度在最后再一起加上去。

但是事实上这很慢!往往会进行一些截断(truncate),例如反向传播二十步即告终。

如何拿来生成句子?输入 [BEG] token 然后一个一个喂进去即可,每次依照生成的分布采样一个单词。以 [EOF] token 告终。

如何衡量你的 Language Model 牛不牛?

定义 Perplexity 困惑度为

\[\text{perplexity}=\prod_{t=1}^T\left(\dfrac1{\Pr(x^{t+1}\mid x_1,\dots,x_t)}\right)^{1/T} \]

\(\ln\) 就是 CELoss。困惑度越低越好。

\(n\)-gram 的困惑度是 \(100+\);但是困惑度有大约 \(20\) 的下界,因为有很多场合根本无法预测。

RNN 的其它用处:

  • Part of Speech tagging,named entity tagging……
  • 句子的情感分类。【跑完整个句子后的 hidden state 应该被视作整个句子的 embedding】
  • 问题回答/音频识别/机器翻译……

RNN 的问题:

  • 梯度在时间尺度下消失。【发生于转移矩阵 \(W_h\) 的全体特征值均小于 \(1\) 的场合】这是因为,RNN 擅长处理周遭事物,而远程对梯度的影响远小于近程。【解决方案:LSTM】
  • 同理,梯度也可能爆炸。【解决方案:gradient clipping 梯度剪裁,如果梯度太大就把它缩放】

LSTM 的思想:如今的算法每一步都会重写整个隐藏状态。因此想让它不完全重写。

  • 两个隐藏状态:hidden state \(\b h\) 和 cell state \(\b c\)。其中,后者更接近常规 RNN 中的 hidden state 的地位。
  • 门向量衡量哪些位置应该被抹去、抹去多少。

首先计算三个门向量 \(\b f\) 遗忘门、\(\b i\) 输入门、\(\b o\) 输出门,都用 \(\sigma(\dots)\) 得到。

然后计算新 cell state \(\tilde{\b c}=\tanh(\dots)\)。之后,真正的 cell state \(\b c=\b i\odot\tilde{\b c}+\b f\odot\b c\),然后 \(\b h=\b o\odot\tan\b c\)

梯度爆炸、消失等仍会出现。解决方法是建立 shortcut、skip 连接等。


hidden state 可以被看作一个词在上下文中的 embedding。但是也存在一些问题,例如只有左侧的单词会贡献信息。

  • 解决方法之一:双向 RNN,训一个反向的 RNN,将两个 hidden state 直接拼接。【不适用于目标是根据前缀生成下一个的 Language Modelling 任务】

其之七结集众英杰贤达

机器翻译是从源语言(source language)翻译为目标语言(target language)的任务。

早期:纯机械查单词(效果很烂)

1990-2010:Statistical Machine Translation。即,从数据中学习一个概率模型。

思想:对于源语言的句子 \(x\) 找到最优的目标语言句子 \(y\),即求得

\[\arg\max\Pr(y\mid x) \]

使用 Bayes 公式改写为

\[\arg\max\dfrac{\Pr(x\mid y)\Pr(y)}{\Pr(x)} \]

分母上的 \(\Pr(x)\) 是常数可以忽略;分母上两部分相对独立。\(\Pr(y)\) 可以根据语言模型算出,\(\Pr(x\mid y)\) 呢?

  • 首先,搜集大量的 parallel data,即匹配的源-目标语句对。
  • 然后,引入一个隐变量 \(a\) 表示对齐(alignment),即单词级别的对应关系,然后处理 \(\Pr(x,a\mid y)\)
  • 对齐有一些功能,比如说处理不同语言间的不同语序关系,或者某些语言中没有对应关系的虚词等。因此,对齐可能是一对一、一对多、多对一、多对多(词组对词组的翻译)【这同样也适用于同一种语言中,对同一个意象的不同表达方式】
  • 学习 \(a\) 的方式多样,如观察两个单词共同出现的频率等。
posted @ 2024-11-30 17:29  Troverld  阅读(53)  评论(8编辑  收藏  举报