ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NLP word embedding汇总

2021-06-20 14:58:10  阅读:477  来源: 互联网

标签:NLP 中心词 word emb hot embedding hate


Word Embedding 词嵌入,从字面意思理解其实不是很好懂,他本质是一个向量化Vectorization的过程,一个把文字文本转化成数字形式的方式。这样模型才能够处理和训练文本。

比如我有一句话I love you, 最简单的翻译成向量,那就是[0,1,2],因为我的词库里暂时只有这三个词。接下来我想说I hate you,其中hate是新词,其他两个是旧词,那就是[0,3,2], 而hate是词典里的新词,所以他的编号也是放在最后。

当这个词库越来越大,比如有1万个词了,就像字典一样,基本每一句话都能用数字表示,这就实现了基本的向量化。当然直接用10进制肯定是不太好的,计算机就应该用01表示,于是one hot vector就产生了(这里不是二进制,每一个词只有一个位置为1)

One hot vector

在这里插入图片描述
对于这种表示方式,词典有多长,每个one hot vector就有多长,而其中1的位置就像个开关,在对应词的位置就表示1,其他位置则表示0。

再次回到最开始的例子,我现在的vocabulary只有四个词I, love, you, hate,那one hot vector就分别是1000,0100, 0010, 0001,
而I love you=[1000, 0100, 0010]。

但显而易见,这种方式肯定是不够的,他没有区分每个词之间的区别,也没有考虑相似度。比如car和bus都是交通工具,但是从vector的角度而言,他们就是两个没有任何关联的单独的值。

另一方面,效率也不行,假如字典有10000万个词,那每个词都是9999个0和1个1组成,过于稀疏,并且也非常浪费空间。

进化一点,我们就有了Bag of Words 词袋模型。

Bag of Words

在这里插入图片描述
词袋模型是不考虑顺序的,只根据每个词在构建的vocab中的频率表示
比如I love you, but you hate me, 这里由于新加入了词语,词典变成了[I, love, you, hate, but, me] 一共六个词,根据对应的频率表示
原句为[1, 1, 2, 1, 1, 1], 正好对应每个词出现的次数,2就表示you这个词出现了两次。

但问题是由于他不考虑顺序,
I love you, but you hate me
I hate you, but you love me
这两句话用词袋表示是一样的,但显而易见他们的含义是有很大差异的。

于是方法需要继续改进。

另外每个词的重要性也是不同的,比如[I love the movie] 和 [I hate the movie], 这两句话,love和hate显然比其他词更重要,而the这种甚至是可有可无的。于是我们希望更好的向量化方法。

TF-IDF

于是有了TF-IDF,可以衡量词在文本中的重要性,他是通过计算两个值TF(Term Frequency, 词频), IDF(Inverse Document Frequency)是实现,具体的TF-IDF计算方式和代码实现可以看我的另一篇文章
在这里插入图片描述
简而言之:
假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频就是3/100=0.03。而IDF的是以文件集的文件总数,除以出现“母牛”一词的文件数。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是lg(10,000,000 / 1,000)=4。最后的tf-idf的分数为0.03 * 4=0.12

有时候为了防止IDF中分母为0,会用1+df表示分母。

当然tfidf也是有缺点的,他只考虑频率,而没有词之间的相似度,比如car和bus,他会认为这是两个没有关联的词,并且当词典特别大时,表示也会变得特别稀疏。

Word2Vec, FastText

于是,进一步改进,有了word2vec, fasttext,他们就考虑了词之间的相似度,具体操作可以通过gensims调包实现,这里具体可以看我的另一篇文章

具体Word2vec中CBOW,skipgram怎么训练的,可以看知乎上这个人写的, 感觉还不错。

Word2Vec和Fasttext都有两种模式,分别是CBOW和Skip gram。
在这里插入图片描述

训练过程如下,以CBOW为例:
每个输入的词都用one-hot vector表示,当我用CBOW是就是周围词预测中心词,那么中心词就成了target Y,而周围词就是那一堆input,每一个input都会经过一个参数矩阵W。看下图比较容易理解,其中window size=2,即每个中心词的前2个词后2个词都是周围词。

在这里插入图片描述

分别有输入权重矩阵 W W W,和输出权重矩阵 W ′ W' W′,比如CBOW的时候每个周围词用one hot vector和 W W W相乘之后再相加,然后进入 W ′ W' W′,然后再和中心词的向量计算loss,一直迭代更新两个参数矩阵 W , W W,W W,W。
在这里插入图片描述
这个W矩阵就把one-hot向量映射到了低维度表示,然后中间这一层,就要用每一个周围词映射之后的向量相加,来表示中心词
在这里插入图片描述
中心词现在是 v ^ \hat{v} v^, 他是根据周围词构建的,然后用 W ′ W' W′把它反向转换成长度跟one-hot vector一样的向量,再计算softmax,再和中心词原本的one-hot计算loss。
在这里插入图片描述
这个训练过程其实就是神经网络的训练过程,经过一次次迭代之后可以获得最终的矩阵表示。

理解了CBOW之后,Skipgram就是一个相反的过程,他同样有 W , W ′ W, W' W,W′两个参数矩阵,输入是中心词的one-hot,target就是几个周围词的one-hot。

当然Word2Vec也是有缺点的,他不能处理OOV(Out-of-Vocabulary)问题,即不在词典里的词他没法表示。

而FastText是可以处理这个的,FastText虽然也有CBOW和Skipgram,但是和Word2Vec不同的是他是基于n-gram训练的,n-grams的意思就是他会把每n个字母或者词当作一个单独整体,比如2-grams(bigrams)时,apple就可以写成ap,pp,pl,le,如果是3-grams(trigrams),就是app,ppl,ple。

最后生成的结果,会对每一个n-grams都生成一个word embedding。基于这种策略,OOV问题就可以解决,即使这个词没有出现在vocab里面,但是他可以由存在的n-grams拼接而成,比如我有ban,native两个词,当我遇到banana这个新词时,就可以用ban中的‘ba’和native中的’na 拼接而成。

但无论是FastText还是Word2Vec,都局限在中心词和周围词,也就是只利用了局部信息,而没有利用全局信息,于是就有了利用到全局信息的Glove

glove

glove会利用到全局的词共现矩阵
在这里插入图片描述

可以直接调用别人训练好的glove模型,而不需要自己训练

import gensim.downloader as api

model = api.load("glove-twitter-25")  

如果你想查看某个词在这个导入的模型中的词向量,只需要使用.wv[]并带上相应的词语。

model.wv['good']

结果如下,你会发现这个向量的长度就是25,也就是’glove-twitter-25’中25的含义,还有其他类似的可导入的模型,比如’glove-twitter-50’, 'glove-twitter-100’等。
在这里插入图片描述

通过这种方式,我们可以用别人训练好的模型,在我们自己的vocab上生成一个embedding matrix作为lookup table,用来给我们后续的模型进行初始化,而不是用随机参数。

这里的word_list就是一个包含了input中所有词的list

import numpy as np
emb_dim = model.vector_size #向量长度,这里是25

emb_table = []
for i, word in enumerate(word_list):
    if word in word_emb_model:
        emb_table.append(word_emb_model[word])
    else:
        emb_table.append([0]*emb_dim)
emb_table = np.array(emb_table)

根据lookup table初始化模型

class Model(nn.Module):
    def __init__(self, hidden_dim, attn):
        super(Model, self).__init__()
        self.we_emb = nn.Embedding(vocab_size, emb_dim)
        self.we_emb.weight.data.copy_(torch.from_numpy(emb_table))
        
        self.lstm = nn.LSTM(we_dim, hidden_dim//2, num_layers=2, bidirectional=True, dropout = 0.5) #only word_embedding(glove-twittwe-25), no pretrained embedding,  no pos tagging
        
        self.linear = nn.Linear(hidden_dim*2, n_class)

其他的Word Embedding 方法

预训练模型pre-trained

利用预训练模型,可以直接用别人训练好的模型进行word embedding
比如BERT, GPT-3等,实现方式也有很多种

比如用Flair包,下载:

!pip install flair

然后用flair生成embedding模型

from flair.embeddings import StackedEmbeddings,CharacterEmbeddings,TransformerWordEmbeddings,PooledFlairEmbeddings
flair_embedding = StackedEmbeddings(
    [
        TransformerWordEmbeddings('bert-base-uncased', layers='-6',subtoken_pooling="mean"), 
        TransformerWordEmbeddings('roberta-large', layers='-6',subtoken_pooling="mean"),  
        
    ]
).to(device)

具体有哪些模型可以使用的可以看这个链接
这些预训练模型可以单独使用,也可以stack到一起使用。
在这里插入图片描述

当模型构建好之后,测试一下

from flair.data import Sentence
sents = [['I', 'am', 'always', 'good', 'for', 'you'],
        ['come', 'here', 'and', 'have', 'a', 'drink']]
for sent in sents:
    temp_sent = Sentence(" ".join(sent),use_tokenizer=False)
    flair_embedding.embed(temp_sent)
    temp_emb=[]
    for emb in temp_sent:
        temp_emb.append(emb.embedding.cpu().tolist())
    print(temp_emb)

结果就是这两句话的word embedding向量。

完成了word embedding,就可以进行NLP的后续任务了。

标签:NLP,中心词,word,emb,hot,embedding,hate
来源: https://blog.csdn.net/OldDriver1995/article/details/118069883

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有