讨论 2020-09-21
=
###### tags: `tutorials` `Fudan` `2020`
## NLP是做什么的?
自然语言处理的根本目标是让计算机做到两件事,读懂自然语言和生成自然语言,也就是读和写。
### 一个简单的例子
读懂一句话也就是理解其中的含义,或者说把文本内容的语义提取出来。所以读懂/理解一句话就是把它的语义抽象出来。比如“好吃”,“真好吃”,“好吃!”都会被抽象成正面评价“好”,而“难吃”,“不好吃”则被抽象成“坏”。
用形式化的语言来描述这个问题就是我们要找到一个函数$f$,满足$$f(好吃)=好, f(难吃)=坏$$
当然,我们还要满足很多其他条件,比如输入是可以拆分的。我们这里的情况比较简单,可以把“好吃”当做一个输入,但假如处理长句子“昨天天气不错,今天天气也不错,这个汉堡好吃。”,显然把这一整句话当做一个输入就比较困难了,因为语言的组合和说法太多,不可能为每个句子一一存储。所以,我们通常需要把输入拆分成更小的单元,比如词,字。
下面我们考虑如何构造$f$,绝大多数情况下,我们都采取人为设计函数形式,再用优化的方法估计其中的参数。
$f(好吃)=\alpha e(好) + \beta e(吃), f(难吃)=\alpha e(难) + \beta e(吃)$
这里面的 $e$是每个字的代称,实际上每个字都是一个变量,比如$e(好)=x_1, e(吃)=x_2$
有了这些设定后,我们从求解$f$就变成了求解$\alpha,\beta,e$。
(这种转换的目的是什么?)
为了方便,我们把要满足的目标改为0,1,实际上可以是任意不相等的两个数,所以
\begin{gather}
f(好吃)=0, f(难吃)=1 \\
L = ||0-f(好吃)||_2 + ||1-f(难吃)||_2
\end{gather}
而$L$,loss function,误差函数的作用是衡量我们离目标有多远。
至此,我们发现有一种通用的求解参数$\alpha,\beta,e$的方法,那就是利用$\frac{\partial L}{\partial \alpha}, \frac{\partial L}{\partial \beta}, \frac{\partial L}{\partial e}$。
不管$\alpha,\beta,e$的初始值是什么,利用梯度,我们总能找到一个局部最优解。
有了$f$的具体参数,我们就可以用它去处理新数据,完成相应的任务。
但这个例子中忽略很多重要问题,我们下面会一一讨论。
### NLP问题的通用流程
- Data,数据,数据是我们解决问题最基础的条件,数据的质量,数量往往决定了我们可以达到的上限。特别需要注意的是数据处理在NLP中非常重要,其作用远胜于其他环节,良好的数据处理加上简单的模型可以很容易超越粗糙的数据处理加上精妙的模型。
- Model,模型,也就是我们人为规定的参数形式,是我们接触最多也修改最多的,但要明确模型是骨架,设计出一个好的模型只是个开始,我们还需要其他环节把内容填好。
- Loss,误差函数,误差函数是我们定义的游戏规则,我们要尽量避免漏洞,保证其目标和我们期望的一致。
- Optimization,优化,loss制定了游戏规则,model和data决定了我们的上限,但optimization决定了我们实际能做得多好。其他设计的再好,优化不好,也拿不到好结果。
- Analysis,分析,参数估计的方法决定了我们不是从已知条件推理出答案的,而是从茫茫大海中挑选了一个可行的答案,这个答案为什么对,怎么来的,我们都不知道。为了知道我们拿到的结果在其他地方有什么作用,有什么反应,分析是必不可少的。

### 读
http://nlpprogress.com/
Constituency parsing, Coreference resolution, Dependency parsing, Information extraction, Intent Detection and Slot Filling, Named entity recognition, Natural language inference, Part-of-speech tagging, Question answering, Semantic parsing, Semantic role labeling, Sentiment analysis, Text classification, Word segmentation, etc.
#### 整句分类
从输入序列映射到单一输出是文本分类中很常见的一种设定,比如情感分析,判断一句话的情感极性,这里主要涉及一个问题就是如何把变长输入变成定长输出。方法虽多,但不外乎几种思路,一是把变长序列补成定长,二是时间维度的pooling,例如取序列最大值,平均值,topk等。三是加权求和,其中又分为归一化的求和,比如attention,和不归一化的求和,比如gate。此外,还有一种方法就是递归求解,比如把一个序列两两合并,直至只剩一个元素。
#### 序列标注
序列标注其实是最直观的分类任务,因为每一个输入都对应一个输出,只需要把特征映射到类别即可。但序列标注经常会遇到的一个问题就是类别不均衡问题,比如NER中O比其他tag出现要多很多。如果是SRL和slot filling等任务中,这一现象就更为明显。
#### 结构抽取
结构抽取的概念比较杂,比如关系抽取,指代消解,事件抽取,句法分析等等。他们的机制各不相同,并且与生成有一定联系,但他们的共同点是在很有限的范围里做出决策。比如关系抽取只能在预先定义的关系中选择一种,指代消解也只能在输入中进行选择,事件抽取只能从模板中选取。这些任务有时可以用生成模型来处理,但和生成问题的区别主要还是在这些问题决策的范围是非常有限的,并且是紧紧围绕在输入信息上面的。而生成任务往往更自由,选择范围更大。
### 写
Data-to-Text Generation, Grammatical error correction, Language modeling, Machine translation, Summarization, Dialogue, etc.
#### 无源文本生成
无源生成就是指随意生成人话,之所以不直接叫语言模型,是因为GAN和VAE序列的工作和语言模型还有一定的区别,这些模型可以生成文本,但很多时候不能显式给出其概率。或者VAE也可以叫有源,但这个信息源是噪声分布,所以归于无源生成更好些。
#### 有源文本生成
有源生成也就是根据给定信息进行文本生成,给定信息可以是各种形式,比如是图片,那就是Image Caption,如果是外语,那就是Machine Translation,如果是大段文本,可能就是 Summarization。 这类任务最常见的架构就是encoder-decoder,要注意decoder是如何利用encoder信息的。

https://www.tensorflow.org/tutorials/text/nmt_with_attention
https://github.com/pytorch/fairseq/blob/master/fairseq/modules/transformer_layer.py
#### 复制粘贴及带限制的文本生成
有些时候,我们需要生成过程满足一些规律,比如在翻译过程中出现的人名,地点,就可以直接复制过去,而不是从完整词表中选择。有的时候我们需要输入的信息都要被用到,而不是有大量遗漏,又或者,我们不希望生成的文字有太多重复的内容。
#### 自回归和非自回归生成
人说话和写字都是有顺序的,那机器一定要和人顺序一样吗,或者说一定要有序吗?非自回归模型讨论了一种新的可能性,也就是所有位置同时生成,而不设定具体的顺序。
### 常见模型
NLP中常用模型为CNN,RNN,Attention,近年来对GNN的使用也在增多。
#### NLP特有问题
和一般机器学习问题相比,NLP问题有两大特点
- 输入变长且有长距离依赖
- 离散且数据空间极大
#### CNN
卷积可以看做对一个局部区域按位置求和,在图像上卷积核的物理意义比较明显,比如模糊,锐化,方向检测等等。但在文本上无明确的物理含义,因为文字是离散的,我们很难理解语义的几何关系,比如我们可以理解 “一般”在“好”和“不好”的中间,但很难去思考“月球”和“汽车”的中间值是什么。
$$y_i = W_1 x_{i-k} + W_2 x_{i-k+1}+ ...+W_{2k+1} x_{i+k}$$

http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/
#### RNN
循环神经网的本质是时间步之间的参数共享,即从$i \rightarrow i+1$和$j \rightarrow j+1$的规律相同。虽然这一假设在广义上总能满足,但实际上还是有困难,比如一段文字的背后规律是DAG,自动机这种。可另一方面,RNN可以近似任意阶的Markov Chain,已经很强了。

http://colah.github.io/posts/2015-08-Understanding-LSTMs/
#### Attention
注意力机制不像RNN和CNN有明显的归纳偏好,注意力机制允许任意输入元素间两两交互,但实际上它也自己的假设,只是不如RNN和CNN那样明显。注意力机制实际上对两两交互关系做了分解,用向量外积来生成交互矩阵,而这些被使用的向量是与位置无关的,是每个位置的特征独立运算所得。
\begin{align}
\alpha =& QK^T \\
\alpha =& H W_Q (H W_K)^T\\
\alpha =& H W_Q W_K^T H^T \\
\alpha =& H R H^T \\
\end{align}
$R$实际上定义了特征之间如何两两交互,注意力机制把交互矩阵$\alpha$参数化为$H H^T$的形式其实也是一种归纳偏好。比如处理的语言,它不论内容如何,一定是回文的,即正反读是一样的,那注意力机制就不好直接刻画这种关系。
#### 词嵌入表示
因为语言涉及的离散状态实在太多,人们就想到用一种连续的表示来覆盖这些状态,也就是词嵌入表示。
https://projector.tensorflow.org/
#### 小结
理论上,RNN和注意力机制都是有广泛适用性的,换言之绝大多数NLP问题都可以用RNN和注意力机制,并且存在可行解,但实际中存在不代表我们可以找到。每种模型甚至是同一模型的不同的实现方法都有各自的特点。具体问题要具体分析。
## 几个问题
### 为什么需要非线性?
线性模型有局限性,难以涵盖一些情况,所以需要非线性。
|输入|输出| |
|-|-|-|
|好好吃| 正面| a+x = 0|
|不好吃| 反面| b+x = 1|
|好难吃| 反面| a+y = 1|
|不难吃| 正面| b+y = 0|
### 自然语言的“自然”是什么意思?
Chomsky hierarchy 把语言分成四个层级,正则表达式,上下文无关文法,上下文有关文法,和无限制文法。而自然语言就属于最后一种,机器所用的语言大多属于前两种。
### 语言的最小单元是什么?
在之前的例子中我们也有提到,希望把输入信息分解成由小单元组成的序列,这也就涉及了最小单元的概念,实际上,有很多不同理解,字,词,subword,拼音,笔画,unicode的一个字节等等。不同工作,不同场景下拆分的粒度也有不同。但大体上要考虑三方面因素,一是长度,拆得越细,长度越长,二是词表大小,粒度越粗,词表越大,三是表达能力,粒度越细,往往每个元素包含的语义信息越少,我们也就需要更复杂的网络来融合它们。
# 关于研究的一些建议
## 代码可以借鉴,论文不能抄袭
## 灵感哪里来
- **站在巨人的肩膀上** 很多问题,很多解法前人都考虑过,充分利用这些知识会很重要的,过去失败的方法可能只是需要的条件没达到,放到现在也许就是成功的。
- **多观察** 多观察数据,多观察实验结果,在发现规律这个问题上,人比机器强
- **多比较** 新颖性永远是个相对的概念,首先要熟知相关工作的做法,才能知道什么是新颖的,自己方法的特色是什么
- **生活实践** 生活常识有时也是方法的来源,同时当我们有新想法时,也要考虑是否符合常识
## 不要为论点找论据
不要先有一个结论,然后想方设法做实验,找到证据来证明这个论点。
- **贝叶斯公式** 先验概率是很有指导意义的,不要有太多侥幸心理,虽然很多科学发现来源于失败的实验或意外,但总体而言,尽量不要把小概率事件作为实验的目标。
- **辩证法** 实验之前,考虑导致成功的因素有哪些,为什么成功,同时也要考虑导致失败的因素有哪些,为什么失败
- **逻辑知识** 同一个实验结果是否有其他解释,控制变量,充分和必要条件,三段论等
## 好习惯
- 良好的实验记录,由于实验需要进行非常多次(上百,上千),实验记录是非常必要的,并且实验记录可以很琐碎,最后阅读实验记录的也是程序。
- 预分析实验结果,在实验结果出来之前,先为每一种可能结果做预案,比如出现哪种结果说明什么,需要下一步进行什么实验。
- 关注实验过程,例如训练误差,校验集的变化,测试结果的变化,乃至各种中间变量,统计量的变化都值得关注,一个实验结果可能是偶然,但整个过程,各种变量都一致的偶然是十分罕见的,这也是一个检验程序正确性的好方法。