前言
最近要使用NLP的知识,所以边学习边总结一下自然语言处理中常用的算法,本笔记主要来源于油管shusengwang的视频,链接在此:https://www.youtube.com/watch?v=NWcShtqr8kc&list=PLvOO0btloRnuTUGN4XqO85eKPeFSZsEqK
一、文本数据处理基础
1.1、数字特征和分类特征
文字数据具有数字特征和分类特征,机器学习只能理解数字特征,而无法理解分类特征,为了让计算机能够处理带有分类特征信息的文字,就必须要讲其分类特征转换成数字特征。举个例子:
在上面这张图中,“age”一栏中表示的是数字特征,不用处理。“gender”和“nationality”一栏中的数据具有分类特征。这时需要将其变为数字特征。我们使用one-hot向量来表示文字的分类特征,而不是使用简单的1,2,3…数字来表示,原因是1代表的文字和2代表的文字相加不得3代表的文字信息,而使用one-hot向量相加确比较合理
使用one-hot方法我们可以表示:
US 为[1,0,0…];
China 为 [0,1,0…];
India 为 [0,0,1…]。
这样第一行文字信息可以使用向量 [35,1,1,0,0…]表示,第三行信息可以使用向量 [29,0,0,0,1…]表示。(如果“nationality”为空,我们可以使用全零向量表示)
1.2、文本处理步骤
1.2.1、分割(Tokenization:文本—>单词/字母)
分割就是将一句话分解成一个个单词或者一个个字母,为了方便讲解我们以分割成单词讲述。
1.2.2、one-hot编码
此时是使用字典统计一下各个单词在整个文本中所出现过的次数,使用key记录文字,使用value记录单词出现的次数。
然后按照词频递减的顺序排列,即表最前是出现频率最高的,表最后的单词是出现频率最低的。接着将字典的value部分按顺序从上到下使用索引1,2,3…填充,即每个单词可以使用一个数字表示(如下图)。整个字典的长度就是词汇量,也等于one-hot向量的长度。这样处理的目的就是保留常用词,去掉低频词,删除词汇量尾部的词可以排除拼写错误的单词或者人名等单词,最主要的原因还是降低one-hot向量的长度,以此加快计算速度。
删除词汇量中词频低的数据会造成有一部分单词在词汇量中找不到,在处理时可以把他们直接不处理或者使用全零向量填充。
1.2.3、词嵌入(word embedding)
-
先统一长度(多删少补):一般文字信息处理后使用矩阵表示,这就要求文字长度必须对齐,所以如果待处理 的文字长度大于指定长度,就省略前面或者后面;如果长度小于指定长度,就使用 空格补全。
-
然后做词嵌入:将每个单词的高维one-hot向量映射到低维连续向量中,如
cat: (-0.065, -0.035, 0.019, -0.026, 0.085,…)
**dog**: (-0.019, -0.076, 0.044, 0.021,0.095,…)
词嵌入同时使相似词映射到相似方向(语义相似性被编码了)算是优点之一。
如上图所示,e为one-hot向量,P为参数矩阵,x为转换后的词向量,其实也可以看出P矩阵中每一列都是一个词向量,维度d为词嵌入的维度,由人工设定;维度v为词汇量
1.2.4、使用网络模型学习:
神经网络输入的数据都是词向量,而不是单纯的one-hot表示的文本信息。所以接下来我们主要讲解主要的网络模型。
二、RNN(循环神经网络)
2.1、Simple RNN
2.1.1、简介
循环神经网络类似人类阅读一样,一次输入一个单词,然后不停的循环输入单词,直到整个句子结束,适用于处理文本、语音等带有时序序列信息的数据。RNN的网络结构如下图所示:首先将一个文字经过词嵌入处理转换成向量x,然后传入给神经网络参数矩阵A,输出状态向量h。接着在输入下一个文字数据…,如此反复的循环处理文字便是RNN的主要思想。其中每个输出状态h仅包含前面所有单词的信息,最后的输出状态h则包含整个句子的信息。注意整个RNN只有一个参数矩阵A,右边的是将左边网络的展开。
其中参数矩阵A的现状如下图所示,最后使用双曲正切函数tanh将参数规整到[-1,1]之间,使用该函数是为了避免矩阵参数过大或过小。
矩阵参数的数量为:输出状态h和词向量x的维度均为人工设置。
Simple RNN可以选择只输出最后一个状态向量ht,也可以选择输出所有的状态向量h。
2.1.2、缺点
Simple RNN适合处理简短的文字信息,对于较长文字输入时,该模型在深层次求导(反向传播)时会遇到梯度消失,所以会遗忘之前的文字信息,就像鱼一样只要7秒记忆。
2.2、LSTM(long short-term memory)
该模型相比于Simple RNN可以有效避免梯度消失,延长’‘记忆’’。它和Simple RNN的结构区别如下图所示:LSTM使用"传输带C"的方法避免梯度消失从而避免过早遗忘的问题。
LSTM同时使用各种”门“来有选择的对数据进行处理;主要有”遗忘门“、”输入门“、”输出门“和一个”new value“。下面一一讲解:
2.2.1、遗忘门
如图所示,遗忘门使用上一个状态h和当前词向量x作为输入,处理过程和Simple RNN一样,使用一个神经网络参数矩阵W记录信息,输出使用开关函数 σ 处理后输出 f(f 的参数在[0,1]之间);最后将输出 f 向量与传输带C矩阵做点乘,达到选择性记忆和遗忘的功能。
2.2.2、输入门
输入门将上一状态 h 和当前输入词向量 x 连接后经过 σ 开关函数后输出 i
2.2.3、New Value
此外,将前一状态 h 和当前数据 x 链接后使用 tanh 函数处理输出向量 c ;
然后对传输带进行计算,传输带总输出为: f × C + i × c
2.2.4、输出门
输出门使用 σ 开关函数连接上一状态输出 h 和当前输入 x 得到向量 o
然后对传送带向量 C 先做 tanh 处理再与输出门点乘得到最新的状态输出 h 。
2.2.5、参数量
一共有四个参数矩阵,每个矩阵的形状均一致,如下图所示:
2.3、多层RNN(Stacked RNN)
类似于搭建CNN,RNN的搭建也可以使用多层,值得注意的是:**只有最后一层可以选择不输出所有的状态h,只有当对整个句子处理完再输出即可;**而其他层均必须输出每次的状态h以传输给下一层网络。
2.4、双向RNN(Bi RNN)
无论是Simple RNN 还是LSTM,都会或多或少的产生遗忘的问题。为了再次降低过早遗忘,又诞生出了双向RNN,设计结构如下图所示:
三、基于RNN做文本生成
3.1、简介
文本生成简单理解就是事先使用RNN对大量的文本信息进行学习,然后使用一小段固定长度的文本作为开头,循环输入进RNN中,使RNN能够持续预测下一个单词或字母,最后完成整段文本信息的输出。
文本生成的原理还属于监督学习,所以文本生成的风格完全取决于训练数据的风格。
3.2、准备训练数据
在给定的一段文本训练数据,可以将其按单词进行分割,也可以按字符进行分割,为了使词汇量较小,一般使用字符进行分割、使用两个列表分别存储文本片段(segment)和下一个字符(next_char)。举个例子如下图所示:其中步长为3。
接着使用第一章讲的方法将字符转成one-hot向量,注意这里不需要将one-hot向量再转为低维度的词向量,因为这里的词汇量本身不大(包括字符、空格、标点符号等最多一百左右)。接着上边的例子的参数数量如下图所示:词汇量为57,segment长度为60,取步长为3则总共的 segment 数量大概为20万左右。所以输入数据的格式为 [60,57],输出数据格式为 [57,1]。
3.3、网络搭建
基于keras使用LSTM模型搭建神经网络,网络的各项参数设置如下图所示:
3.4、网络预测
在网络预测下一个单词时可以使用不同的选择方案,这里主要说三个。
- 第一个是使用完全贪婪策略,每次直接选择softmax概率最大的预测单词作为输出,这中方案会缺少随机性,导致后续的输出完全取决于最开始的输入,所以效果不太好。
- 第二种方案是使用依概率随机的方案进行选择下一个单词,这样导致随机性可能过大,如果使用字符分割的方案会导致输出很多错误的单词,所以也不是太推荐。
- 第三种方案就是综合上面两种方案的思路,使预测在贪婪和随机之间取一个折中值,使用一个温度超参数([0,1])来设置折中程度。这样原本大的概率会变大,小的概率值会变的更小一些。具体方法是先对预测概率进行下图中得处理后再依概率随机选择。
四、机器翻译(仅使用Seq2Seq模型)
机器翻译的方法有很多种,我们这里只介绍sequence-to-sequence模型,做机器翻译和文本生成是不一样的,因为两种语言不管用字符分割(char_level)还是单词分割(word_level),他们的词汇表都是不一样的,所以必须使用两个词汇表分别存储各自的词汇表。(实际上机器翻译大多使用单词分割)
4.1、创建词汇表(分割)
为了方便讲述,使用字符分割(实际应用上却不是)。值得注意的是,目标语言(要翻译的语言)需要在字典中额外加入一个起始符号和一个终止符号(具体符号随意设置,不和词汇表中其他单词重复即可),以英语(源语言)翻译成德语(目标语言)为例,词汇表如下图所示:
然后使用one-hot向量表示各自词汇表中的字符,这样一个单词/句子使用一个one-hot矩阵表示。
4.2、模型搭建及训练
该模型由一个编码器(encoder)和一个解码器(decoder)组成,网络结构如下图所示:其中encoder传给decoder的信息是最后的状态,即整个句子的完整信息。decoder其实就是上面讲的文本生成器,唯一不同的就是它使用encoder的输出最后文本生成的开头信息。decoder使用encoder的英语输入信息和当前的德语单词预测下一个德语的输出单词 p ,然后使用德语数据标签 y 计算二者的损失函数,不断重复这个过程以此完成监督学习。
使用源语言文本和目标语言文本作为训练数据完成训练后,即可使用相同过程进行预测完成机器翻译。
4.3、网络改进
4.3.1、双向LSTM
如果文本信息过长, encoder在采集源语言文本时会产生一定的遗忘,这是decoder怎样改进都无法提高准确率的。为了降低遗忘,可以仅在encoder中使用双向LSTM模型。(decoder是无法使用双向LSTM的),但只能减少遗忘概率,而无法彻底避免。
4.3.2、使用attention模型
详细请见下一章
五、Attention
Attention 模型可以用在所有的 RNN 上,下面将attention分别用在Seq2Seq和Simple RNN上。
5.1、Seq2Seq+Attention
无论使用多层RNN还是双向RNN等或多或少都还是存在遗忘问题,为例避免遗忘,新的attention模型
诞生了。在Seq2Seq模型中,传统的encoder只将最后的输出h传给decoder,而新网络将每次输出加上权重c,让网络自己学习权重,进而避免遗忘问题。(可以理解为decoder输出时每次都会再看一遍encoder,并且知道关注encoder哪个状态输出)其网络结构中的权重如下图所示:
关于 α 的计算方法有很多,方法一如下图所示:值得注意得是矩阵 V 和 W 均为网络参数,由网络训练得到。
方法二:使用两个参数矩阵单独对 h 和 s 处理,然后再做乘积,最后做 softmax 。
求完权重后,做下图所示处理:其中 c 包含 encoder 的全部完整信息,这样decoder就知道encoder全部信息了,就不存在遗忘的问题。
之后将 c、s、和当前输入 x 连接后输出下一个状态s,注意:每次计算 s 时的 α 都需要重新计算的
- 缺点:参数巨大,耗时巨大。时间复杂度对比如下图:
5.2、Simple+self-Attention
加入 self-Attention 模型的 Simple RNN 仅是将每次的连接矩阵由h变为c:如下图所示:
参数 α 的计算方法和上一节的一致,以此不停的循环即可完成左右的输出。