python词嵌入_【自然语言处理】收藏!使用Python的4种句嵌入技术

本文介绍了自然语言处理中4种常用的句嵌入技术,包括词嵌入的基本原理、Doc2Vec、SentenceBERT、InferSent和Universal Sentence Encoder,并提供了Python实现这些技术的代码示例。通过句嵌入,机器可以理解文本的上下文和语义信息,实现更精确的文本分析和处理。
摘要由CSDN通过智能技术生成

人类理解语言细微差别的能力是非常强大的——我们敏锐的大脑可以在一句话里轻易地感受到幽默、讽刺、负面情绪等,但发挥这个“超能力”的前提是,我们必须知道话语所使用的语言。

例如,如果有小伙伴用日文评论这篇文章,大部分人应该无法理解他想说什么吧,自然也不敢轻易回复。所以,为了实现有效沟通,我们需要用彼此最能理解的语言进行互动。

而对于机器来说,为了让机器可以处理和理解任意文本,我们必须用机器能够理解的语言来表示文本。那么它最懂哪种语言呢?

答案是数字(numbers)——无论我们提供给机器什么数据:视频、音频、图像或文本,机器都只会与数字打交道,这也就是为什么将文本表示为数字或嵌入文本(embedding text)是自然语言处理中最热门的话题之一。

这篇文章,我将介绍Python代码中最常用的4种句嵌入技术并且概述它们的体系结构以及如何用Python实现这些技术,包括如下内容:什么是词嵌入(Word Embedding)

什么是句嵌入(Sentence Embedding)

Doc2Vec是什么

SentenceBERT介绍

InferSent

Universal Sentence Encoder

什么是词嵌入?

最初的嵌入技术只处理单词,即给定一组单词,而该技术就是把集合中的每个单词生成一个嵌入。最原始的方法是对单词序列进行热编码,如此一来,集合中的单词就由1表示,其他单词由0表示。

虽然这种方法在表示单词和其他简单的文本处理任务上很有效,但面对更复杂的任务(查找相似单词)时却没什么用了。比如,我们需要查询:“北京最好的日料店”,我们希望得到与“日料”、“北京餐厅”和“最好”相对应的搜索结果,若我们得到的结果是“北京的顶级日本料理“,那么用原始方法就无法检测出“最好”和“顶级”,或“料理”和“店”之间的相似性了。词嵌入技术图示

这个词关联问题让词嵌入技术得以开发和发展,与传统的热编码相比,词嵌入技术转换的不仅是单词,还能识别出该词的语义和语法以构建该信息的向量。目前常用的词嵌入技术有Word2Vec、GloVe、ELMo、FastText等。

词嵌入的基本原理就是使用与该词相邻的词的信息。随着词嵌入技术的发展,技术人员已经找到了更好的方法来表达更多的信息,由此扩展到了句子和段落。

什么是句嵌入?

如果我们直接处理句子呢?要知道,在大文本的情况下,很大程度上我们的分析会被从词嵌入中提取的信息所限制。

假设,我们读到一个句子“我不喜欢拥挤的地方”,接着,我们又读到“然而,我喜欢世界上最繁忙的城市之一,纽约”。我们怎样才能让机器明白“拥挤的地方”和“繁忙的城市”之间的关联呢?

显然,词嵌入技术在这里是不够的,我们需要用到句嵌入技术了。句嵌入是将整个句子及其语义信息表示为向量,让机器能理解上下文、用意和其他潜藏在文本中的细微差别。

接下来我们将用Python代码实例,直观地给大家介绍目前最受欢迎的4中句嵌入技术:Doc2Vec、SentenceBERT、InferSent、Universal Sentence Encoder

那我们一起来建立基本语料库并定义句子列表吧!

Step 1:

首先,导入库并下载‘punkt’

import nltk

nltk.download('punkt')

from nltk.tokenize import word_tokenize

import numpy as np

Step 2:

然后,我们来定义句子列表。当然,你也可以使用一个更大的列表(最好只使用一个句子列表以便更容易地处理每个句子)

sentences = ["I ate dinner.",

"We had a three-course meal.",

"Brad came to dinner with us.",

"He loves fish tacos.",

"In the end, we all felt like we ate too much.",

"We all agreed; it was a magnificent evening."]

Step 3:

我们再保留一份这些句子的标记版

# Tokenization of each document

tokenized_sent = []

for s in sentences:

tokenized_sent.append(word_tokenize(s.lower()))

tokenized_sent

Step 4:

最后,我们定义一个函数,让它返回两个向量间的余弦相似度(cosine similarity)

def cosine(u, v):

return np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))

好了!接下来,我们就用这个句子列表来学习这4个句嵌入技术吧!

Doc2Vec

作为Word2Vec的扩展,Doc2Vec是当下最流行的句嵌入技术之一。该算法于2014年引入,是一种无监督算法,主要原理是将一个“段落向量”添加到Word2Vec模型中,而其中,添加方法两个:

1) PVDM(分布式存储版本的段落向量):

在分配一个段落向量句的同时给所有句子共享词向量。然后通过平均或连接(段落向量和单词向量)来得到最后的句关联。其实,它是Word2Vec连续词袋法的扩展——在词袋中,我们根据一组单词预测下一个单词。在PVDM中,我们是根据一组句子预测下一个句子。PVDM图示

2) PVDOBW(分布式包词版本的段落向量):

和PVDM一样, PVDOBW也是Word2Vec的另一扩展,但与PVDM不同的是,我们只在句子中随机抽取单词,然后让模型去预测它来自哪个句子(可以理解成是一个分类任务)。

Step 1:

我们将使用Gensim来演示如何使用Doc2Vec。首先要导入模型、语料库和其他库,然后构建一个带标记的语料库。每个句子都被表示为一个TaggedDocument,其中包含单词列表和与之关联的标记。

# import

from gensim.models.doc2vec import Doc2Vec, TaggedDocument

tagged_data = [TaggedDocument(d, [i]) for i, d in enumerate(tokenized_sent)]

tagged_data

Step 2:

接着,我们将用以下参数对模型进行训练:

## Train doc2vec model

model = Doc2Vec(tagged_data, vector_size = 20, window = 2, min_count = 1, epochs = 100)

'''

vector_size = Dimensionality of the feature vectors.

window = The maximum distance between the current and predicted word within a sentence.

min_count = Ignores all words with total frequency lower than this.

alpha = The initial learning rate.

'''

## Print model vocabulary

model.wv.vocab

Step 3:

我们现在来挑一个句子来测试吧,让模型去从数据中找出与其最相似的5个句子,并按相似度降序显示。其中,infer_vector方法返回测试句子的向量化形式(包括段落向量);most_similar方法返回相似的句子。

test_doc = word_tokenize("I had pizza and pasta".lower())

test_doc_vector = model.infer_vector(test_doc)

model.docvecs.most_similar(positive = [test_doc_vector])

'''

positive = List of sentences that contribute positively.

'''

成功找到了!

SentenceBERT

SentenceBERT在2018年一经推出就立即在句嵌入测试中受到热捧。这个基于BERT模型的技术有4个关键概念:Attention

Transformer

BERT

孪生神经网络(Siamese Network)

SentenceBERT使用孪生神经网络结构,使用2个句子作为输入。这2个句子会被传递给BERT模型,然后使用pooling层来生成它们的嵌入。最后使用句子对的嵌入作为输入来计算余弦相似度。孪生神经网络图示

SentenceBERT技术图示

Step 1:

加载预训练的BERT模型。sentence-transformers里还有许多其他开源的预训练模型,可以在此处找到模型的完整列表。

!pip install sentence-transformers

from sentence_transformers import SentenceTransformer

sbert_model = SentenceTransformer('bert-base-nli-mean-tokens')

Step 2:

对句子进行编码并显示句子向量:

sentence_embeddings = model.encode(sentences)

#print('Sample BERT embedding vector - length', len(sentence_embeddings[0]))

#print('Sample BERT embedding vector - note includes negative values', sentence_embeddings[0])

Step 3:

定义一个测试查询并对其进行编码:

query = "I had pizza and pasta"

query_vec = model.encode([query])[0]

Step 4:

使用scipy计算余弦相似度,然后检索句子和测试查询间的相似度

for sent in sentences:

sim = cosine(query_vec, model.encode([sent])[0])

print("Sentence = ", sent, "; similarity = ", sim):

我们获得文本中的句子与测试句之间的相似性了!实例使用的是已经预训练的BERT模型,如果小伙伴想从头训练SentenceBERT,它的运行速度将会变得异常慢hhh。

InferSent

InferSent是Facebook人工智能研究所在2018年推出的一项有监督的句嵌入技术。该模型最大的特点是它是在自然语言推理(NLI)数据集里训练的,更具体地说,就是SNLI (Stanford自然语言推理)数据集。该数据集由57万对人类生成的英语句子组成,而这些句子已经被人工标记为隐含、矛盾或中性了。

和SentenceBERT一样,InferSent也是使用一对句子并对它们进行编码以生成实际的句子嵌入:

输出向量进入分类器,分类器会将向量分类到3个定义类别之一中(concatenation、element-wise product、absolute element-wise difference)

让我们看看句子相似度任务是如何使用推理的。我们将使用PyTorch进行此操作:

Step 1:

首先,下载推断模型和已经预训练的单词向量。为此,请从这里保存model .py文件并将其存储到工作目录中。

我们还需要保存训练好的模型和预训练好的GLoVe词向量。所以,我们的工作目录应该有一个“encoders”文件夹和一个名为“GLoVe”的文件夹。encoders文件夹将有我们的模型,而GloVe文件夹应该有词向量:

! mkdir encoder

! curl -Lo encoder/infersent2.pkl https://dl.fbaipublicfiles.com/infersent/infersent2.pkl

! mkdir GloVe

! curl -Lo GloVe/glove.840B.300d.zip http://nlp.stanford.edu/data/glove.840B.300d.zip

! unzip GloVe/glove.840B.300d.zip -d GloVe/

加载模型和词向量:

from models import InferSent

import torch

V = 2

MODEL_PATH = 'encoder/infersent%s.pkl' % V

params_model = {'bsize': 64, 'word_emb_dim': 300, 'enc_lstm_dim': 2048,

'pool_type': 'max', 'dpout_model': 0.0, 'version': V}

model = InferSent(params_model)

model.load_state_dict(torch.load(MODEL_PATH))

W2V_PATH = '/content/GloVe/glove.840B.300d.txt'

model.set_w2v_path(W2V_PATH)

Step 2:

从最开始准备好的句子列表中构建词汇表:

model.build_vocab(sentences, tokenize=True)

Step 3:

测试——使用InferSent对该测试查询进行编码并生成嵌入:

query = "I had pizza and pasta"

query_vec = model.encode(query)[0]

query_vec

Step 4:

计算此查询与文本中每个句子的余弦相似度:

similarity = []

for sent in sentences:

sim = cosine(query_vec, model.encode([sent])[0])

print("Sentence = ", sent, "; similarity = ", sim)

Universal Sentence Encoder

目前性能最好的句嵌入技术应该就是Universal Sentence Encoder了,是我们可以用它来进行多任务学习。

这意味着我们生成的句嵌入可以用于多种任务,如情绪分析、文本分类、句子相似度等,这些请求的结果会反馈到模型中,从而得到比之前更好的句向量。

Universal Sentence Encoder是基于两种编码器的模型:Transformer和Deep Averaging Network(DAN)这两种模型都能够将一个单词或句子作为输入,并为其生成嵌入。基本流程如下:将句子转换为小写字母后将其标记

根据编码器的类型,句子被转换为512维向量如果我们使用Transformer,它类似于transformer模块的架构,会使用自注意机制。

使用DAN则会首先计算unigram和bigram嵌入,然后对它们进行平均以得到单个嵌入。然后,它被传递到深度神经网络,以得到512维的句嵌入。

这些句嵌入然后用于各种非监督和监督任务,如Skipthoughts, NLI等,然后再次重用训练好的模型,生成新的512维句子嵌入。

首先下载TensorFlow and TensorFlow hub:

!pip3 install --upgrade tensorflow-gpu

# Install TF-Hub.

!pip3 install tensorflow-hub

Step 1:

导入需要的库:

import tensorflow as tf

import tensorflow_hub as hub

import numpy as np

Step 2:

通过TFHub使用该模型:

module_url = "https://tfhub.dev/google/universal-sentence-encoder/4"

model = hub.load(module_url)

print ("module %s loaded" % module_url)

Step 3:

为句子列表和查询生成嵌入:

sentence_embeddings = model(sentences)

query = "I had pizza and pasta"

query_vec = model([query])[0]

Step 4:

计算测试查询与句子列表之间的相似度:

for sent in sentences:

sim = cosine(query_vec, model([sent])[0])

print("Sentence = ", sent, "; similarity = ", sim)

小结

小编给大家介绍了自然语言处理中中最常用的4种句嵌入技术以及用于查找文本相似度的基本代码。这里小编建议大家使用更大的数据集来尝试这些模型。此外,这里只提供了计算句子相似度的基本代码。对于其他适合的模型,您需要首先对这些句子进行预处理,然后将它们转换为嵌入。

此外,小编这里并没有说没有其他流行的模式(包括FastSent, Skip-thought, Quick-thought, Word Movers Embedding等)

如果你已经尝试过这些或任何其他模式,请在评论中与我们分享!

欢迎点赞、收藏、留言!【自然语言处理】学习帐​www.zhihu.com

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值