浅谈NLP预处理及WordEmbedding(Word2Vec,Glove等)

1. 文本预处理

1.1 分词器Tokenizer

Tokenizer 是一个用于向量化文本的类,这是一个分词的过程。英文分词,考虑空格;中文分词就复杂点。

keras.preprocessing.text.Tokenizer(num_words=None,
 filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n',
  lower=True,
  split=" ",
 char_level=False)

num_words:处理的最大单词数据量,若被设置为整数,则分词器将被限制为待处理数据集中最常见的num_words个单词;
char_level:若为True,每个字符被视为一个标记。

属性:
word_index: 字典,将单词(字符串)映射为它们的排名或者索引。仅在调用fit_on_texts之后设置。

Tokenizer几种方法应用:
包括训练fit_on_texts, texts_to_sequences,pad_sequences(将多个序列截断或补齐为相同长度。)

## some config values 
embed_size = 300 # how big is each word vector
max_features = None # how many unique words to use (i.e num rows in embedding vector)
maxlen = 72 # max number of words in a question to use #99.99%

## fill up the missing values
X = train["question_text"].fillna("_na_").values
X_test = test["question_text"].fillna("_na_").values

## Tokenize the sentences
tokenizer = Tokenizer(num_words=max_features)
tokenizer.fit_on_texts(list(X))

X = tokenizer.texts_to_sequences(X)
X_test = tokenizer.texts_to_sequences(X_test)

## Pad the sentences 
X = pad_sequences(X, maxlen=maxlen)
X_test = pad_sequences(X_test, maxlen=maxlen)

## Get the target values
Y = train['target'].values

sub = test[['qid']]

关于OOV(out of value)的处理:

>> num_words = 3
>> tk = kpt.Tokenizer(oov_token='UNK', num_words=num_words+1)
>> texts = ["my name is far faraway asdasd", "my name is","your name is"]
>> tk.fit_on_texts(texts)
>> print(tk.word_index)
>> print(tk.texts_to_sequences(texts))
>> ## **Key Step**
>> tk.word_index = {e:i for e,i in tk.word_index.items() if i <= num_words} # <= because tokenizer is 1 indexed
>> tk.word_index[tk.oov_token] = num_words + 1
>> print(tk.word_index)
>> print(tk.texts_to_sequences(texts))
{'your': 7, 'my': 3, 'name': 1, 'far': 4, 'faraway': 5, 'is': 2, 'UNK': 8, 'asdasd': 6} 
[[3, 1, 2], [3, 1, 2], [1, 2]]  ## Wrong Behavior. Should not drop OOVs
{'name': 1, 'my': 3, 'is': 2, 'UNK': 4}
[[3, 1, 2, 4, 4, 4], [3, 1, 2], [4, 1, 2]] ## Correct behavior

2. Word Embedding

词向量(Word Embedding),或者词嵌入,就是把词使用向量来表示。
在这里插入图片描述
这里把,Embedding 分成 tf-idf(稀疏向量表示) 和 稠密向量表示。把单词用稠密向量(dense vectors)表示的方法有 NNLM, Word2vec, GloVe等方法。

tfidf 介绍看这;

这里,对用稠密向量表示单词的工具进行分类:
(1)基于预测模型
代表: googlenews, Word2Vec

(2) 基于统计单词频率模型
例如:GloVe。

2.1 NNLM

初期的prediction-based模型/神经网络语言模型(NNLM)
在这里插入图片描述
在这里神经网络的输入是前一个单词 w i − 1 w_{i−1} wi1的词向量( 1-of-N Encoding )形式,经过神将网络他的输出是下一个出现的单词 w i w_i wi 是某一个词的几率,拟合目标是真实的 w i w_i wionehot向量。因为是 1-of-N Encoding 形式,所以输出的每一维代表是某一个词的概率。然后取输入层的权值输入作为词向量。

假如知道语料有 N 个不同的单词,每个单词经过 one-hot N N N维向量.
NNLM的输入是 w t − 1 w_{t-1} wt1的onehot 向量,目标是它下一时刻单词 w t w_t wt的onehot向量。
所以,输入层,输出层的节点个数都是 N。经过训练后,输出层代表 w t − 1 w_{t-1} wt1下一个单词是语料中对应索引单词的概率。
图中, z z z 是隐层,或者Embedding层,节点数远比N要小。我们把所有连接到 w 1 w_1 w1 非零的节点的权重值当作一个向量,也就是隐层 z z z,当做输入单词 w t − 1 w_{t-1} wt1或者 w t w_t wt的词向量, 这里把隐层向量 z z z当做 w t w_t wt 的词向量了。

改进的NNLM模型
在这里插入图片描述
既然可以用前面的一个 w t − 1 w_{t-1} wt1来预测后一个 w t w_t wt,我们也可以用多个前面的单词,比如, w t − n + 1 , . . . , w t − 1 w_{t-n+1},...,w_{t-1} wtn+1,...,wt1 来预测后面的单词 w t w_t wt
用到的技巧是,把输入的单词 w t − 1 w_{t-1} wt1的onehot向量乘于一个随机的Q矩阵,得到 C ( W t − 1 ) C(W_{t-1}) C(Wt1),然后,把他们拼接,最后,输出为下一个单词 w t w_t wt为词料中某个单词的概率。训练后的Q矩阵的每一行就是相应单词的词向量。

2.2 Word2vec

word2vec 是 google 在2013年提出 NLP 模型,它的特点是将所有的词表示成低维稠密向量,从而可以在词向量空间上定性衡量词与词之间的相似性。

onehot ,使用0-1来对字符串编码,也是word2vec,但是有个缺点,如果出现的不同的字符串个数很多,那么维度就很大。
因此,我们引入表。
在这里插入图片描述
中间W 矩阵,相当于一个表,行维度应该包含输入输入内容的所有元素个数,比如一定领域的汉字作为输入,这个表的行数可能就上万了。 W矩阵,可以看成一个全连接神经网络层,也就是所谓的 Embedding层。
一旦训练好embedding层,把text 转化为向量后,获得 index 矩阵,直接查表,就可以获得word embedding了。

示例:
一般把分词后padding 的数据作为Word2vec模型的输入。
TensorFlow/Keras模型Embedding Layer参数:

tf.keras.layers.Embedding(
    input_dim,
    output_dim,
    embeddings_initializer="uniform",
    embeddings_regularizer=None,
    activity_regularizer=None,
    embeddings_constraint=None,
    mask_zero=False,
    input_length=None,
    **kwargs
)

定义Embedding Layer:

model = Sequential()
model.add(Embedding(1000, 64, input_length=10))
# 模型将输入一个大小为 (batch, input_length) 的整数矩阵。
# 输入中最大的整数(即词索引)不应该大于 999 (词汇表大小)
# 现在 model.output_shape == (None, 10, 64),其中 None 是 batch 的维度。
input_array = np.random.randint(1000, size=(32, 10))
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
assert output_array.shape == (32, 10, 64)

除了使用模型进行训练之外,还可以使用一些已经训练好的词向量,只需要找到你文本里边的词对应的index加载即可。开源的词向量有word2vec api.

Keras载入已经训练好的Embedding矩阵emb

emb_layer = Embedding(input_dim=emb1.shape[0],output_dim=emb.shape[1],
weights=[emb],input_length=90,trainable=False)

注意:这里weights参数是Keras Layer的参数,Embedding 层是Layer的子类。

关于网络训练问题:

严格来讲,神经网络都是有监督的,而Word2Vec之类的模型,准确来说应该是“自监督”的,它事实上训练了一个语言模型,通过语言模型来获取词向量。所谓语言模型,就是通过前nn个字预测下一个字的概率,就是一个多分类器而已,我们输入one hot,然后连接一个全连接层,然后再连接若干个层,最后接一个softmax分类器,就可以得到语言模型了,然后将大批量文本输入训练就行了,最后得到第一个全连接层的参数,就是字、词向量表,当然,Word2Vec还做了大量的简化,但是那都是在语言模型本身做的简化,它的第一层还是全连接层,全连接层的参数就是字、词向量表。

这样看,问题就比较简单了,我也没必要一定要用语言模型来训练向量吧?对呀,你可以用其他任务,比如文本情感分类任务来有监督训练。因为都已经说了,就是一个全连接层而已,后面接什么,当然自己决定。当然,由于标签数据一般不会很多,因此这样容易过拟合,因此一般先用大规模语料无监督训练字、词向量,降低过拟合风险。注意,降低过拟合风险的原因是可以使用无标签语料预训练词向量出来(无标签语料可以很大,语料足够大就不会有过拟合风险),跟词向量无关,词向量就是一层待训练参数,有什么本事降低过拟合风险?

Word2Vec两种实现
Word2Vec和NNLM类似,但做了一些改变,实现有 CBOW(Continuous Bags of Words Model)和Skip-Gram(Continuous Skip-gram model)。
在这里插入图片描述
首先,CBOW 在NNLM的基础上,引入了下文单词 w t + 1 , . . . , w t + n w_{t+1},...,w_{t+n} wt+1,...,wt+n
Skip-gram 则和CBOW相反,它输入是当前时刻单词 w t w_t wt,输出是它临近各个时刻 . . . , w t − 1 , w t + 1 , . . . ...,w_{t-1}, w_{t+1},... ...,wt1,wt+1,...是哪几个单词的概率,拟合的目标就是 w t w_t wt附近这些时刻 . . . , w t − 1 , w t + 1 , . . . ...,w_{t-1}, w_{t+1},... ...,wt1,wt+1,...的onehot向量拼接成的大向量。

2.3 GLOVE模型

Word2Vec 之后又有GloVe 模型产生。

GloVe模型主要思路如下图所示 :
在这里插入图片描述
两词向量共同出现的频率比较高的话,那么这两个词向量也应该比较相似。所以两个词向量的点积应该与它们公共出现的次数成正比.

GloVe模型公式:
代价函数:
J = ∑ i , j N f ( X i , j ) ( v i T v j + b i + b j − log ⁡ ( X i , j ) ) 2 J=\sum_{i, j}^{N} f\left(X_{i, j}\right)\left(v_{i}^{T} v_{j}+b_{i}+b_{j}-\log \left(X_{i, j}\right)\right)^{2} J=i,jNf(Xi,j)(viTvj+bi+bjlog(Xi,j))2

v i , v j v_{i}, v_{j} vi,vj是单词 i i i和单词 j j j的词向量, b i , b j b_{i}, b_{j} bi,bj是两个标量(偏差项), f f f是权重函数(具体函数公式及功能下一节介绍), N N N是词汇表的大小(共现矩阵维度为 N ∗ N N*N NN), X i , j X_{i,j} Xi,j是共现矩阵。。
可以看到,GloVe模型没有使用神经网络的方法

具体权重函数, 首先应该是非减的,其次当词频过高时,权重不应过分增大,作者通过实验确定权重函数为:

f ( x ) = { ( x / x max ⁡ ) 0.75 ,  if  x < x max ⁡ 1 ,  if  x > = x max ⁡ f(x)=\left\{\begin{array}{ll}{(x / x \max )^{0.75},} & {\text { if } x<x \max } \\ {1,} & {\text { if } x>=x \max }\end{array}\right. f(x)={(x/xmax)0.75,1, if x<xmax if x>=xmax

2.4 paragram

释义数据库PPDB(the Paraphrase Database)来学习通用的sentence embeddings
论文模型的基本流程是输入mini-batch的释义对 ( < x 1 , x 2 > ) (<x_1, x_2>) (<x1,x2>)集合 ( X b ) (X_b) (Xb),并通过对\(X_b\)中的句子进行采样得到\(x_1,x_2\)对应的负样本\(t_1, t_2\),将这四个句子通过编码器(编码函数)\(g\)得到句子编码,然后使用一种 margin-based loss进行优化,损失函数的基本思想是希望编码后的释义对\(<x_1,x_2>\)能够非常相近而非释义对\(<x_1,t_1>\)\(<x_2,t_2>\)能够有不小于\(\delta\)的间距。

在这里插入图片描述
原论文

2.5 wiki news

在这里插入图片描述
wiki news 训练加入子词信息,n_gram对单词进行提取信息。

2.6 随机Embedding

如果没有训练好的语料,Embedding层先用随机的Vector来代替。

import torch.nn as nn
import torch 

embedding_size = 10
max_idx = 10000
embedding = nn.Embedding(max_idx, embedding_size, padding_idx=0)
input = np.array([7788, 9992, 9999])
embedding(torch.LongTensor(input))

结果:

tensor([[-0.6454,  1.0659,  0.8753,  0.0054, -0.8724,  0.7973,  0.1209, -0.2043,
          0.1764,  0.0975],
        [-0.8743,  1.6775,  0.5449,  0.1142,  0.8465,  1.6576,  0.3122, -0.4616,
          1.0896,  2.5375],
        [ 1.4861, -1.5820,  1.0397,  0.0299, -0.5425, -0.0418,  0.0634,  1.2271,
          0.0850,  0.0540]], grad_fn=<EmbeddingBackward>)
2.7 小结: GloVe模型和Word2Vec模型区别

区别:

两者最直观的区别在于,word2vec是predictive的模型,而GloVe是count-based模型。

不采用 negative sampling 的word2vec 速度非常快,但是准确率仅有57.4%。只告诉模型什么是有关的,却不告诉它什么是无关的,模型很难对无关的词进行惩罚从而提高自己的准确率.
在python的gensim这个包里,gensim.models.word2vec. Word2Vec默认是不开启negative sampling的,需要开启的话请设置negative参数,如何设置文档中有明确说明gensim: models.word2vec. 当使用了negative sampling之后,为了将准确率提高到68.3%,word2vec就需要花较长的时间了(8h38m)

相比于word2vec,因为golve更容易并行化,所以速度更快,达到67.1%的准确率,只需要花4h12m。

由于GloVe算法本身使用了全局信息,自然内存费的也就多一些,相比之下,word2vec在这方面节省了很多资源.

3. 总结

NLP对文本数据处理有两种:
1、词袋模型
其中,词袋模型又可以分成3种,tfidf、CountVector、HashVector。
2、词向量方法
其中,词向量分为onehot、常见的Word2Vec;word2vec根据上下文推中间文字,或者根据中间文字推上下文;其中,对于句子,目前一些模型,如fastrnn, 使用句子单词的词向量求和作为输入。
目前,处理文本思路有 RNN(把词向量作为输入);CNN、Attention三种。


reference:

  1. towardsdatascience :A non-nlp application of word2vec;
  2. (推荐)Keras Tokenizer 介绍
  3. bojone: 词向量与embedding;
  4. keras: embedding层
  5. cs124 pdf CS 124/LINGUIST 180 From Languages to Information ;
  6. github :awesome embedding
  7. 论文: wiki news model, Advances in Pre-Training Distributed Word Representations;
  8. csdn: blog 无监督学习:词嵌入
  9. csdn :理解GloVe模型(Global vectors for word representation);
  10. github: glove简单pytorch代码实现 ;
  11. blog :nlp面经;
  12. 知乎: [NLP] 秒懂词向量Word2vec的本质
  13. CNblog: NLP之Word2Vec详解;
  14. cloudTencent :将句子表示为向量(下):基于监督学习的句子表示学习(sentence embedding)
  15. 知乎: 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史
  16. Using Tokenizer with num_words;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rosefunR

你的赞赏是我创作的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值