一、分词
大小写转换、分词、标点符号处理
二、文档矢量表示
文档分词之后,对词进行表示就可以得到文档矢量,主要有两种不同的表示方式:onehot矢量和词袋矢量。
使用onehot矢量表示词,每个文档就是一个
m
×
n
m \times n
m×n的矩阵,其中m为词的个数,n为词表的大小,这时通过该矩阵也能同样还原文档,是一种无损失的表示形式,但对存储空间要求大。
词袋矢量表示文档相当于把onehot矩阵按行累加,为一个
1
×
n
1\times n
1×n的矢量,每一列为词表中该词出现的次数,这样做的好处是节省了存储空间,但通过这个矢量无法完全还原文档中各词的先后顺序,是一种有损的表示形式。
在词袋模型的基础上,将一个文档中的每个词都用TF-IDF重要度进行表示时,将这个矢量称为文档的TF-IDF矢量表示。
基于文档的词袋模型和TF-IDF模型,可以对文档进行降维操作:如LSA/PCA,获得每个词的主题向量,从而整个文档的主题向量为多个词的主题向量之和。这种降维方式能够去除文档中的噪声,将经常同时出现的词归为同一主题,对一义多词的场景有很好的应用。
三、深度学习
3.1 word2vec
3.1.1 word2vec与LSA
获得词向量的方式:
算法 | 训练方式 | 词袋空间 |
---|---|---|
LSA | SVD分解得到主题向量,是一种非监督的方式 | 整个文档空间 |
传统神经网络 | 监督学习,输入为文档的TF-IDF向量,输出为label | 整个文档空间 |
word2vec | 非监督学习,通过词的上下文进行训练 | 词袋空间可自行定义 |
- LSA和word2vec都是非监督的方式获取词向量,其两者的不同在于?
LSA也可以把词语用主题向量进行表示,从而对词语降维,但LSA的词袋是整个文档空间,但word2vec可以通过滑动窗口的大小控制词袋空间,一般控制在5个以内,因为有滑动窗口的存在,每个词能够使用的次数更多。
Topic vectors constructed from entire documents using LSA are great for document classification, semantic search, and clustering. But the topic-word vectors that LSA produces aren’t accurate enough to be used for semantic reasoning or classification and clustering of short phrases or compound words.
使用LSA提取主题向量的方式更适合于文档分类,语义检索和聚类,但用在语义推理,短语或复合词的分类和聚类方面就不够准确了。
LSA训练比word2vec快,且更适合长文档的分类和聚类;
word2vec在大语料库上更加高效,且对词向量的刻画更加精确,在做语义推理/类比时尤其明显。【“哈利·波特+大学=霍格沃茨”】LSA要做到这种效果的话必须使用将长文档切成短语进行训练。
- word2vec与传统神经网络的区别?
在没有word2vec之前,使用神经网络得到词的向量表示需要把文档的TF-IDF向量表示作为输入,label作为输出,即使用监督学习的方式得到词向量用于分类任务。
而word2vec得到词向量的方式是一种非监督学习,不需要人工标注。 - 为什么要使用词向量呢?
词向量可以用于推理和类比,例如武汉之于湖北等同于**之余湖南,通过词向量可以得到是长沙。
另外,使用词向量可以在建模和可视化方面都可以提升NLP任务的准确度。
获取word2vec的具体算法有两种:skip-grams和CBOW。
- skipgram
- cbow(CONTINUOUS BAG-OF-WORDS)
sentence = “Claude Monet painted the Grand Canal of Venice in 1806.”
输入 | 输出 | 训练方式 | |
---|---|---|---|
skipgram | 中间词的onehot | 临近词的onehot | 如果是5-grams的话,对每一个中间词都迭代4次 ,例如painted–>Claude, painted–>Monet, painted–>the, painted–>Grand |
CBOW | 临近词的onehot向量加和 | 中间词的onehot | 对5-grams而言,只需要迭代一次,Claude,Monet,the,Grand–> painted |
- 如何选择skip-gram和cbow?
skip-gram方法适用于小型语料库或者专业术语中,因为使用这种方式可以得到更多的训练数据,例如在5-grams中可以得到4个训练对。但使用cbow方法可以对出现频次较高的词提高精度,并且训练速度更快。
3.1.2 Glove and fastText
另外还有两种得到词向量的预训练的模型:Glove和fastText。Glove:direct optimization of the global vectors of word co-occurrences。
- Glove 与 word2vec
Glove训练速度更快,但达到与word2vec一样的精度。原因在于,word2vec的神经网络结构必须使用backpropagation反向传播进行参数迭代,而Glove可以使用更成熟的优化算法,例如SVD分解。另外,Glove在较小的语料库上也可以收敛。现在更多使用的是Glove。
Glove的优点:
- 训练速度更快
- RAM/CPU效率更高,能够处理更长的文档
- 对数据的使用更加充分,在小语料库上表现高
- 同样训练次数下精度更高
- fastText
fastText 相比于 word2vec, 在临近词的基础上加上了n-character grams,这使得它处理稀有词好得多。google公布了294种语言的已训练好的fastText模型,词库为wiki库。
词向量与训练语料相关,当语料带有偏见时,训练出的词向量也是带有偏见的。
例如,计算
word_model.distance(‘man’, ‘nurse’) # 0.7453
word_model.distance(‘woman’, ‘nurse’) # 0.5586
词向量认为护士这个词就偏向于与女性的距离更近。修正这种偏见也是词向量面临的一大挑战。
3.1.3 Doc2vec
doc2vec的学习方式与word2vec非常相似,仅仅是在输入上有所不同,对于skip-gram而言,它的输入不仅仅是临近词,还包含了这个文档的ID,因此训练出来的文档ID对应的向量就是文档向量。
文档得到矢量表示之后,就可以去做相似度计算或者聚类操作。
3.2 CNNs
前一节我们学习了词的矢量表示word2vec,但语言真正的妙处不是词语本身的含义,而是词语的组合和词序。这一节我们将学习如何发现句子隐含的意思。
使用python来实现神经网络是比较流行的一种处理方式。其中,Lasagne (Theano) and Skflow (TensorFlow) 更多被使用,但文本采用的是Keras,它可以使用Theano和TensorFlow作为底层实现,本文中采用的是TensorFlow。
CNN参数:
- stride/ step size: 滑动步长,需要设置为一个>=1的整数。
- padding:valid or same。前者导致输出size小于输入,例如输入为55,经过stride=1,kernel_size=33的卷积操作后,输出大小为3*3。后者会对原图边界用0补充,使输出大小和输入相同。
- filters : 卷积神经元的个数
CNN应用在图片领域时,卷积神经元是一个二维矩阵,当应用在文本领域时,卷积神经元应该是一维矩阵。当文本中每个词用词矢量表示时,卷积神经元的宽度应该与词矢量一致,而长度可以作为超参数设置。下图很好地展示了用词矢量作为输入时卷积神经元的表示。
备注:这里的“一维矩阵”的含义是指卷积核只能横向移动,即一维方向移动,但实际上,当输入用embedding的word vector表示时,卷积核是一个二维矩阵。conv1D
CNN应用在图片领域时,pooling窗口是一个二维矩阵,对经过卷积核的输出数据进行pooling操作,在文本处理中,pooling窗口为一维,方式有两种:average 或者 max,后者使用的更多些。GlobalMaxPooling1D
- 为什么可以用CNN网络来处理NLP问题呢?
CNN就是一个超级N-Gram,而N-Gram就是考虑局部统计信息的语言模型,CNN相当于在低维向量空间中实现了它。如果局部相关性存在,就可以使用CNN
3.3 RNN
使用CNN处理文本时存在的问题:
- CNN只能提取局部信息,当句子中的词相隔太远时,无法对词语含义进行组合考虑。如果只是将窗口取的太大,则又使语义模糊。
不同于CNN一次性输入全部文本的方式all at once,RNN 采用的文本输入方式是一次输入一个词 one at a time,前一个词的output也作为后一个词的input,最后的output才是整句话的label。
CNN | RNN | |
---|---|---|
输入 | 一次性输入所有文本,且文本需要固定长度maxlen(maxlen, embedding_dim) | 每次输入一个token, 长度为embedding_dim,+上一次输出神经元个数neurons |
输出 | 一个输出 | 每个token都有一个输出 |
参数个数 | 一般来说比较多,跟卷积核个数相关 | 一般来说少一些,因为多个token公用一个网络参数 |
3.4 LSTM(long short-term memory)
RNN和CNN在处理文本问题时遇到的一个问题就是,当词语之间距离较远时,模型并不能很好的学习到词语间的含义。例如对下文中第1个语句,RNN和CNN都可以学习到woman 和went之间的主谓关系,但第2个句子中,因为woman和went之间的距离比较远,对RNN和CNN就是一个挑战了。在使用RNN时,当输入went时,woman这个词的影响就衰落的比较严重了,这个时候,我们希望能够有一种网络结构能够“记住”过去所有的输入。LSTM就是这样一种神经网络结构。
1 The young woman went to the movies with her friends.
2 The young woman, having found a free ticket on the ground, went to the movies.
GRU(gated recurrent unit)在LSTM的基础上进行了改进,能够同时记住长期和短期的输入信息,使之处理句子和文档的能力更强。目前在NLP,时间序列和离散序列的处理中,LSTM基本已经取代了RNN。
LSTM的输入和输出与RNN相同,不同的是,LSTM多了一个记忆单元存储数据 C t C_t Ct。能够减少梯度消失和梯度爆炸的问题。
数据处理
对神经网络来说,输入为每个token的embedding vector,如果有些词的embedding矢量在库中没有找到应该怎么办?
常见的处理方式是直接丢掉这个词,大多数情况下,这种方式是可用的,但是如果是在,I don’t like this movie 句子中,don’t这个词没有对应的embedding矢量而直接丢掉这个词的话,句意效果将会完全不同。
一般对这种词,业界有两种比较认同的处理方式:1.在已有矢量词中随机挑选一个矢量来替代这个未知矢量词,但这种方式会导致句意不可读;2.将这种词用‘UNK’
3.5 sequence-to-sequence models and attention
应用场景:文本翻译
模型结构:encoder-decoder,encoder将输入(文本)转化为向量表示,decoder将向量表示转化为文本输出。
encoder结构可以通过LSTM来构造,每一时刻的输入为当前时刻输入xt和上一时刻输出at-1,最后时刻的输出也是一个矢量;
decoder结构如果复用LSTM来构造,每一时刻的输入为上一时刻输出和当前文本输入,则无法解决输入和输出长度不一致的问题。
thought vector指的是神经网络对输入文本的转化向量。因为decoder不能直接复用encoder的LSTM结构,因此需要重新构造一个LSTM作为单独的decoder。seq2seq的思路就是用一个encoder将文本转换为向量,然后再构造一个decoder,将向量转换为文本。