向量嵌入与实战
向量嵌入(Vector Embeddings)是向量数据库的核心基础,其核心功能是将非结构化数据转换为高维向量,从而使其能在向量空间中实现存储、检索与分析。借助这一嵌入技术,文本、图像、音频等非结构化数据得以映射为具有语义关联性的向量表示,这为相似性搜索与数据挖掘提供了关键技术支撑。随着人工智能技术的持续发展,非结构化数据的应用范围正不断扩大。 本章开篇先系统介绍静态与动态向量嵌入的核心原理及实现路径,深入剖析二者在语义关系捕捉层面的独特优势与固有局限。通过聚焦数据降维技术在嵌入优化过程中的核心价值,具体阐释如何在有效降低数据复杂度的同时,最大限度保留关键语义信息。本章整体旨在为高效嵌入的生成与优化工作提供坚实的理论支撑与可落地的实践指引,进而为向量数据库系统的构建奠定核心技术基础。
1.静态向量嵌入
静态向量嵌入(Static Vector Embedding)是向量数据库中常用的非结构化数据处理方式,其核心逻辑是通过固定不变的映射规则,将文本、图像、音频等非结构化数据,转换为维度固定、数值稳定的连续型向量。一旦向量生成,其数值便不再随数据所处的上下文环境、应用场景变化;这些静态向量可存储于向量数据库中,依托余弦相似度、欧氏距离等相似性计算方法,高效实现数据的检索、聚类、分类等任务。
在静态向量嵌入的应用中,文本领域的传统词向量模型是典型代表 —— 这类模型专注于将离散的词汇(或子词)映射为固定的高维向量,从而捕捉词汇间的基础语义关联(如 “医生” 与 “医院” 的场景关联性、“篮球” 与 “足球” 的类别相似性),以提升文本处理效率。本节以介绍 Word2Vec 和 GloVe 这两个最常用的静态向量嵌入模型为例,介绍其核心原理、实现步骤及应用场景。
(1)Word2Vec Word2Vec 基于浅层神经网络架构,通过两种核心任务学习词汇的静态向量: CBOW(连续词袋模型):以 “上下文词汇” 为输入,训练模型预测 “目标中心词”,通过优化预测误差,让语义相近的词汇在向量空间中距离更近(如 “春天”“花开”“温暖” 的向量会聚集在相近区域); Skip-gram(跳字模型):与 CBOW 反向,以 “目标中心词” 为输入,预测 “其周围的上下文词汇”,更适用于处理低频词汇,能更精准学习罕见词的语义向量。 该模型的训练依赖局部上下文窗口(通常设置为 5-10 个词),仅捕捉窗口内的词汇关联,生成的每个词汇对应唯一向量(如 “手机” 在 “买手机”“用手机拍照” 中向量完全一致),且向量数值终身固定,属于典型的静态向量。
(2)GloVe(Global Vectors for Word Representation) GloVe 的核心优势在于结合全局语料信息,其训练逻辑不依赖神经网络,而是通过 “统计 - 优化” 两步实现: 统计全局共现频率:遍历整个语料库,统计 “目标词 - 上下文词” 共同出现的次数,构建 “词 - 词共现矩阵”(矩阵中每个元素代表两个词共同出现的频率,如 “国王” 与 “王后” 的共现频率高于 “国王” 与 “苹果”); 优化向量误差:通过数学模型预测 “目标词与上下文词的共现概率比”,并最小化 “预测值” 与 “共现矩阵中真实值” 的误差,最终生成每个词汇的固定向量。 相比 Word2Vec,GloVe 能更精准捕捉词汇间的线性语义关系(如 “国王 - 男人 + 女人 ≈ 王后” 的向量运算成立),但本质仍是静态向量 —— 词汇向量不随上下文变化,仅由全局语料的共现规律决定。
上面的文字表述有点抽象,这样我们换一种方式来表述: 我们可以把 “语言里的所有单词” 想象成 “一个巨大图书馆里的每一本书”,而 “单词之间的语义关系”,就像 “书和书之间的关联”(比如同主题、常被一起翻阅等)。Word2Vec 和 GloVe 这两个模型,就像是两种不同风格的 “图书整理员”,用不同方法帮我们找到书与书的关联,再把这种关联变成 “向量”(可以理解成一串数字,数字越像,单词语义越近)。
Word2Vec 更像一位 “喜欢观察邻居的管理员”—— 它整理图书时,不看全图书馆的所有书,只盯着 “每本书旁边的几本书”(对应模型里的 “上下文窗口”,比如看某本书前后 5 本相邻的书)。 它的工作逻辑很简单,就靠两个小任务训练: 比如看到 “苹果” 这本书旁边常放着 “水果”“甜的”“咬一口” 这些书,就试着 “根据旁边的书(如‘水果’‘甜的’)猜出中间的书是‘苹果’”; 或者反过来,看到 “苹果” 这本书,就试着 “猜出它旁边可能会放‘水果’‘甜的’这些书”。 练得多了,Word2Vec 就会发现:“苹果” 和 “水果” 总是紧挨着,“猫” 和 “狗”“鱼”“毛茸茸” 常相邻,于是就把这些语义相近的 “书”(单词),在向量里安排在离得近的位置。比如你查 “苹果” 的向量,会发现它和 “香蕉”“橘子” 的向量很像,和 “汽车”“电脑” 的向量差得很远 —— 这就是它通过 “看邻居” 找到的语义关联。
GloVe 则像一位 “爱做全面统计的管理员”—— 它不满足于只看 “某本书旁边的几本书”,而是会先做一件大事:给整个图书馆画一张 “全局统计表”。 这张表会记录: 每本书(比如 “苹果”)和其他所有书(比如 “水果”“公司”“甜的”“电脑”)“一起出现过多少次”; 再算出 “它们一起出现的概率”(比如 “苹果” 和 “水果” 一起出现的概率,是 “苹果” 和 “电脑” 一起出现概率的多少倍)。 通过分析这张全局表,GloVe 能同时抓住 “局部小关联” 和 “全局大规律”: 它也能像 Word2Vec 一样,知道 “苹果” 和 “水果” 关系近; 还能发现更细致的全局关联,比如 “国王” 和 “王后” 的关系,很像 “男人” 和 “女人” 的关系(这就是常说的 “国王 - 男人 + 女人 ≈ 王后” 的向量计算,靠全局统计才能更准确)。 不过要注意一个关键点:GloVe 虽然看的是全局数据,但它给 “苹果” 这本书只分配一个固定的向量—— 所以它没法区分 “苹果(水果)” 和 “苹果(公司)” 的不同含义,因为这两个意思共用同一个向量。它能发现 “苹果” 既常和 “水果” 一起出现,也常和 “公司” 一起出现,却没法把这两个意思分开。
静态向量嵌入虽能捕捉词汇的基础语义关联,但由于其 “一词一固定向量” 的核心特性,在处理复杂语言场景时存在显著局限性,具体可归纳为以下三点:
- 多义词语义混淆:无法区分词汇的歧义
例如:“苹果” 在 “今天吃了一个苹果”(水果语义)和 “新买的苹果手机很好用”(品牌语义)中,含义完全不同,但静态向量相同;
- 上下文场景信息丢失:忽略语义的场景依赖性
“跑步” 在 “清晨在公园跑步”(户外、有氧运动)和 “雨天在跑步机上跑步”(室内、器械运动)中,场景差异明显,但静态向量完全一致;
- 动态语义无法适配:向量固定且不可更新
“手机” 在十年前的语料中常与 “通话、短信” 关联,而现在常与 “5G、拍照、智能办公” 关联,但静态向量无法更新这种语义变化;
2.Python 代码实战:直观验证静态向量的语境不变性
为了更直观地展现静态向量的不足,我们以Word2Vec(静态向量代表模型) 为例,通过代码提取同一多义词在不同语境下的向量,验证其向量是否完全相同。
2.1 环境准备
首先安装依赖库(gensim提供 Word2Vec 的实现及预训练模型):
pip install gensim # 用于加载Word2Vec预训练模型
pip install numpy # 用于向量计算
pip install modelscope # 魔塔社区模型下载
2.2 代码实现:提取多义词在不同语境下的向量
我们选择两个典型多义词 ——“apple”(对应中文 “苹果”,含 “水果”“品牌” 歧义)和 “bank”(对应中文 “银行”,含 “金融机构”“河岸” 歧义),通过以下步骤验证: 加载预训练 Word2Vec 模型(采用 Google 新闻语料训练的 300 维模型,覆盖常见词汇); 构造不同语境的句子,提取目标词的向量; 计算同一词在不同语境下的余弦相似度(向量相同则相似度 = 1.0)和欧氏距离(向量相同则距离 = 0); 输出结果并分析。
模型文件可通过魔塔社区下载:https://www.modelscope.cn/models/lili666/text2vec-word2vec-tencent-chinese/summary 本次演示,使用腾讯词训练的 200 维模型,覆盖常见词汇。
import numpy as np
from gensim.models import KeyedVectors
def test_static_embedding(model, target_word, related_words1, related_words2, desc1, desc2):
"""
测试静态向量对多义词的处理能力(基于gensim)
:param model: gensim加载的KeyedVectors模型
:param target_word: 多义词
:param related_words1: 与语义1相关的词汇列表
:param related_words2: 与语义2相关的词汇列表
:param desc1: 语义1描述
:param desc2: 语义2描述
"""
# 检查目标词是否在模型词表中
if target_word not in model:
print(f"⚠️ 词汇'{target_word}'不在模型词表中")
return
# 1. 验证同一词在不同语境下的向量是否相同
vec1 = model[target_word] # 语义1对应的向量(静态模型中唯一)
vec2 = model[target_word] # 语义2对应的向量(静态模型中唯一)
# 计算余弦相似度(静态向量应恒为1.0)
cos_sim = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
print(f"\n=== 多义词:'{target_word}' ===")
print(f"语义1:{desc1};语义2:{desc2}")
print(f"两种语义下的向量余弦相似度:{cos_sim:.4f}(=1.0表示向量完全相同)")
# 2. 计算与两种语义相关词汇的相似度
print(f"\n【与{desc1}相关词汇的相似度】")
for word in related_words1:
if word in model:
# gensim的similarity方法直接计算词向量相似度
sim = model.similarity(target_word, word)
print(f"'{target_word}'与'{word}':{sim:.4f}")
print(f"\n【与{desc2}相关词汇的相似度】")
for word in related_words2:
if word in model:
sim = model.similarity(target_word, word)
print(f"'{target_word}'与'{word}':{sim:.4f}")
print("\n结论:静态向量无法区分多义词的不同语义,向量对两种相关词汇均有一定关联")
if __name__ == "__main__":
# 加载腾讯轻量版中文词向量(需替换为本地文件路径)
model_path = "./model/lili666/text2vec-word2vec-tencent-chinese/light_Tencent_AILab_ChineseEmbedding.bin" # 替换为你的模型文件路径
try:
# 腾讯模型为二进制格式,binary=True
model = KeyedVectors.load_word2vec_format(model_path, binary=True)
print("模型加载成功!")
except FileNotFoundError:
from modelscope import snapshot_download
model_dir = snapshot_download('lili666/text2vec-word2vec-tencent-chinese',cache_dir='./model')
except Exception as e:
print(f"模型加载失败:{e}")
exit()
# 测试:"苹果"(水果 vs 品牌)
test_static_embedding(
model=model,
target_word="打",
related_words_list=[
["拳头", "打架", "击打", "殴打"], # 语义1:击打
["游戏", "篮球", "排球", "比赛"], # 语义2:进行活动
["毛衣", "家具", "铁具", "编织"], # 语义3:制作/编织
["电话", "视频", "通讯", "号码"] # 语义4:通讯
],
desc_list=[
"击打(如:用拳头打)",
"进行活动(如:打游戏)",
"制作/编织(如:打毛衣)",
"通讯(如:打电话)"
]
)
=== 多义词:'打' ===
语义列表:['击打(如:用拳头打)', '进行活动(如:打游戏)', '制作/编织(如:打毛衣)', '通讯(如:打电话)']
任意两种语义下的向量余弦相似度:[1.0, 1.0, 1.0, 1.0, 1.0, 1.0](均为1.0,证明向量完全相同)
【与击打(如:用拳头打)相关词汇的相似度】
'打'与'拳头':0.4525
'打'与'打架':0.5573
'打'与'击打':0.4717
'打'与'殴打':0.3791
【与进行活动(如:打游戏)相关词汇的相似度】
'打'与'游戏':0.4393
'打'与'篮球':0.3739
'打'与'排球':0.4302
'打'与'比赛':0.5015
【与制作/编织(如:打毛衣)相关词汇的相似度】
'打'与'毛衣':0.3089
'打'与'家具':0.2496
'打'与'编织':0.3060
【与通讯(如:打电话)相关词汇的相似度】
'打'与'电话':0.5287
'打'与'视频':0.3960
'打'与'通讯':0.2415
'打'与'号码':0.4213
结论:静态向量对差异极大的多义词语义完全无法区分,向量同时关联所有语义的相关词,导致语义混乱
3.动态向量嵌入
动态向量嵌入是自然语言处理(NLP)领域的一次重要技术升级,可生成与上下文紧密关联的语义表示。与静态向量嵌入不同,动态嵌入不再依赖固定的词汇向量,而是结合具体句子结构与上下文语境,为每个输入文本(或 token)动态调整其向量表示。以 BERT、GPT 为代表的预训练语言模型,正是借助深度神经网络架构与核心的自注意力机制,实现了对上下文信息的精准捕捉,进而让多义词的语义区分、复杂句子的深层理解成为可能。
动态词向量嵌入模型(以 BERT、GPT 为代表)的核心突破在于:摆脱静态嵌入 “一个词对应一个固定向量” 的局限,能根据词语所在的上下文(如句子中前后词的含义、搭配关系)动态生成向量。
其技术实现依赖两大关键:
自注意力机制:精准计算词语与上下文其他词的关联权重,捕捉语义关联强度;
预训练任务:让模型在大规模文本数据中提前学习语义规律,为后续动态向量生成奠定基础。
最终生成的向量能精准反映词语在具体语境中的真实含义(例如 “银行” 在 “去银行取钱” 与 “河边有银行” 中,向量会因上下文差异完全不同)。
3.1 BERT:双向上下文理解的核心模型
(1)全称与定位
BERT(Bidirectional Encoder Representations from Transformers,即 “基于 Transformer 的双向编码器表示”)是专为文本理解场景设计的模型,核心优势是能同时从词语的 “左侧” 和 “右侧” 捕捉语义信息,适合需要深度解析文本含义的任务。
(2)核心技术:双向编码器 + 自注意力机制
基础架构:基于 Transformer 框架,但仅使用其中的 “编码器(Encoder)” 部分;
双向设计:分析任意词语时,模型会同时关注其左侧和右侧的所有上下文。
示例:分析句子 “小明在公园散步” 中的 “公园” 时,模型会同步关联左侧 “小明在” 与右侧 “散步”,通过自注意力机制计算 “公园” 与这两个片段的关联权重(如 “公园” 与 “散步” 的关联权重高于 “小明”),从而精准定位 “公园” 在该句中的语义角色(即 “散步的场所”)。
(3)预训练任务:遮掩语言模型(Masked Language Model, MLM)
MLM 任务的核心是让模型学习 “上下文语义关联”,具体流程如下:
从输入句子中随机挑选 15% 的词语,用特殊符号 “[MASK]” 替换(例如将 “猫在沙发上睡觉” 改为 “猫在 [MASK] 上睡觉”);
模型需基于 “[MASK]” 前后的双向上下文信息,预测被遮掩的原词;
经过大规模文本训练后,模型能掌握词语在不同语境下的搭配规律(如 “沙发” 常与 “上”“睡觉” 搭配),最终可生成 “词级”(单个词的向量)和 “句子级”(整个句子的向量)两类动态嵌入。
(4)输出特点与应用场景
向量特点:对 “上下文语义差异” 敏感度极高,能精准区分多义词在不同场景的含义;
适用任务:文本分类、情感分析、问答系统(如判断 “苹果” 是 “水果” 还是 “科技品牌”)、文本相似度计算等需 “深度理解文本含义” 的场景。
3.2 GPT:单向文本生成的标杆模型
(1)全称与定位
GPT(Generative Pre-trained Transformer,即 “生成式预训练 Transformer”)是专为文本生成场景设计的模型,核心优势是能基于 “前文内容” 预测后文,生成具有连贯性的上下文相关向量,在逐词产出文本的任务中表现突出。
(2)核心技术:单向解码器 + 自注意力机制
基础架构:基于 Transformer 框架,但仅使用其中的 “解码器(Decoder)” 部分(注:早期 GPT-1、GPT-2 为 “仅解码器架构”,聚焦单向序列建模);
单向设计:分析任意词语时,模型仅能关注其 “左侧前文”,无法提前获取右侧后文信息。
示例:分析句子 “小明早上起来后” 中的 “后” 时,模型仅能关联左侧 “小明早上起来”,无法预知右侧可能出现的 “去吃早餐”;自注意力机制在此处的作用是计算前文每个词对 “后” 的影响权重(如 “早上” 对 “后” 的关联权重高于 “小明”),确保模型按 “时间顺序” 理解文本逻辑。
(3)预训练任务:自回归语言模型(Autoregressive Language Model)
自回归任务的核心是让模型学习 “文本序列连贯性”,具体流程如下:
给模型输入一段文本的前 N 个词(例如 “今天天气很”),要求模型预测第 N+1 个词(可能输出 “好”“热”“冷” 等合理结果);
将 “前 N+1 个词” 作为新输入,继续让模型预测第 N+2 个词,以此类推(类似 “文本接龙”);
经过大规模训练后,模型能掌握文本的序列规律(如 “天气很” 后更可能接 “好” 而非 “苹果”),生成的词向量天然带有 “预测后文” 的属性,为后续生成任务提供支撑。
(4)输出特点与应用场景
向量特点:更侧重 “文本序列连贯性”,能保证生成内容的逻辑流畅性;
适用任务:文本生成(如文章写作、诗歌创作)、对话机器人(连续聊天)、机器翻译(逐句生成目标语言)、文本摘要等需 “逐词产出文本” 的场景。
4.Python 代码实战:直观验证动态向量
4.1 环境准备
首先安装依赖库(gensim提供 Word2Vec 的实现及预训练模型):
pip install transformers #加载模型
pip install torch # 深度学习框架
pip install modelscope #下载模型
4.2 直观比较动态向量的
模型文件可通过魔塔社区下载: https://www.modelscope.cn/models/iic/nlp_bert_entity-embedding_chinese-base/summary 本次演示项目使用阿里巴巴开源的Bert实体向量-中文-通用领域-base模型
import os
import numpy as np
import torch
from transformers import BertTokenizer, BertModel
def test_dynamic_embedding(tokenizer, bert_model, target_word, context_sentences, desc_list):
"""
测试动态向量(BERT)核心特性:多义词随上下文生成不同向量
:param tokenizer: BERT分词器(用于将句子转为模型可识别的token)
:param bert_model: BERT预训练模型(用于生成动态向量)
:param target_word: 待测试的多义词(如“打”)
:param context_sentences: 包含多义词的不同上下文句子(每种句子对应一种语义)
:param desc_list: 每个上下文句子对应的语义描述(与context_sentences一一对应)
"""
print("="*60)
print(f"【动态向量(BERT)测试:多义词'{target_word}'】")
dynamic_vecs = [] # 存储不同上下文下多义词的动态向量(含语义描述和句子)
# 1. 为每个上下文生成多义词的动态向量
for idx, (sentence, desc) in enumerate(zip(context_sentences, desc_list), 1):
# 步骤1:BERT分词(将自然句子转为token ID、注意力掩码)
inputs = tokenizer(
sentence,
return_tensors="pt", # 返回PyTorch张量(模型默认输入格式)
padding=True, # 自动补全长度(确保输入维度统一)
truncation=True # 自动截断过长句子(避免模型输入超界)
)
# 步骤2:通过BERT模型生成隐藏层输出(动态向量来自最后一层)
with torch.no_grad(): # 关闭梯度计算(仅推理,不训练,加快速度)
outputs = bert_model(**inputs)
# last_hidden_state:BERT最后一层隐藏层输出,形状为 [1, seq_len, hidden_size]
# 1=批次大小(单句子),seq_len=句子token数量,hidden_size=向量维度(BERT-base为768)
last_hidden_state = outputs.last_hidden_state
# 步骤3:定位多义词在token序列中的位置(确保提取正确词的向量)
token_ids = inputs["input_ids"][0].tolist() # 取出当前句子的所有token ID
target_token_id = tokenizer.convert_tokens_to_ids(target_word) # 多义词对应的token ID
try:
target_pos = token_ids.index(target_token_id) # 找到多义词在序列中的索引
except ValueError:
print(f"⚠️ 句子'{sentence}'中未找到'{target_word}',跳过该语境测试")
continue
# 步骤4:提取多义词的动态向量(对应位置的最后一层隐藏状态)
target_vec = last_hidden_state[0, target_pos, :].numpy() # 转为numpy数组(方便后续计算)
dynamic_vecs.append((target_vec, desc, sentence)) # 存储向量、语义描述、原句
# 打印当前语境的基础信息
print(f"\n--- 语境{idx}:{desc} ---")
print(f"上下文句子:{sentence}")
print(f"动态向量维度:{target_vec.shape[0]}(BERT-base默认768维)")
# 2. 计算不同语境下多义词的向量相似度(核心对比,体现动态特性)
print("\n" + "-"*50)
print("【关键对比:不同语境下动态向量的相似度】")
if len(dynamic_vecs) < 2:
print("⚠️ 有效语境不足2个,无法计算相似度对比")
return
# 遍历所有语境组合,计算余弦相似度
for i in range(len(dynamic_vecs)):
vec_i, desc_i, sent_i = dynamic_vecs[i]
for j in range(i + 1, len(dynamic_vecs)):
vec_j, desc_j, sent_j = dynamic_vecs[j]
# 余弦相似度公式:cosθ = (A·B) / (||A|| × ||B||)
cos_sim = np.dot(vec_i, vec_j) / (np.linalg.norm(vec_i) * np.linalg.norm(vec_j))
print(f"语境{i+1}({desc_i})与语境{j+1}({desc_j}):相似度 = {cos_sim:.4f}")
# 3. 总结动态向量核心特性
print("\n" + "-"*50)
print("【动态向量核心结论】")
print(f"1. 多义词'{target_word}'在不同语境下的向量相似度显著低于1.0(静态向量恒为1.0)")
print(f"2. 语义差异越大,向量相似度越低(例如“击打”与“编织”的相似度远低于“游戏”与“比赛”)")
print(f"3. 动态向量能精准捕捉上下文语义,解决静态向量“一词一向量”的局限性")
print("="*60)
if __name__ == "__main__":
# --------------------------
# 1. 加载BERT模型与分词器(仅依赖ModelScope)
# --------------------------
# 配置:ModelScope模型仓库ID + 本地保存路径(固定为ModelScope下载后的路径格式)
model_repo_id = "iic/nlp_bert_entity-embedding_chinese-base" # 用户指定的ModelScope模型
# ModelScope下载后,模型会保存在 cache_dir/仓库ID/版本 路径下,此处预设标准路径
local_model_dir = f"./model/{model_repo_id}/master"
tokenizer = None
bert_model = None
try:
# 第一步:检查本地是否已有ModelScope下载的模型
if os.path.exists(local_model_dir):
print(f"🔍 检测到本地ModelScope模型:{local_model_dir},正在加载...")
tokenizer = BertTokenizer.from_pretrained(local_model_dir)
bert_model = BertModel.from_pretrained(local_model_dir)
print("✅ 本地ModelScope模型加载成功!")
# 第二步:本地无模型,触发ModelScope下载
else:
from modelscope import snapshot_download
print(f"🔍 未检测到本地模型,开始通过ModelScope下载:{model_repo_id}")
# 调用ModelScope下载模型,指定缓存目录为./model
downloaded_dir = snapshot_download(
repo_id=model_repo_id,
cache_dir="./model", # 模型下载后自动保存在 ./model/仓库ID/master 下
revision="master" # 模型版本(固定为master,匹配预设的local_model_dir)
)
print(f"✅ 模型下载完成,保存路径:{downloaded_dir}")
# 从下载路径加载模型和分词器
tokenizer = BertTokenizer.from_pretrained(downloaded_dir)
bert_model = BertModel.from_pretrained(downloaded_dir)
print("✅ 从ModelScope下载路径加载模型成功!")
# 捕获所有模型加载相关错误(下载失败、路径错误、权限问题等)
except Exception as e:
print(f"❌ 模型加载失败:{str(e)}")
print("💡 建议:1. 检查网络连接(确保能访问ModelScope);2. 确认./model目录有写入权限;3. 无需手动修改路径,ModelScope会自动管理")
exit()
# --------------------------
# 2. 定义测试数据(多义词“打”的4种典型语境)
# --------------------------
target_word = "打" # 待测试的多义词
# 包含“打”的不同上下文句子(每种句子对应一种独特语义)
context_sentences = [
"他用拳头打坏人", # 语境1:击打动作
"他在电脑上打游戏", # 语境2:进行活动
"妈妈在灯下打毛衣", # 语境3:制作/编织
"他给家人打电话" # 语境4:通讯行为
]
# 每个语境对应的语义描述(与上下文句子一一对应)
desc_list = [
"击打动作(例:用拳头打坏人)",
"进行活动(例:打游戏、打篮球)",
"制作/编织(例:打毛衣、打家具)",
"通讯行为(例:打电话、打视频)"
]
# --------------------------
# 3. 执行动态向量测试
# --------------------------
test_dynamic_embedding(
tokenizer=tokenizer,
bert_model=bert_model,
target_word=target_word,
context_sentences=context_sentences,
desc_list=desc_list
)
--- 语境1:击打动作(例:用拳头打坏人) ---
上下文句子:他用拳头打坏人
动态向量维度:768(BERT-base默认768维)
--- 语境2:进行活动(例:打游戏、打篮球) ---
上下文句子:他在电脑上打游戏
动态向量维度:768(BERT-base默认768维)
--- 语境3:制作/编织(例:打毛衣、打家具) ---
上下文句子:妈妈在灯下打毛衣
动态向量维度:768(BERT-base默认768维)
--- 语境4:通讯行为(例:打电话、打视频) ---
上下文句子:他给家人打电话
动态向量维度:768(BERT-base默认768维)
--------------------------------------------------
【关键对比:不同语境下动态向量的相似度】
语境1(击打动作(例:用拳头打坏人))与语境2(进行活动(例:打游戏、打篮球)):相似度 = 0.8171
语境1(击打动作(例:用拳头打坏人))与语境3(制作/编织(例:打毛衣、打家具)):相似度 = 0.8417
语境1(击打动作(例:用拳头打坏人))与语境4(通讯行为(例:打电话、打视频)):相似度 = 0.7743
语境2(进行活动(例:打游戏、打篮球))与语境3(制作/编织(例:打毛衣、打家具)):相似度 = 0.8723
语境2(进行活动(例:打游戏、打篮球))与语境4(通讯行为(例:打电话、打视频)):相似度 = 0.8177
语境3(制作/编织(例:打毛衣、打家具))与语境4(通讯行为(例:打电话、打视频)):相似度 = 0.8096
--------------------------------------------------
【动态向量核心结论】
1. 多义词'打'在不同语境下的向量相似度显著低于1.0(静态向量恒为1.0)
2. 语义差异越大,向量相似度越低(例如“击打”与“编织”的相似度远低于“游戏”与“比赛”)
3. 动态向量能精准捕捉上下文语义,解决静态向量“一词一向量”的局限性