词向量评价实战:相似度、类比与下游任务

发布时间:2026/10/26 5:07:07
词向量评价实战:相似度、类比与下游任务 1. 词向量评价到底在评什么训练完一批词向量文件夹里躺着一个几百兆的.vec这时候最想知道的就一件事它到底好不好用。词向量评价说白了就是回答这个问题的一套方法它不产生新模型只负责给已有的向量打分、排名、挑毛病。词向量本身是词的稠密实数表示语义相近的词在空间里距离近这个大家都知道但近到什么程度上算好近的方向对不对就必须靠评价来量化。我在实际项目里见过太多这样的情况有人把语料翻了三倍维度从 100 调到 300训练loss看着降了不少于是宣布新模型更好结果一接到下游任务上效果反而掉了两个点。loss 低只说明模型更会拟合训练语料的共现统计跟语义质量并不是一回事。词向量评价存在的意义就是把这层窗户纸捅破用外部的、和训练目标无关的标尺去衡量向量避免自我感觉良好。这套东西适合谁刚入门自然语言处理的同学需要一套能跑通的脚本和判断标准已经在做文本分类、检索、聚类的工程师需要在上线前给自己一个交代还有做垂直领域语料的团队通用的向量往往不好用得靠评价来验证领域微调到底有没有收益。不管你是哪一类核心诉求都一样用尽量小的成本得到一个可信的、能横向比较的分数。评价大体分两派。一派叫内在评价intrinsic直接拿向量本身做相似度判断、类比推理、聚类看结果和人工标注是否吻合另一派叫外在评价extrinsic把向量丢进真实任务看任务指标涨没涨。前者快、便宜、可解释后者准、贵、噪声大。真正靠谱的做法是两个都用先用内在评价快速筛掉明显不合格的版本再用外在评价做最终裁决。2. 内在评价不碰下游任务也能摸清底细2.1 相似度任务与 Spearman 相关系数相似度评价的逻辑特别朴素找一批词对人工给每对打个语义相关度分数然后让模型算余弦相似度最后比较两个序列的排序一致性。这里不能用 Pearson 相关系数因为人工打分的绝对尺度比如 0 到 10和余弦相似度的绝对尺度-1 到 1根本没有可比性我们关心的是谁比谁更相似这个相对顺序所以用 Spearman 秩相关取值范围 -1 到 1越接近 1 越好。公开的人工标注集有不少常见的是几百个词对规模的那种覆盖具体名词、抽象名词、动词、形容词。行业里的一般经验是在通用语料上训练的词向量Spearman 能到 0.6 到 0.75 之间算正常水平超过 0.75 已经不错低于 0.5 基本要怀疑训练配置或者语料有问题。但这个数字强依赖于评价集本身不同标注集的难度差异很大跨数据集比较没有意义只能在同一数据集内部比较不同模型。实操上有个坑必须提前说词对覆盖率。评价集里有些词在你的词表里压根不存在尤其是低频词、带连字符的词、专有名词。直接跳过这些词对会让分数虚高因为模型答不上来的题被剔除了剩下的都是它会的。正确做法是记录被跳过的比例如果超过 10%这个分数就不该拿去和别人比。我一般的处理是把覆盖率作为报告的一部分一起打出来而不是悄悄扔掉。2.2 类比任务king - man woman 的老把戏与新陷阱类比任务大概是词向量最出圈的玩法给a对b的关系找一个c使得c对某个d也满足同样的关系。经典例子是国王之于男人相当于王后之于女人向量运算写成vec(king) - vec(man) vec(woman)然后在词表里找余弦相似度最高的词看是不是queen。这个任务直观、好讲、适合做演示但它作为评价手段的可靠性一直被高估。原因有几个。第一类比集的构造成分很重很多题目是围绕少数几个高频关系批量生成的模型只要把这几个方向的偏移量学准分数就能刷上去泛化能力未必真好。第二答案往往不唯一king - man woman排第一的可能是queen也可能是princess、monarch只取 top-1 会低估模型。第三排除策略很关键算出来的向量最相似的三个词往往就是a、b、c本身必须把它们从候选里剔除否则准确率会莫名其妙地很高。我自己的做法是同时报 top-1 和 top-3 准确率并且明确写出排除策略。另外类比任务对词形很敏感如果语料里woman和women都高频出现模型的偏移方向会被复数形式带偏。做英文语料的时候我一般会先做词形归一或者干脆把不同词形的向量取平均效果通常更稳。还有一种更稳的变体叫 3CosMul把加法换成乘法再归一化公式大致是cos(b, b*) * cos(c, c*) / (cos(a, a*) ε)对小语料训练出来的向量更友好。我实测过在千万级 token 的语料上3CosMul 比 3CosAdd 稳定一些但在十亿级语料上差距不明显。2.3 聚类与异常词检测换个角度看看空间结构相似度和类比都是从点对角度看问题聚类和异常词检测则是从局部结构角度看。做法是挑一组语义上属于同一类的词比如若干种水果把它们聚成若干簇看同类的词是不是被分到同一个簇里。指标可以用纯度、NMI 或者简单的簇内平均距离。这个评价不像 Spearman 那样有标准分数更适合做定性观察和版本对比。异常词检测更好玩给一组词其中有一个语义上格格不入让模型把它揪出来。比如给苹果、香蕉、橘子、汽车模型应该指向汽车。这种题能有效暴露模型是不是把高频共现当成了语义因为汽车和水果在语料里几乎不共现能挑出来说明向量确实编码了类别信息。实际用的时候我会自己构造几十组这样的题目覆盖不同的抽象层级作为相似度评价的补充成本很低但很有诊断价值。3. 外在评价把向量丢进真实任务见真章3.1 下游任务怎么选、向量怎么用外在评价的核心问题是选什么任务。我的原则是选一个和你最终用途结构相似的任务。如果你的向量是要拿去做检索那就用句对匹配或者排序任务来评如果是要做分类特征就用文本分类如果是要做实体识别那就用序列标注。拿一个八竿子打不着的任务来评测出来的差距很可能来自任务本身的特性而不是向量的质量。向量在任务里的使用方式也直接决定结论。常见三种第一种是冻结把词向量当固定特征只训练上层的分类器这是最纯粹的评价方式因为它完全排除了向量被任务数据救回来的可能第二种是微调向量跟着一起训练这时候评价的其实是向量作为初始化的价值和向量本身质量是两回事第三种是直接算距离比如用平均词向量做句子表示然后算最近邻这种最轻量适合快速验证。我的建议是第一次评价一定用冻结方式得到一个干净的数字然后再用微调方式跑一遍看两者差距。如果微调之后差距被抹平了说明你的向量只是提供了个还行的起点本身没有特别的信息量如果冻结方式就明显更好那才是真的有用。3.2 控制变量别让评价被别的东西污染外在评价最怕的就是变量没控住。我踩过的坑包括换了向量同时也换了分词器结果差距不知道是谁贡献的训练集划分不一样测试集有重叠分数虚高随机种子不同跑了三次结果波动 3 个点却拿单次结果下结论。正确的做法是把所有和向量无关的因素全部固定下来同一份训练/验证/测试划分、同一个分类器结构、同一组超参数、同一批随机种子至少 3 个取均值并报告标准差。如果条件允许做配对显著性检验样本量小的时候差异很容易是噪声。我在一个中等规模的分类任务上做过实验同一个向量换 5 个种子准确率波动范围能到 1.8 个点所以低于 1 个点的差距我一律当作没有差异。还有一个容易忽略的点是词表对齐。外在评价用的任务数据里有些词在向量词表里不存在必须处理成 UNK 向量。UNK 向量怎么初始化影响很大全零、随机、或者是所有词向量的均值三种方式在小数据集上能差出好几个点。我一般用均值并且在报告里注明避免别人复现时对不上。4. 实操搭一套可复现的评价流程4.1 数据准备与词表对齐评价流程的第一步不是写代码是把数据理顺。需要准备三样东西向量文件、相似度评价集每行词1 词2 分数制表符分隔、类比评价集每行四个词空格分隔。格式定死后面的脚本就能通用。读写向量我用gensim的KeyedVectors它把词到索引的映射和矩阵分开了查词和批量算相似度都很快。加载大文件时用mmapr可以避免一次性吃满内存几百兆的文本向量文件大概几秒就能挂上。如果你的向量是自己训练的直接model.wv也能用但建议先save_word2vec_format落盘一份保证评价阶段用的是固定快照而不是训练中途的状态。import numpy as np from gensim.models import KeyedVectors from scipy.stats import spearmanr kv KeyedVectors.load_word2vec_format( vectors.vec, binaryFalse, mmapr ) print(词表大小:, len(kv.index_to_key), 维度:, kv.vector_size)跑任何评价之前先看一眼词表大小和维度再看几个高频词的最近邻确认向量没有加载错、没有维度错位。我曾经因为文件第一行的词数 维度头写错了导致整个矩阵错位评价分数低得离谱排查了半天才发现是格式问题。4.2 相似度与类比评测的实现相似度评测的核心就是逐对算余弦、收集分数、算秩相关。这里不用kv.similarity因为它内部会做额外的归一化处理自己写更可控也便于替换成欧氏距离等其他度量做对比。def cosine(u, v): nu, nv np.linalg.norm(u), np.linalg.norm(v) if nu 0 or nv 0: return 0.0 return float(np.dot(u, v) / (nu * nv)) def eval_similarity(kv, path): gold, pred, miss [], [], 0 with open(path, encodingutf-8) as f: for line in f: parts line.rstrip(\n).split(\t) if len(parts) ! 3: continue w1, w2, s parts if w1 not in kv or w2 not in kv: miss 1 continue gold.append(float(s)) pred.append(cosine(kv[w1], kv[w2])) if len(gold) 10: return None rho, _ spearmanr(gold, pred) cover len(gold) / (len(gold) miss) return {rho: round(rho, 4), n: len(gold), coverage: round(cover, 4)}覆盖率这个字段一定要打出来。我见过有人在只有 300 个词对、覆盖率 62% 的情况下报了个 0.81 的 Spearman拿去和覆盖率 95%、分数 0.72 的模型比结论完全反了。类比评测稍微复杂一点难点在候选排除和 top-k 统计。下面这版用kv.cosine_similarities一次性算完整个词表比逐个查快得多。def eval_analogy(kv, path, topk3): total hit1 hitk skip 0 for line in open(path, encodingutf-8): parts line.strip().split( ) if len(parts) ! 4: continue a, b, c, d parts if not all(w in kv for w in parts): skip 1 continue total 1 query kv[a] - kv[b] kv[c] sims kv.cosine_similarities(query, kv.vectors) order np.argsort(-sims) picked [] for idx in order: w kv.index_to_key[int(idx)] if w in (a, b, c): continue picked.append(w) if len(picked) topk: break if picked and picked[0] d: hit1 1 if d in picked: hitk 1 if total 0: return None return { top1: round(hit1 / total, 4), top3: round(hitk / total, 4), n: total, skipped: skip, }跑完这两个函数你就有了最基础的一组数字。别急着下结论先把它们和覆盖率、跳过量放在一起看。如果类比集的跳过量超过 20%说明你的词表太小或者词形处理没过关这时候的分数参考价值很低。4.3 结果记录与版本对比评价最容易犯的错是只跑一次记在脑子里一周后完全不记得当时用的什么配置。我现在的习惯是建一张表每次实验追加一行字段固定向量文件、训练语料来源和规模、维度、窗口、最小词频、相似度 rho、覆盖率、类比 top1、类比 top3、备注。版本语料规模维度窗口最小词频相似度 rho覆盖率类比 top1类比 top3v13000 万 token100550.6210.910.2840.512v23000 万 token200550.6480.930.3010.529v31.2 亿 token200530.7020.950.3520.581v41.2 亿 token200830.7110.950.3360.574v5词形归一1.2 亿 token200530.7240.970.3810.607这张表能看出很多东西。v1 到 v2 只调维度涨了 2 个多点说明维度不够是当时的瓶颈v2 到 v3 扩语料涨了 5 个多点说明语料规模比维度更重要v4 把窗口从 5 拉到 8相似度略涨但类比略降典型的话题集中度换来的代价v5 做词形归一两个指标都涨属于低成本高回报的操作。这些结论只有把数据摆在一起才看得出来。5. 常见问题与排查手册5.1 分数虚高的四个典型来源第一个是各向异性。训练出来的词向量往往不是均匀分布在球面上的而是挤在一个狭窄的锥形区域里导致任意两个词的余弦相似度都是 0.3 到 0.7 这种量级区分度被压缩。这种情况下相似度评价的绝对分数会偏高但不一定有意义。一个常用的缓解办法叫 all-but-the-top算所有词向量的均值并减掉再做 PCA 去掉前一到两个主成分然后再算相似度。我实测在中等规模语料上这个处理能让相似度评分的区分度明显提升但会不会改善下游任务要看具体情况不能一概而论。第二个是hubness。有些词莫名其妙地成为大量词的最近邻不管查什么都能撞上它这类词通常高频、语义泛化比如时间东西这类。检测方法是统计每个词出现在 top-10 最近邻里的次数画个分布如果少数词占了极大比例说明 hubness 严重。处理办法包括归一化、用 CSLS 做双向距离惩罚等。第三个是频率偏置。低频词的向量训练不充分方向基本是随机的但它们在评价集里往往被当作难题出现。如果评价集里低频词占比高分数就会整体偏低。这时候应该按词频分桶分别报告分数而不是只看总体。第四个是评价集泄漏。如果你用的评价集词汇大量出现在训练语料里这几乎必然模型对这些词学得特别准分数就会虚高。严格的做法的做法是把评价集的词从训练语料里去掉再训一遍但这不现实。退一步的做法是至少知道这件事别把 0.8 的 Spearman 当成模型懂语义的证据。5.2 排查速查表现象可能原因排查方法处理方式相似度 rho 低于 0.4语料太小或噪声大看词表大小、抽查最近邻扩语料加最小词频过滤分数极高但下游任务不涨各向异性或评价集偏简单算相似度分布、去主成分后重测去主成分、换更难的评价集覆盖率低于 0.8分词或词形不一致统计缺失词清单统一分词器做词形归一类比 top1 高但 top3 不高模型把答案排在 2、3 位打印错误样例本身不算问题报 top3 即可换种子波动超过 2 点评价集太小多种子重复扩评价集或用配对检验最近邻全是同一个词hubness统计 top-10 出现频次CSLS 或归一化处理中文效果明显差于英文分词粒度不匹配对比字级和词级向量尝试字级向量或混合粒度5.3 几个只有踩过才知道的细节大小写。英文语料里Apple和apple是不是合并对相似度评价影响不小。合并之后词频变高、向量更稳但专有名词的区分度丢了。我的做法是保留原始大小写训练评价时先精确匹配匹配不上再试小写形式这样既保住了信息又不至于让覆盖率掉太多。标点和特殊符号。评价集里出现带撇号的词比如缩写形式时如果你的分词器把撇号切掉了就永远匹配不上。这不是模型的问题是预处理链路不一致。统一用同一个分词器处理语料和评价集是最省事的解法。中文的分词粒度。中文词向量评价里最头疼的是切分歧义。研究生命起源切成研究/生命/起源还是研究生/命/起源直接决定词表里有没有研究生这个词。我一般的做法是同时准备词级和字级两套向量词级用于需要精确语义的任务字级用于覆盖率要求高的场景。字级向量的相似度评价没法直接用人标的词对得自己做映射麻烦但避开了 OOV。维度选择的经验值。不是越高越好。100 到 300 维是大多数场景的甜点区再往上收益递减而且小语料上高维更容易过拟合。我做过一组对比3000 万 token 的语料维度从 100 加到 300相似度涨了 3 个点从 300 加到 500只涨了不到 1 个点训练时间却翻倍。这个边际收益曲线值得每个人自己画一遍。6. 训练配置怎样影响最终评价分数6.1 窗口、负采样与最小词频窗口大小决定了模型看到多远的上下文。窗口小2 到 5学到的偏向于词性、句法层面的相似同义词、反义词容易挨得很近窗口大8 到 15学到的是话题层面的相似同领域的词会聚在一起。这直接体现在评价分数上用小窗口训练的向量在类比任务上通常更好因为句法关系更清晰用大窗口训练的在主题聚类类的评价上更好。所以看到窗口 5 比窗口 10 好这种结论时一定要问一句是在什么任务上比的。负采样数量影响的是训练的充分程度。默认的 5 到 15 在大多数语料上都够用样本量特别大的时候可以适当提高但边际收益也很有限。真正影响大的是最小词频。设成 1词表里塞满只出现一两次的词这些词的向量基本是噪声还会拉低相似度评价的覆盖率相关指标设成 5 到 10词表会小一圈但留下的都是相对可靠的。我一般设 5然后在报告里注明方便对比。还有一个经常被忽略的是下采样。高频词的是andthe在语料里占比极高不下采样的话它们会主导训练。常见做法是按词频的平方根倒数进行下采样阈值设在万分之一左右。这个操作对评价分数的影响是正向的尤其是相似度任务因为它让中频词获得了更多的训练信号。6.2 语料领域与评价集的匹配问题这是我最想强调的一点通用评价集上的高分不代表你的垂直领域能用。拿新闻语料训出来的向量去评医疗文本的相似度可能一堆词都不在词表里反过来用医疗语料训的向量去跑通用评价集覆盖率可能只有六七成分数自然难看。我一般的做法是准备两套评价一套通用评价集用来和公开结果做粗略对照一套自建的领域评价集几百个词对就够由业务方或者熟悉领域的人标注专门用来验证领域向量的质量。自建评价集的成本不高但价值极大因为它反映的是你真正关心的那部分语义。标注的时候有几个要点词对要覆盖高频和低频、具体和抽象、同义和相关但不完全同义不要全挑容易的每个词对至少两个人标一致性太低的重标或者剔除。领域评价集还有一个隐性好处它能暴露语料本身的偏差。比如你的语料全是产品评论那质量这个词的向量会严重偏向好/差的评价维度而不是物理意义上的质量。这种偏移在通用评价集上完全看不出来但在领域评价集上一目了然。7. 我自己的一套判断顺序跑了这么多轮下来我现在拿到一批新向量基本是按固定顺序过一遍的。先看词表大小和覆盖率覆盖率不到 0.85 的直接打回去查预处理然后抽十个高频词看最近邻肉眼判断有没有明显离谱的比如医生最近的邻居是护士病人就正常是但是因为就有问题接着跑相似度评价同时报分桶结果看低频词和高频词的差距有多大再跑类比 top1 和 top3最后才上外在评价。这个顺序的好处是前面几步都很快几分钟就能跑完能挡掉大部分明显不合格的版本不至于在一个坏向量上浪费半天做下游实验。外在评价我一般只跑一到两个任务多了没意义还会引入噪声。关于分数怎么看我的经验是不要追绝对值的极限要看增量是否稳定。同一个评价集上从 0.65 提到 0.70 可能是真提升但从 0.78 提到 0.79 很可能就是噪声。评价集本身的规模决定了它的分辨率上限几百个词对的评价集分辨不出 1 个点的差异。想要更细的区分唯一的办法是扩评价集而不是反复调训练参数去凑那个小数点。最后一个习惯每次评价完把错误样例存下来。相似度任务里那些人工打高分但模型算低分的词对类比任务里排第二第三的答案这些比分数本身有信息量得多。看多了你会发现模型的错误往往高度模式化集中在某几类语义关系上这种发现对下一步怎么改语料、怎么调参数比一个总分有用得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询