孙悟空 + 红楼梦 - 西游记 = ?
孙悟空 + 红楼梦 - 西游记 = ?
这样的脑洞数学题。01. 文字是怎么变成向量的
pip install gensim scikit-learn transformers matplotlib
from gensim.models import KeyedVectors
Literature
文学作品,并且加载该模型。# 加载中文词向量模型
word_vectors = KeyedVectors.load_word2vec_format('sgns.literature.word', binary=False)
print(f"'孙悟空'的向量的前四个维度:{word_vectors['孙悟空'].tolist()[:4]}")
'孙悟空'的向量的前四个维度:[-0.09262000024318695, -0.034056998789310455, -0.16306699812412262, -0.05771299824118614]
02.
语义更近,距离更近
IP
计算两个向量的距离,这里我们使用余弦相似度来计算。print(f"'孙悟空'和'猪八戒'向量的余弦相似度是:{word_vectors.similarity('孙悟空', '猪八戒'):.2f}")
print(f"'孙悟空'和'沙僧'向量的余弦相似度是:{word_vectors.similarity('孙悟空', '沙僧'):.2f}")
'孙悟空'和'猪八戒'向量的余弦相似度是:0.60
'孙悟空'和'沙僧'向量的余弦相似度是:0.59
# 查找与“孙悟空”最相关的4个词
similar_words = word_vectors.most_similar("孙悟空", topn=4)
print(f"与'孙悟空'最相关的4个词分别是:")
for word, similarity in similar_words:
print(f"{word}, 余弦相似度为:{similarity:.2f}")
与'孙悟空'最相关的4个词分别是:
悟空, 余弦相似度为:0.66
唐僧, 余弦相似度为:0.61
美猴王, 余弦相似度为:0.61
猪八戒, 余弦相似度为:0.60
# 导入用于数值计算的库
import numpy as np
# 定义要可视化的单词列表
words = ["西游记", "三国演义", "水浒传", "红楼梦",
"西瓜", "苹果", "香蕉", "梨",
"长江", "黄河"]
# 使用列表推导式获取每个单词的向量
vectors = np.array([word_vectors[word] for word in words])
# 导入用于降维的PCA类
from sklearn.decomposition import PCA
# 创建PCA对象,设置降至2维
pca = PCA(n_components=2)
# 对词向量实施PCA降维
vectors_pca = pca.fit_transform(vectors)
# 导入用于绘图的库
import matplotlib.pyplot as plt
# 创建一个5x5英寸的图
fig, axes = plt.subplots(1, 1, figsize=(7, 7))
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimSong']
# 确保负号能够正确显示
plt.rcParams['axes.unicode_minus'] = False
# 使用PCA降维后的前两个维度作为x和y坐标绘制散点图
axes.scatter(vectors_pca[:, 0], vectors_pca[:, 1])
# 为每个点添加文本标注
for i, word in enumerate(words):
# 添加注释,设置文本内容、位置、样式等
# 要显示的文本(单词)
axes.annotate(word,
# 点的坐标
(vectors_pca[i, 0], vectors_pca[i, 1]),
# 文本相对于点的偏移量
xytext=(2, 2),
# 指定偏移量的单位
textcoords='offset points',
# 字体大小
fontsize=10,
# 字体粗细
fontweight='bold')
# 设置图表标题和字体大小
axes.set_title('词向量', fontsize=14)
# 自动调整子图参数,使之填充整个图像区域
plt.tight_layout()
# 在屏幕上显示图表
plt.show()
apple
,最接近的5个词分别是 OS
、macintosh
、amiga
、ibm
和 microsoft
。03. 如果孙悟空穿越到红楼梦
result = word_vectors.most_similar(positive=["孙悟空", "红楼梦"], negative=["西游记"], topn=4)
print(f"孙悟空 + 红楼梦 - 西游记 = {result}")
孙悟空 + 红楼梦 - 西游记 = [('唐僧', 0.4163001477718353), ('贾宝玉', 0.41606390476226807), ('妙玉', 0.39432790875434875), ('沙和尚', 0.3922004997730255)]
result = word_vectors.most_similar(positive=["牛奶", "发酵"], topn=1)
print(f"牛奶 + 发酵 = {result[0][0]}")
result = word_vectors.most_similar(positive=["男人", "泰国"], topn=1)
print(f"男人 + 泰国 = {result[0][0]}")
牛奶 + 发酵 = 变酸
男人 + 泰国 = 女人
04.
一词多义怎么办# 从transformers库中导入BertTokenizer类和BertModel类
from transformers import BertTokenizer, BertModel
# 加载分词器 BertTokenizer
bert_tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
# 加载嵌入模型 BertModel
bert_model = BertModel.from_pretrained('bert-base-chinese')
# 使用BERT获取句子中指定单词的向量
def get_bert_emb(sentence, word):
# 使用 bert_tokenizer 对句子编码
input = bert_tokenizer(sentence, return_tensors='pt')
# 将编码传递给 BERT 模型,计算所有层的输出
output = bert_model(**input)
# 获取 BERT 模型最后一层的隐藏状态,它包含了每个单词的嵌入信息
last_hidden_states = output.last_hidden_state
# 将输入的句子拆分成单词,并生成一个列表
word_tokens = bert_tokenizer.tokenize(sentence)
# 获取目标单词在列表中的索引位置
word_index = word_tokens.index(word)
# 从最后一层隐藏状态中提取目标单词的嵌入表示
word_emb = last_hidden_states[0, word_index + 1, :]
# 返回目标单词的嵌入表示
return word_emb
sentence1 = "我今天很开心。"
sentence2 = "我打开了房门。"
word = "开"
# 使用 BERT 模型获取句子中指定单词的向量
bert_emb1 = get_bert_emb(sentence1, word).detach().numpy()
bert_emb2 = get_bert_emb(sentence2, word).detach().numpy()
# 使用词向量模型获取指定单词的向量
word_emb = word_vectors[word]
最后,查看这三个向量的区别。
print(f"在句子 '{sentence1}' 中,'{word}'的向量的前四个维度:{bert_emb1[: 4]}")
print(f"在句子 '{sentence2}' 中,'{word}'的向量的前四个维度:{bert_emb2[: 4]}")
print(f"在词向量模型中, '{word}' 的向量的前四个维度:{word_emb[: 4]}")
在句子 '我今天很开心。' 中,'开'的向量的前四个维度:[1.4325644 0.05137304 1.6045816 0.01002912]
在句子 '我打开了房门。' 中,'开'的向量的前四个维度:[ 0.9039772 -0.5877741 0.6639165 0.45880783]
在词向量模型中, '开' 的向量的前四个维度:[ 0.260962 0.040874 0.434256 -0.305888]
# 导入用于计算余弦相似度的函数
from sklearn.metrics.pairwise import cosine_similarity
# 计算两个BERT嵌入向量的余弦相似度
bert_similarity = cosine_similarity([bert_emb1], [bert_emb2])[0][0]
print(f"在 '{sentence1}' 和 '{sentence2}' 这两个句子中,两个 '{word}' 的余弦相似度是: {bert_similarity:.2f}")
# 计算词向量模型的两个向量之间的余弦相似度
word_similarity = cosine_similarity([word_emb], [word_emb])[0][0]
print(f"在词向量中, '{word}' 和 '{word}' 的余弦相似度是: {word_similarity:.2f}")
在 '我今天很开心。' 和 '我打开了房门。' 这两个句子中,两个 '开' 的余弦相似度是: 0.69
在词向量中, '开' 和 '开' 的余弦相似度是: 1.00
05.
怎么获得句子的向量# 导入 PyTorch 库
import torch
# 使用 BERT 模型获取句子的向量
def get_bert_sentence_emb(sentence):
# 使用 bert_tokenizer 对句子进行编码,得到 PyTorch 张量格式的输入
input = bert_tokenizer(sentence, return_tensors='pt')
# print(f"input: {input}")
# 将编码后的输入传递给 BERT 模型,计算所有层的输出
output = bert_model(**input)
# print(f"output: {output}")
# 获取 BERT 模型最后一层的隐藏状态,它包含了每个单词的嵌入信息
last_hidden_states = output.last_hidden_state
# 将所有词的向量求平均值,得到句子的表示
sentence_emb = torch.mean(last_hidden_states, dim=1).flatten().tolist()
# 返回句子的嵌入表示
return sentence_emb
pip install pymilvus "pymilvus[model]"
# 导入 bge_m3 模型
from pymilvus.model.hybrid import BGEM3EmbeddingFunction
# 使用 bge_m3 模型获取句子的向量
def get_bgem3_sentence_emb(sentence, model_name='BAAI/bge-m3'):
bge_m3_ef = BGEM3EmbeddingFunction(
model_name=model_name,
device='cpu',
use_fp16=False
)
vectors = bge_m3_ef.encode_documents([sentence])
return vectors['dense'][0].tolist()
sentence1 = "我喜欢这部电影!"
sentence2 = "这部电影太棒了!"
sentence3 = "我讨厌这部电影。"
# 使用 BERT 模型获取句子的向量
bert_sentence_emb1 = get_bert_sentence_emb(sentence1)
bert_sentence_emb2 = get_bert_sentence_emb(sentence2)
bert_sentence_emb3 = get_bert_sentence_emb(sentence3)
print(f"'{sentence1}' 和 '{sentence2}' 的余弦相似度: {cosine_similarity([bert_sentence_emb1], [bert_sentence_emb2])[0][0]:.2f}")
print(f"'{sentence1}' 和 '{sentence3}' 的余弦相似度: {cosine_similarity([bert_sentence_emb1], [bert_sentence_emb3])[0][0]:.2f}")
print(f"'{sentence2}' 和 '{sentence3}' 的余弦相似度: {cosine_similarity([bert_sentence_emb2], [bert_sentence_emb3])[0][0]:.2f}")
'我喜欢这部电影!' 和 '这部电影太棒了!' 的余弦相似度: 0.93
'我喜欢这部电影!' 和 '我讨厌这部电影。' 的余弦相似度: 0.94
'这部电影太棒了!' 和 '我讨厌这部电影。' 的余弦相似度: 0.89
# 使用 bge_m3 模型获取句子的向量
bgem3_sentence_emb1 = get_bgem3_sentence_emb(sentence1)
bgem3_sentence_emb2 = get_bgem3_sentence_emb(sentence2)
bgem3_sentence_emb3 = get_bgem3_sentence_emb(sentence3)
print(f"'{sentence1}' 和 '{sentence2}' 的余弦相似度: {cosine_similarity([bgem3_sentence_emb1], [bgem3_sentence_emb2])[0][0]:.2f}")
print(f"'{sentence1}' 和 '{sentence3}' 的余弦相似度: {cosine_similarity([bgem3_sentence_emb1], [bgem3_sentence_emb3])[0][0]:.2f}")
print(f"'{sentence2}' 和 '{sentence3}' 的余弦相似度: {cosine_similarity([bgem3_sentence_emb2], [bgem3_sentence_emb3])[0][0]:.2f}")
'我喜欢这部电影!' 和 '这部电影太棒了!' 的余弦相似度: 0.86
'我喜欢这部电影!' 和 '我讨厌这部电影。' 的余弦相似度: 0.65
'这部电影太棒了!' 和 '我讨厌这部电影。' 的余弦相似度: 0.57
06.
藏宝图词向量模型
Efficient Estimation of Word Representations in Vector Space (https://arxiv.org/abs/1301.3781) Distributed Representations of Words and Phrases and their Compositionality (https://arxiv.org/abs/1310.4546)
中文词向量模型
Chinese-Word-Vectors (https://github.com/Embedding/Chinese-Word-Vectors) 项目提供了上百种预训练的中文词向量,这些词向量是基于不同的表征、上下文特征和语料库训练的,可以用于各种中文自然语言处理任务。 腾讯 AI Lab 中英文词和短语的嵌入语料库 word2vec-Chinese (https://github.com/lzhenboy/word2vec-Chinese) 介绍了如何训练中文 Word2Vec 词向量模型。
BERT 模型
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding (https://arxiv.org/abs/1810.04805) ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT (https://arxiv.org/abs/2004.12832)
bge_m3 模型
注意力模型
模型库
gensim (https://radimrehurek.com/gensim/) 包含了 word2vec 模型和 GloVe(Global Vectors for Word Representation)模型。 Transformers (https://huggingface.co/transformers/) 是 Hugging Face 开发的一个开源库,专门用于自然语言处理(NLP)任务,它提供了大量预训练的 Transformer 模型,如 BERT、GPT、T5 等,并且支持多种语言和任务。 Chinese-BERT-wwm (https://github.com/ymcui/Chinese-BERT-wwm) 是哈工大讯飞联合实验室(HFL)发布的中文 BERT 模型。 pymilvus.model (https://milvus.io/docs/embeddings.md) 是 PyMilvus 客户端库的一个子包,提供多种嵌入模型的封装,用于生成向量嵌入,简化了文本转换过程。
作者介绍
Zilliz 黄金写手:江浩