NLP系列——(4)文本表示

文本表示

    • 1、文本表示
    • 2、 文本表示的方法
      • 2.1 one-hot表示
      • 2.2 word2vec
        • 2.2.1 CBOW
        • 2.2.2 Skip-Gram

1、文本表示

文本表示的意思是把字词处理成向量或矩阵,以便计算机能进行处理。文本表示是自然语言处理的开始环节。

文本表示按照细粒度划分,一般可分为字级别、词语级别和句子级别的文本表示。

文本表示分为离散表示分布式表示。离散表示的代表就是词袋模型,one-hot(也叫独热编码)、TF-IDF、n-gram都可以看作是词袋模型。分布式表示也叫做词嵌入(word embedding),经典模型是word2vec,还包括后来的Glove、ELMO、GPT和最近很火的BERT。

  1. 词袋模型:离散、高维、稀疏
    1)One-Hot Encoding:
    独热编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都有它独立的寄存器位,并且在任意时候,其中只有一位有效。
    本质上是用一个只含一个 1、其他都是 0 的向量来唯一表示词语。
    2)TF-IDF:https://blog.csdn.net/xh999bai/article/details/89287016
    3)n-gram:n-gram是从一个句子中提取n个连续的字的集合,可以获取到字的前后信息。一般2-gram或者3-gram比较常见。
    文本的离散表示存在着数据稀疏、向量维度过高、字词之间的关系无法度量的问题,适用于浅层的机器学习模型,不适用于深度学习模型。

  2. 分布式表示:连续、低维、稠密。
    word2vec是Google于2013年开源推出的一个用于获取词向量的工具包。
    word2vec是一个将词表示为一个向量的工具,通过该向量表示,可以用来进行更深入的自然语言处理,比如机器翻译等。

word2vec作为神经概率语言模型的输入,其本身其实是神经概率模型的副产品,是为了通过神经网络学习某个语言模型而产生的中间结果。具体来说,“某个语言模型”指的是“CBOW”和“Skip-gram”。具体学习过程会用到两个降低复杂度的近似方法——Hierarchical Softmax或Negative Sampling。两个模型乘以两种方法,一共有四种实现。

1)CBOW:CBOW 是 Continuous Bag-of-Words Model 的缩写,是一种根据上下文的词语预测当前词语的出现概率的模型。
2)Skip-gram:Skip-gram只是逆转了CBOW的因果关系而已,即已知当前词语,预测上下文。

2、 文本表示的方法

2.1 one-hot表示

one-hot向量表示为ti=[0,0,0,…,1,…0],长度等于特征数目。
假设在一个语料集合中,一种有n个不同的词,则可以使用一个长度为n的向量,对于第i个词(i=0…n−1),向量index=i处值为1外,向量其他位置的值都为0,这样就可以唯一地通过一个[0,0,1,…,0,0] 形式的向量表示一个词。
举个例子,假设我们有四个样本(行),每个样本有三个特征(列),如图: 
 
NLP系列——(4)文本表示_第1张图片
上图中我们已经对每个特征进行了普通的数字编码:我们的feature_1有两种可能的取值,比如是男/女,这里男用1表示,女用2表示。那么one-hot编码是怎么搞的呢?我们再拿feature_2来说明:

这里feature_2 有4种取值(状态),我们就用4个状态位来表示这个特征,one-hot编码就是保证每个样本中的单个特征只有1位处于状态1,其他的都是0。
NLP系列——(4)文本表示_第2张图片
对于2种状态、三种状态、甚至更多状态都是这样表示,所以我们可以得到这些样本特征的新表示:
NLP系列——(4)文本表示_第3张图片
one-hot编码将每个状态位都看成一个特征。对于前两个样本我们可以得到它的特征向量分别为:
NLP系列——(4)文本表示_第4张图片
one-hot在提取文本特征上的应用
one hot在特征提取上属于词袋模型(bag of words)。关于如何使用one-hot抽取文本特征向量我们通过以下例子来说明。假设我们的语料库中有三段话:
我爱中国
爸爸妈妈爱我
爸爸妈妈爱中国

我们首先对预料库分离并获取其中所有的词,然后对每个此进行编号:

1 我; 2 爱; 3 爸爸; 4 妈妈;5 中国

然后使用one hot对每段话提取特征向量:
NLP系列——(4)文本表示_第5张图片
NLP系列——(4)文本表示_第6张图片
NLP系列——(4)文本表示_第7张图片
因此我们得到了最终的特征向量为

我爱中国  ->   1,1,0,0,1

爸爸妈妈爱我  ->  1,1,1,1,0

爸爸妈妈爱中国  ->  0,1,1,1,1

one-hot 优缺点分析
优点:一是解决了分类器不好处理离散数据的问题,二是在一定程度上也起到了扩充特征的作用
缺点:在文本特征表示上有些缺点就非常突出了。首先,它是一个词袋模型,不考虑词与词之间的顺序(文本中词的顺序信息也是很重要的);其次,它假设词与词相互独立(在大多数情况下,词与词是相互影响的);最后,它得到的特征是离散稀疏的

sklearn实现one-hot encode

from sklearn import preprocessing  

enc = preprocessing.OneHotEncoder()  # 创建对象
enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]])   # 拟合
array = enc.transform([[0,1,3]]).toarray()  # 转化
print(array)

2.2 word2vec

什么是word2vec?你可以理解为word2vec就是将词表征为实数值向量的一种高效的算法模型,其利用深度学习的思想,可以通过训练,把对文本内容的处理简化为 K 维向量空间中的向量运算,而向量空间上的相似度可以用来表示文本语义上的相似。

Word2vec输出的词向量可以被用来做很多 NLP 相关的工作,比如聚类、找同义词、词性分析等等。如果换个思路, 把词当做特征,那么Word2vec就可以把特征映射到 K 维向量空间,可以为文本数据寻求更加深层次的特征表示 。

Word2vec 使用的词向量不是我们上述提到的One-hot Representation那种词向量,而是 Distributed representation 的词向量表示方式。其基本思想是 通过训练将每个词映射成 K 维实数向量(K 一般为模型中的超参数),通过词之间的距离(比如 cosine 相似度、欧氏距离等)来判断它们之间的语义相似度.其采用一个 三层的神经网络 ,输入层-隐层-输出层。有个核心的技术是 根据词频用Huffman编码 ,使得所有词频相似的词隐藏层激活的内容基本一致,出现频率越高的词语,他们激活的隐藏层数目越少,这样有效的降低了计算的复杂度。而Word2vec大受欢迎的一个原因正是其高效性,Mikolov 在论文中指出,一个优化的单机版本一天可训练上千亿词。

这个三层神经网络本身是 对语言模型进行建模 ,但也同时 获得一种单词在向量空间上的表示 ,而这个副作用才是Word2vec的真正目标。

与潜在语义分析(Latent Semantic Index, LSI)、潜在狄立克雷分配(Latent Dirichlet Allocation,LDA)的经典过程相比,Word2vec利用了词的上下文,语义信息更加地丰富。

Word2Vec实际上是两种不同的方法:Continuous Bag of Words (CBOW) 和 Skip-gram。CBOW的目标是根据上下文来预测当前词语的概率Skip-gram刚好相反:根据当前词语来预测上下文的概率。这两种方法都利用人工神经网络作为它们的分类算法。起初,每个单词都是一个随机 N 维向量。经过训练之后,该算法利用 CBOW 或者 Skip-gram 的方法获得了每个单词的最优向量。

2.2.1 CBOW

这里, 数学基础及英文好的同学可以参照斯坦福大学Deep Learning for NLP课堂笔记。

NLP系列——(4)文本表示_第8张图片

  • 输入层:上下文单词的onehot. {假设单词向量空间dim为V,上下文单词个数为C}
  • 所有onehot分别乘共享的输入权重矩阵W. {V*N矩阵,N为自己设定的数,初始化权重矩阵W}
  • 所得的向量 {因为是onehot所以为向量} 相加求平均作为隐层向量, size为1*N.
  • 乘以输出权重矩阵W’ {N*V}
  • 得到向量 {1*V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维都代表着一个单词},概率最大的index所指示的单词为预测出的中间词(target word)
  • 与true label的onehot做比较,误差越小越好
    所以,需要定义loss function(一般为交叉熵代价函数),采用梯度下降算法更新W和W’。训练完毕后,输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),这个矩阵(所有单词的word embedding)也叫做look up table(其实聪明的你已经看出来了,其实这个look up table就是矩阵W自身),也就是说,任何一个单词的onehot乘以这个矩阵都将得到自己的词向量。有了look up table就可以免去训练过程直接查表得到单词的词向量了。
    举个例子:
    假设我们现在的Corpus是这一个简单的只有四个单词的document:
    {I drink coffee everyday}
    我们选coffee作为中心词,window size设为2
    也就是说,我们要根据单词”I”,”drink”和”everyday”来预测一个单词,并且我们希望这个单词是coffee。
    NLP系列——(4)文本表示_第9张图片
    NLP系列——(4)文本表示_第10张图片
    NLP系列——(4)文本表示_第11张图片
    NLP系列——(4)文本表示_第12张图片
    NLP系列——(4)文本表示_第13张图片
    假设我们此时得到的概率分布已经达到了设定的迭代次数,那么现在我们训练出来的look up table应该为矩阵W。即,任何一个单词的one-hot表示乘以这个矩阵都将得到自己的word embedding

2.2.2 Skip-Gram

根据当前词预测上下文。
NLP系列——(4)文本表示_第14张图片
接下来我们来看看如何训练我们的神经网络。假如我们有一个句子“The dog barked at the mailman”。
首先我们选句子中间的一个词作为我们的输入词,例如我们选取“dog”作为input word;
有了input word以后,我们再定义一个叫做skip_window的参数,它代表着我们从当前input word的一侧(左边或右边)选取词的数量。如果我们设置skip_window=2,那么我们最终获得窗口中的词(包括input word在内)就是[‘The’, ‘dog’,‘barked’, ‘at’]。skip_window=2代表着选取左input word左侧2个词和右侧2个词进入我们的窗口,所以整个窗口大小span=2x2=4。另一个参数叫num_skips,它代表着我们从整个窗口中选取多少个不同的词作为我们的output word,当skip_window=2,num_skips=2时,我们将会得到两组 (input word, output word) 形式的训练数据,即 (‘dog’, ‘barked’),(‘dog’, ‘the’)。
神经网络基于这些训练数据将会输出一个概率分布,这个概率代表着我们的词典中的每个词是output word的可能性。这句话有点绕,我们来看个栗子。第二步中我们在设置skip_window和num_skips=2的情况下获得了两组训练数据。假如我们先拿一组数据 (‘dog’, ‘barked’) 来训练神经网络,那么模型通过学习这个训练样本,会告诉我们词汇表中每个单词是“barked”的概率大小。
gensim 库中word2vec使用

import logging
import gensim
from gensim.models import word2vec

# 设置输出日志
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# 直接用gemsim提供的API去读取txt文件,读取文件的API有LineSentence 和 Text8Corpus, PathLineSentences等。
sentences = word2vec.LineSentence("./all.txt")

# 训练模型,词向量的长度设置为200, 迭代次数为8,采用skip-gram模型,模型保存为bin格式
model = gensim.models.Word2Vec(sentences, size=200, sg=1, iter=8)
model.wv.save_word2vec_format("./word2Vec" + ".bin", binary=True)

# 加载bin格式的模型
wordVec = gensim.models.KeyedVectors.load_word2vec_format("word2Vec.bin", binary=True)

参考资料

https://blog.csdn.net/cqy_chen/article/details/78881084
https://blog.csdn.net/mawenqi0729/article/details/80698780
https://blog.csdn.net/nc514819873/article/details/89444948

你可能感兴趣的:(nlp)