PyTorch基础——词向量(Word Vector)技术

一、介绍

内容

将接触现代 NLP 技术的基础:词向量技术。

第一个是构建一个简单的 N-Gram 语言模型,它可以根据 N 个历史词汇预测下一个单词,从而得到每一个单词的向量表示。

第二个将接触到现代词向量技术常用的模型 Word2Vec。在实验中将以小说《三体》为例,展示了小语料在 Word2Vec 模型中能够取得的效果。

在最后一个将加载已经训练好的一个大规模词向量,并利用这些词向量来做一些简单的运算和测试,以探索词向量中包含的语义信息。

知识点

  • N-Gram(NPLM) 语言模型
  • Word2Vec 词向量模型
  • 使用 Word2Vec 词向量进行语义运算

二、N-Gram 词向量模型

引入相关包

# 加载必要的程序包
# PyTorch的程序包
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 数值运算和绘图的程序包
import numpy as np
import matplotlib.pyplot as plt

import matplotlib

值得注意的是 sklearn 包,在本次实验中将用到其中的 PCA 降维算法。

# 加载机器学习的软件包
from sklearn.decomposition import PCA

#加载‘结巴’中文分词软件包

import jieba

#加载正则表达式处理的包
import re

%matplotlib inline

文本预处理

读入原始文件

下载数据 网盘链接:https://pan.baidu.com/s/1D1YI4h7k-xPpPbFYQx4E8A 提取码:osk5

#读入原始文件

f = open("三体.txt", 'r')
text = str(f.read())
f.close()

text

接下来用“结巴(jieba)”分词工具来分词,并过滤掉所有的标点符号

# 分词
temp = jieba.lcut(text)
words = []
for i in temp:
    #过滤掉所有的标点符号
    i = re.sub("[\s+\.\!\/_,$%^*(+\"\'“”《》?“]+|[+——!,。?、[email protected]#¥%……&*():]+", "", i)
    if len(i) > 0:
        words.append(i)
print(len(words))
words

N-Gram 词向量模型的原理是利用一个人工神经网络来根据前 N 个单词来预测下一个单词,从而得到每个单词的词向量。

# 构建三元组列表.  每一个元素为: ([ i-2位置的词, i-1位置的词 ], 下一个词)
# 我们选择的Ngram中的N,即窗口大小为2
trigrams = [([words[i], words[i + 1]], words[i + 2]) for i in range(len(words) - 2)]
# 打印出前三个元素看看
print(trigrams[:3])

将每个单词进行编码 构造词典

对上面包含所有词汇的列表 word 取一个独立集 set()

根据词典做两个速查表,一个是根据单词索引其编号,一个是根据编号索引单词

# 得到词汇表
vocab = set(words)
print(len(vocab))
# 两个字典,一个根据单词索引其编号,一个根据编号索引单词
# word_to_idx中的值包含两部分,一部分为id,另一部分为单词出现的次数
# word_to_idx中的每一个元素形如:{w:[id, count]},其中w为一个词,id为该词的编号,count为该单词在words全文中出现的次数
word_to_idx = {}
idx_to_word = {}
ids = 0

# 对全文循环,构建这两个字典
for w in words:
    cnt = word_to_idx.get(w, [ids, 0])
    if cnt[1] == 0:
        ids += 1
    cnt[1] += 1
    word_to_idx[w] = cnt
    idx_to_word[ids] = w

word_to_idx

构造模型并训练

下面将构建一个三层的神经网络模型:

  • 1、输入层:embedding 层。

    • 这一层的作用是:先将输入单词的编号映射为一个 one hot 编码的向量,形如:001000,维度为单词表大小。
    • 然后,embedding 会通过一个线性的神经网络层映射出这个词的向量表示,输出为 embedding_dim。
  • 2、隐藏层:线性层 + 非线性 ReLU。
    • 从 embedding_dim 维度到128维度,然后经过非线性 ReLU 函数
  • 3、输出层:线性层 + Log Softmax。
    • 从 128 维度到单词表大小维度,然后 log softmax 函数,给出预测每个单词的概率。
class NGram(nn.Module):

    def __init__(self, vocab_size, embedding_dim, context_size):
        super(NGram, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)  # 输入层
        self.linear1 = nn.Linear(context_size * embedding_dim, 128) # 隐藏层
        self.linear2 = nn.Linear(128, vocab_size) # 输出层

    def forward(self, inputs):
        #嵌入运算,嵌入运算在内部分为两步:将输入的单词编码映射为one hot向量表示,然后经过一个线性层得到单词的词向量
        #inputs的尺寸为:1*context_size
        embeds = self.embeddings(inputs)
        #embeds的尺寸为: context_size*embedding_dim
        embeds = embeds.view(1, -1)
        #此时embeds的尺寸为:1*embedding_dim
        # 线性层加ReLU
        out = self.linear1(embeds)
        out = F.relu(out)
        #此时out的尺寸为1*128

        # 线性层加Softmax
        out = self.linear2(out)
        #此时out的尺寸为:1*vocab_size
        log_probs = F.log_softmax(out, dim=1)
        return log_probs
    def extract(self, inputs):
        embeds = self.embeddings(inputs)
        return embeds

NPLM 模型的训练是非常非常缓慢的,在训练代码的后面提供了预训练好的模型供大家加载使用。

losses = [] #纪录每一步的损失函数
criterion = nn.NLLLoss() #运用负对数似然函数作为目标函数(常用于多分类问题的目标函数)
model_ng = NGram(len(vocab), 10, 2) #定义NGram模型,向量嵌入维数为10维,N(窗口大小)为2

optimizer = optim.SGD(model_ng.parameters(), lr=0.001) #使用随机梯度下降算法作为优化器

# 因为模型的训练速度非常之慢
# 所以在这里把迭代训练的次数修改为0
# 如果你真的好奇有多慢,欢迎修改这个值,一定不会令你失望的
for epoch in range(0):
    total_loss = torch.Tensor([0])
    for context, target in trigrams:
    # 准备好输入模型的数据,将词汇映射为编码
    context_idxs = [word_to_idx[w][0] for w in context]

    # 包装成PyTorch的Variable
    context_var = Variable(torch.LongTensor(context_idxs))

    # 清空梯度:注意PyTorch会在调用backward的时候自动积累梯度信息,故而每隔周期要清空梯度信息一次。
    optimizer.zero_grad()

    # 用神经网络做计算,计算得到输出的每个单词的可能概率对数值
    log_probs = model_ng(context_var)

    # 计算损失函数,同样需要把目标数据转化为编码,并包装为Variable
    loss = criterion(log_probs, Variable(torch.LongTensor([word_to_idx[target][0]])))

    # 梯度反传
    loss.backward()

    # 对网络进行优化
    optimizer.step()

    # 累加损失函数值
    total_loss += loss.data
losses.append(total_loss)
print('第{}轮,损失函数为:{:.2f}'.format(epoch, total_loss.numpy()[0]))

在这里加载预训练的模型。(数据在网盘中)

model_ng = torch.load('NPLM_Ready.mdl')

将向量投影到二维平面进行可视化

下面首先观察 NPLM 模型的网络结构,以便从 NPLM 的输入层中取出词向量。

print(model_ng)

下面将调用模型的 extract 函数提取出来所有单词的词向量。最后的词向量就存储到了 vec 中。

# 从训练好的模型中提取每个单词的向量
vec = model_ng.extract(Variable(torch.LongTensor([v[0] for v in word_to_idx.values()])))
vec = vec.data.numpy()

但此时获得的词向量仍然是高维度的,想要直观的观察到词汇的分布,还要对它进行降维。可以通过 PCA 降维的方法将 vec 中的向量展示在二维世界中。

# 利用PCA算法进行降维
X_reduced = PCA(n_components=2).fit_transform(vec)

# 绘制所有单词向量的二维空间投影
fig = plt.figure(figsize = (30, 20))
ax = fig.gca()
ax.set_facecolor('white')
ax.plot(X_reduced[:, 0], X_reduced[:, 1], '.', markersize = 1, alpha = 0.4, color = 'black')

# 绘制几个特殊单词的向量
words = ['智子', '地球', '三体', '质子', '科学', '世界', '文明', '太空', '加速器', '平面', '宇宙', '信息']

# 设置中文字体,否则无法在图形上显示中文
zhfont1 = matplotlib.font_manager.FontProperties(fname='./华文仿宋.ttf', size=16)
for w in words:
    if w in word_to_idx:
        ind = word_to_idx[w][0]
        xy = X_reduced[ind]
        plt.plot(xy[0], xy[1], '.', alpha =1, color = 'red')
        plt.text(xy[0], xy[1], w, fontproperties = zhfont1, alpha = 1, color = 'black')

那么,获得的词向量好不好呢?我们通常是去查看在向量上相似的词是否具有相似的语义信息,来验证训练出的词向量是高质量的(包含正确的语义信息)。

# 定义计算cosine相似度的函数
def cos_similarity(vec1, vec2):

    norm1 = np.linalg.norm(vec1)
    norm2 = np.linalg.norm(vec2)
    norm = norm1 * norm2
    dot = np.dot(vec1, vec2)
    result = dot / norm if norm > 0 else 0
    return result

# 在所有的词向量中寻找到与目标词(word)相近的向量,并按相似度进行排列
def find_most_similar(word, vectors, word_idx):
    vector = vectors[word_to_idx[word][0]]
    simi = [[cos_similarity(vector, vectors[num]), key] for num, key in enumerate(word_idx.keys())]
    sort = sorted(simi)[::-1]
    words = [i[1] for i in sort]
    return words

# 与智子靠近的词汇
find_most_similar('智子', vec, word_to_idx)

似乎在词义上并没有什么相近性,这说明本次实验中的这个 NPLM 模型学出来的词向量并不好。实际上,训练好的词向量需要大规模语料,同时还要训练足够长的时间。在这两点上,实验中的小模型都没有做到,所以训练出来的词向量并不理想。

三、Word2Vec

引入 Word2Vec 相关包

Gensim 是一个面向自然语言处理领域的 Python 包,包含了 Word2Vec、LDA 主题模型等常用的自然语言处理功能的函数库。

#加载Word2Vec的软件包
import gensim as gensim
from gensim.models import Word2Vec
from gensim.models.keyedvectors import KeyedVectors
from gensim.models.word2vec import LineSentence

用小语料训练自己的词向量

首先载入语料库,并进行分词

# 读入文件、分词,形成一句一句的语料
# 注意跟前面处理不一样的地方在于,我们一行一行地读入文件,从而自然利用行将文章分开成“句子”
f = open("三体.txt", 'r')
lines = []
for line in f:
    temp = jieba.lcut(line)
    words = []
    for i in temp:
        #过滤掉所有的标点符号
        i = re.sub("[\s+\.\!\/_,$%^*(+\"\'””《》]+|[+——!,。?、[email protected]#¥%……&*():;‘]+", "", i)
        if len(i) > 0:
            words.append(i)
    if len(words) > 0:
        lines.append(words)

lines 是输入的已经变成列表的单词,size 是拟嵌入向量的维度;window 表示的是上下文窗口大小,也就是 N-gram 模型中的那个 N;min_count 为保留最少多少的低频词,如果它等于 0,那便意味着算法将计算所有词的词向量,无论它的出现次数是多少。

# 调用Word2Vec的算法进行训练。
# 参数分别为:size: 嵌入后的词向量维度;window: 上下文的宽度,min_count为考虑计算的单词的最低词频阈值

model = Word2Vec(lines, size = 20, window = 2 , min_count = 0)

观察小语料 Word2Vec 词向量的效果

首先对词向量进行降维,投影到二维空间

# 首先将词向量使用 PCA 降维,投影到二维空间
rawWordVec = []
word2ind = {}
for i, w in enumerate(model.wv.vocab):
    rawWordVec.append(model[w])
    word2ind[w] = i
rawWordVec = np.array(rawWordVec)
X_reduced = PCA(n_components=2).fit_transform(rawWordVec)

绘制出使用 Word2Vec 训练出的词向量星空

# 绘制星空图
# 绘制所有单词向量的二维空间投影
fig = plt.figure(figsize = (15, 10))
ax = fig.gca()
ax.set_facecolor('black')
ax.plot(X_reduced[:, 0], X_reduced[:, 1], '.', markersize = 1, alpha = 0.3, color = 'white')

# 绘制几个特殊单词的向量
words = ['智子', '地球', '三体', '质子', '科学', '世界', '文明', '太空', '加速器', '平面', '宇宙', '进展','的']

# 设置中文字体,否则无法在图形上显示中文
zhfont1 = matplotlib.font_manager.FontProperties(fname='./华文仿宋.ttf', size=16)
for w in words:
    if w in word2ind:
        ind = word2ind[w]
        xy = X_reduced[ind]
        plt.plot(xy[0], xy[1], '.', alpha =1, color = 'red')
        plt.text(xy[0], xy[1], w, fontproperties = zhfont1, alpha = 1, color = 'yellow')

下面找出与“智子”最相近的 20 个词

model.wv.most_similar('智子', topn = 20)

从上面打印出的相近词中可以观察到,使用小语料训练的 Word2Vec 词向量仍不能达到理想的效果。原因有可能还是语料太小,或者对于词语的预处理工作还需要加强

四、使用预训练的大规模 Word2Vec 词向量

加载大规模词向量

注:以下代码请在空闲内存大于3G的环境实验

下面实验要用到的词向量是由微博、人民日报、上海热线、汽车之家等多处的大量语料训练而成,包含 1366130 个词向量。规模如此巨大的中文词向量是非常难得的。感谢台湾第一家大数据公司 AsiaMiner 的联合创始人 尹相志 老师提供本词向量文件。大家可以自行搜索下载数据。

词向量文件的名字是:vectors.bin,首先将它加载到内存中,因为词向量较多所以加载需要一小点时间。

# 加载词向量
word_vectors = KeyedVectors.load_word2vec_format('vectors.bin', binary=True, unicode_errors='ignore')
len(word_vectors.vocab)

观察大规模词向量空间中的语义信息

仍然是使用 PCA 降维将词向量投影到 2 维空间

# PCA降维
rawWordVec = []
word2ind = {}
for i, w in enumerate(word_vectors.vocab):
    rawWordVec.append(word_vectors[w])
    word2ind[w] = i
rawWordVec = np.array(rawWordVec)
X_reduced = PCA(n_components=2).fit_transform(rawWordVec)

降维后将所有的词向量绘制在“星空”中

# 绘制星空图
# 绘制所有的词汇
fig = plt.figure(figsize = (30, 15))
ax = fig.gca()
ax.set_facecolor('black')
ax.plot(X_reduced[:, 0], X_reduced[:, 1], '.', markersize = 1, alpha = 0.1, color = 'white')

ax.set_xlim([-12,12])
ax.set_ylim([-10,20])

# 选择几个特殊词汇,不仅画它们的位置,而且把它们的临近词也画出来
words = {'徐静蕾','吴亦凡','物理','红楼梦','量子'}
all_words = []
for w in words:
    lst = word_vectors.most_similar(w)
    wds = [i[0] for i in lst]
    metrics = [i[1] for i in lst]
    wds = np.append(wds, w)
    all_words.append(wds)

zhfont1 = matplotlib.font_manager.FontProperties(fname='./华文仿宋.ttf', size=16)
colors = ['red', 'yellow', 'orange', 'green', 'cyan', 'cyan']
for num, wds in enumerate(all_words):
    for w in wds:
        if w in word2ind:
            ind = word2ind[w]
            xy = X_reduced[ind]
            plt.plot(xy[0], xy[1], '.', alpha =1, color = colors[num])
            plt.text(xy[0], xy[1], w, fontproperties = zhfont1, alpha = 1, color = colors[num])

注意到,二维空间上看起来靠近的点不一定在高维空间上也靠近。因此我们不能简单的根据二维空间上的靠近程度来判断词语意思的相近程度,而更应该相信颜色,因为颜色是根据相似度表示出来的。

有趣的词向量语义运算

观察一下求近似词的效果

# 查看相似词
word_vectors.most_similar('物理', topn = 20)
# 女人-男人=?-国王
words = word_vectors.most_similar(positive=['女人', '国王'], negative=['男人'])
words
# 北京-中国=?-俄罗斯
words = word_vectors.most_similar(positive=['北京', '俄罗斯'], negative=['中国'])
words
# 自然科学-物理学=?-政治学
words = word_vectors.most_similar(positive=['自然科学', '政治学'], negative=['物理学'])
words
# 王菲-章子怡=?-汪峰
words = word_vectors.most_similar(positive=['王菲', '汪峰'], negative=['章子怡'])
words

原文地址:https://www.cnblogs.com/wwj99/p/12222437.html

时间: 2024-10-26 09:09:36

PyTorch基础——词向量(Word Vector)技术的相关文章

词向量技术原理及应用详解(一)

文本表示是自然语言处理中的基础工作,文本表示的好坏直接影响到整个自然语言处理系统的性能.在自然语言处理研究领域,文本向量化是文本表示的一种重要方式. 顾名思义,文本向量化就是将文本表示成一系列能够表达文本语义的向量.无论中文还是英文,词语都是表达文本处理的最基本单元. 当前阶段,对文本向量化都是通过词向量化实现的.当然也有将文章或者句子作为文本处理的基本单元,像doc2vec和str2vec技术. 接下来主要是讨论以词语作为基本单元的word2vec技术,将先从onehot编码到word2vec

词向量技术原理及应用详解(二)

当前文本向量化主流的方式是word2vec词向量技术,从基于统计的方法,到基于神经网络的方法,掌握word2vec词向量技术是学习文本向量化的最好的方式 下面是Tomas MIkolov的三篇有关word embedding的文章:            1.Efficient Estimation of Word Representation in Vector Space, 2013            2.Distributed Representations of Sentences

Dependency-Based Word Embeddings(基于依存的词向量)

最近要开始读论文了,其实自己读论文的能力挺不怎么样的,并且读过就忘记,这实在是让人很不爽的事情.自己分析记不住的原因可以有以下几点: 读论文时理解就不深刻,有时候就是一知半解的 读完之后没有总结,即没有自己概括这篇论文的过程,所以文中一知半解的过程还是忽略了,并且以后再回顾的时候,这篇论文对自己来说就像新的论文一样,还是一样懵. 所以,我决定对读的每一篇论文都做一个总结,并发表在博客上.如果有人能强忍着"这人写了些什么玩意"的想法看完了我的文章,还请不吝赐教,指出我的错误. 作为开始总

词袋模型(BOW,bag of words)和词向量模型(Word Embedding)概念介绍

例句: Jane wants to go to Shenzhen. Bob  wants to go to Shanghai. 一.词袋模型 将所有词语装进一个袋子里,不考虑其词法和语序的问题,即每个词语都是独立的.例如上面2个例句,就可以构成一个词袋,袋子里包括Jane.wants.to.go.Shenzhen.Bob.Shanghai.假设建立一个数组(或词典)用于映射匹配 1 [Jane, wants, to, go, Shenzhen, Bob, Shanghai] 那么上面两个例句就可

【paddle学习】词向量

本章我们介绍词的向量表征,也称为word embedding.词向量是自然语言处理中常见的一个操作,是搜索引擎.广告系统.推荐系统等互联网服务背后常见的基础技术. 在这些互联网服务里,我们经常要比较两个词或者两段文本之间的相关性.为了做这样的比较,我们往往先要把词表示成计算机适合处理的方式.最自然的方式恐怕莫过于向量空间模型(vector space model). 在这种方式里,每个词被表示成一个实数向量(one-hot vector),其长度为字典大小,每个维度对应一个字典里的每个词,除了这

word2vec词向量训练及中文文本相似度计算

本文是讲述如何使用word2vec的基础教程,文章比较基础,希望对你有所帮助! 官网C语言下载地址:http://word2vec.googlecode.com/svn/trunk/ 官网Python下载地址:http://radimrehurek.com/gensim/models/word2vec.html 1.简单介绍 参考:<Word2vec的核心架构及其应用 · 熊富林,邓怡豪,唐晓晟 · 北邮2015年> <Word2vec的工作原理及应用探究 · 周练 · 西安电子科技大学

如何产生好的词向量

如何产生好的词向量? 词向量.词嵌入(word vector,word embedding)也称分布式表示(distributed representation),想必任何一个做NLP的研究者都不陌生.如今词向量已经被广泛应用于各自NLP任务中,研究者们也提出了不少产生词向量的模型并开发成实用的工具供大家使用.在使用这些工具产生词向量时,不同的训练数据,参数,模型等都会对产生的词向量有所影响,那么如何产生好的词向量对于工程来说很重要.中科院自动化所的来斯惟博士对此进行了详细的研究.本篇博客也是我

文本分布式表示(二):用tensorflow和word2vec训练词向量

博客园的markdown用起来太心塞了,现在重新用其他编辑器把这篇博客整理了一下. 目前用word2vec算法训练词向量的工具主要有两种:gensim 和 tensorflow.gensim中已经封装好了word2vec这个包,用起来很方便,只要把文本处理成规范的输入格式,寥寥几行代码就能训练词向量.这样比较适合在做项目时提高效率,但是对理解算法的原理帮助不大.相比之下,用tensorflow来训练word2vec比较麻烦,生成batch.定义神经网络的各种参数,都要自己做,但是对于理解算法原理

PyTorch基础——使用神经网络识别文字中的情感信息

一.介绍 知识点 使用 Python 从网络上爬取信息的基本方法 处理语料"洗数据"的基本方法 词袋模型搭建方法 简单 RNN 的搭建方法 简单 LSTM 的搭建方法 二.从网络中抓取并处理数据 引入相关包 下载所需数据并解压 链接:https://pan.baidu.com/s/1Jg5NPxc9L-M8Tdgh70Tvig 提取码:dpqq # 导入程序所需要的程序包 #PyTorch用的包 import torch import torch.nn as nn import tor