【从零开始的 NLP】理论篇 L1. 分类和向量空间

前言:为了整活好玩的东西,没有数学功底和深度学习经验的萌新开始学 NLP 了!
看的课程链接是这个:https://www.deeplearning.ai/natural-language-processing-specialization/
然后呢,大概会不定期更新一下学的过程中记下来的一些东西。顺便安利一下 Notion 这个笔记软件,实在是太好用啦。

Sentiment analysis 情感分析

任务:预测一个语句带有正面情绪 (positive, 1) 或负面情绪 (negative, 0)。

Vocabulary 词汇表

假设你有一个语句的集合 $S$,那么词汇表 (vocabulary) $V$ 包含了 $S$ 中的每个独立的单词。

示例:

$$V = {I, am, happy, because, learning, NLP, …, hated, the, movie}$$

Feature extraction 特征提取

方法一:稀疏表示 Sparse Representation

将一个句子 (tweet) 表征成一个向量 (vector). 例如,将一个句子中所出现的所有词汇,使用一个长度为 $|V|$ 的向量 $\vec{v}$ 表示;$\textbf{v}_i$ 为词汇表 $V$ 中第 $i$ 个元素的出现次数。

使用上述方法表征句子的特征时,向量 $\vec{v}$ 中会有大量的 0 元素,是一个 稀疏表示 (sparse representation)

稀疏表示带来了一些问题,如果使用此方法表示特征,则线性回归模型需要学习 $n+1$ 个参数 $\theta_0, \theta_1, …, \theta_n$ ($n = |V|$);当词汇表的数量 $|V|$ 很大时,将会产生更长的训练时间和更长的预测时间。

方法二:生成计数 Generate Count

假设标签分为两类:positive 和 negative.

定义词汇表中每个单词具有两个属性: PosFreqNegFreq,分别表示该单词在所有表达正面情绪的句子中出现的次数,和在负面情绪的句子中出现的次数。简而言之,

$$freqs = (word, class) ⇒ frequency.$$

接下来,将一个句子表征成一个具有 $c+1$ 个维度的向量($c$ 是分类的数量)。此时,线性回归模型不需要学习 $|V|$ 个特征,而只需要学习 $3$ 个特征。对于任意的句子 $m$,它的特征向量 $X_m$ 可以表示为:

$$X_m = [1, \sum_w freqs(w,1), \sum_w freqs(w, 0)]$$

解释一下上面这个向量表示,其中:

  • 第一维元素 1 表示 偏置(bias)
  • 第二维元素 $\sum_w freqs(w, 1)$ 表示词汇表中的每个词汇 $w$ 在正面情绪 (label=1) 的句子集合中出现的次数之和
  • 第三维元素 $\sum_w freqs(w, 0)$ 表示词汇表中的每个词汇 $w$ 在负面情绪 (label=0) 的句子集合中出现的次数之和

Preprocessing 预处理

1. 删除停顿词和标点符号

为了删除所有的停顿词(如 and, is, are, at …)和标点符号,需要有两个含有停顿词和标点符号的词汇。

但需要注意的是,有些时候并不一定需要删除标点符号,因为有些时候标点符号会为特定的 NLP 任务提供重要信息(如可能改变语义)。

2. 提取词干、转变为小写

提取词干 (Stemming):通俗地说就是将各种不同形式的词汇转化为原型,例如 tune, tuning, tuned,提取词干后会变成 tun. 提取词干后会使得词汇表中所包含的词汇减少。

为了减少词汇表中的单词数量,需要将词汇转变为小写。

Generate Feature Matrix 生成特征矩阵

假设语料库中有 $m$ 个句子,对所有的句子执行上述预处理操作,并将其表示为一个三维特征向量,最终会得到一个 $m \times 3$ 的 $X$ 矩阵。大体过程如下:

freqs = build_freqs(tweets, labels)    # build frequencies dictionary
X = np.zeros((m, 3))
for i in range(m):
		p_tweet = process_tweet(tweet[i])
    X[i,:] = extract_features(p_tweet, freqs)

Logistic Regression 逻辑回归

逻辑回归的过程示意图:

/assets/img/L1%207d289702a85f4ff1b8050a3d11256334/Untitled.png

函数 $F$ 是一个 $sigmoid$ 函数 (S 形生长曲线,将变量映射到 $[0, 1]$ 之间):

$$h(x^{(i)}, \theta) = \frac{1}{1 + e^{-\theta ^T x^{(i)}}}$$

其中 $\theta ^T x^{(i)}$ 是参数列向量 $\theta$ 转置后与第 $i$ 个句子的特征向量 $x^{(i)}$ 的乘积。

一般认为阈值为 0.5。

Training Logistic Regression Classifier 训练分类器

任务:不断迭代寻找使得代价函数最小的参数 $\theta_i$ 。

/assets/img/L1%207d289702a85f4ff1b8050a3d11256334/Untitled%201.png

左图为 $\theta_1, \theta_2$ 的不同取值下,代价函数的等高线(越靠近中心点,代价函数越小);

  • 首先取 $\theta_i$ 在任意一个点开始,得到 $h = h(X, \theta)$
  • 然后计算 $\theta_1, \theta_2$ 在该点的梯度 $\nabla = \frac{1}{m} X^T (h-y)$
  • 使用梯度更新参数 $\theta = \theta-\nabla$
  • 然后计算 loss (损失)函数 $J(\theta)$,重复上述步骤直到 $J(\theta)$ 足够好。

上述算法称为梯度下降法(收敛性证明可以看吴恩达的机器学习教程)。右图表示随着迭代次数增加,代价函数 Cost 将降低,且下降速度与梯度有关。

/assets/img/L1%207d289702a85f4ff1b8050a3d11256334/Untitled%202.png

Testing Logistic Regression 测试逻辑回归

验证集 (validate):$X{val}, Y{val}, \theta$

  • 首先计算参数为 $\theta$、自变量为 $X_{val}$ 的 $sigmoid$ 函数
  • 计算 $pred = (h(X_{val}, \theta) \ge 0.5)$,0.5 为阈值
  • 对比 $pred$ 和 $Y{val}$ ,计算准确率 (accuracy) = $\sum{i=1}^{|val|} \frac{(pred^i == y_{val}^{i})}{m}$

Cost Function 代价函数

代价函数可以表示为以下形式:

$$J(\theta) = -\frac{1}{m} \sum_{i=1}^m [y^{(i)} \log h(x^{(i)}, \theta) + (1 - y^{(i)}) \log (1 - h(x^{(i)}, \theta))]$$

其中 $m$ 是训练集中的句子个数 (size)。

可以看出代价函数 $J(\theta)$ 是对训练集中所有的句子计算某一个值,然后取平均值。负号的作用是让代价函数始终取非负数。

$y$ 的取值可能是 0 或 1,考虑第一项对代价函数的贡献:

  • 如果 $y^{(i)}$ 为 0,那么第一项无论 $h$ 取何值都为 0;
  • 如果 $y^{(i)}$ 为 1,且 $h$ 接近于 1,则第一项会趋近于 0;
  • 如果 $y^{(i)}$ 为 1,且 $h$ 接近于 0,则第一项中的对数会趋于 $-\infty$,从而使得第一项趋于 $-\infty$.

再考虑第二项对代价函数的贡献:

  • 如果 $y^{(i)}$ 为 1,则 $1-y^{(i)}$ 为 0,那么第二项无论 $h$ 取何值都为 0;
  • 如果 $y^{(i)}$ 为 0,且 $h$ 接近于 0,则第二项会趋近于 0;
  • 如果 $y^{(i)}$ 为 0,且 $h$ 接近于 1,则第二项中的对数会趋于 $-\infty$,从而使得第二项趋于 $-\infty$.