使用BERT模型计算词余弦相似度获取相似词的可行性问询
方案可行性评估与优化建议
你提的这个方案存在几个明显的问题,直接按现有逻辑跑达不到gensim most_similar的效果:
- 首先你当前代码取的embedding完全不对:
outputs.pooler_output是 <[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token的输出经过全连接层和Tanh激活得到的句级表征,用来做文本分类这类句级任务的,根本不是你输入的单个词的词向量。如果要拿单个词的表征,应该取outputs.last_hidden_state中对应词token位置的输出,比如你输入单个词"Hello",分词后序列是<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>, hello, [SEP],取索引为1的位置的隐状态才是这个词的对应向量。 - 其次BERT自带的是子词词表,里面有大量不完整的子词(比如
##less、un##这类),直接全词表计算相似度会返回很多不是完整词语的无效结果,没法直接使用。 - 最后BERT是上下文依赖的预训练模型,单个孤立词的表征效果远不如Word2Vec、GloVe这类静态词向量,本身的设计逻辑就不是用来做静态相似词匹配的,最终得到的相似词结果大概率不如gensim自带的most_similar准确。
如果一定要基于BERT实现这个需求,可以按下面的逻辑调整方案,调整后是可以跑通的:
- 先预处理BERT的vocab.txt,过滤掉所有带
##前缀的子词,只保留完整的独立词作为候选集合 - 提前把所有候选完整词的词向量(取对应token的最后一层隐状态)批量计算好,存成向量库
- 查询时计算目标词向量和向量库所有向量的余弦相似度,取Top N的结果映射回对应词语即可
如果你的需求只是快速得到相似词,没有必须用BERT的强制要求,直接用gensim加载预训练的Word2Vec/GloVe向量调用most_similar是效率和效果都更好的选择。
内容的提问来源于stack exchange,提问作者DevPy
相关产品推荐
相关产品推荐

