使用BERTClient计算余弦相似度时代码运行不终止,如何优化?
问题分析与代码优化
你的代码一直跑停不下来,核心问题是效率极低,还有几个细节疏漏,我给你拆解下问题和优化方案:
核心问题拆解
- 逐词编码的巨大开销:你在嵌套循环里每次单独调用
bc.encode([w]),20万个单词就要发起20万次编码请求(不管BERT服务是本地还是远程),这会产生海量的网络/计算开销,运行时间会夸张到离谱。 - 关键词未处理换行符:从文件读取的
keyword会自带换行符\n,比如原本是"apple",读出来会变成"apple\n",这会让BERT编码出错误的向量,影响相似度计算的准确性。 - 无意义的全量打印:你打印了100*20万=2亿个余弦值,这不仅完全没必要,还会拖慢程序运行速度。
- 未实现top50筛选逻辑:你的代码没有保存和排序相似度结果,根本没法得到每个关键词对应的top50相似词。
优化后的代码
下面是修正后的版本,用批量编码+批量计算相似度的方式,效率会提升几个数量级,同时实现你需要的top50功能:
from sklearn.metrics.pairwise import cosine_similarity from bert_serving.client import BertClient # 初始化BERT客户端 bc = BertClient() # 1. 读取并预处理所有单词:过滤空字符串,批量编码 with open("./words.txt", "r", encoding='utf8') as textfile: words = [word.strip() for word in textfile.read().split() if word.strip()] # 一次性批量编码所有单词,大幅减少编码请求次数 word_vectors = bc.encode(words) # 2. 读取并预处理关键词:过滤空行,去掉换行符 with open("./100_keywords.txt", "r", encoding='utf8') as keyword_file: keywords = [kw.strip() for kw in keyword_file if kw.strip()] # 3. 遍历每个关键词,计算相似度并筛选top50 for keyword in keywords: # 编码当前关键词 keyword_vector = bc.encode([keyword]) # 批量计算当前关键词与所有单词的余弦相似度 similarities = cosine_similarity(keyword_vector, word_vectors)[0] # 获取一维相似度数组 # 将单词与相似度配对,按相似度降序排序 word_similarity_pairs = list(zip(words, similarities)) word_similarity_pairs.sort(key=lambda x: x[1], reverse=True) # 提取top50结果 top50 = word_similarity_pairs[:50] # 输出结果(也可以写入文件方便后续查看) print(f"=== 关键词: {keyword} 的Top50相似词 ===") for idx, (word, score) in enumerate(top50, 1): print(f"{idx}. {word} - 相似度: {score:.4f}") print("\n")
额外优化建议
- 如果你的BERT服务是远程部署的,可以检查客户端的连接配置,确保批量传输的效率最优。
- 20万词的BERT向量(768维)大概占用600MB内存,一般机器都能承载;如果内存不足,可以分批次处理单词。
- 可以把结果写入文件而非打印,比如用
with open(f"{keyword}_top50.txt", "w", encoding='utf8') as f:来保存每个关键词的结果。
内容的提问来源于stack exchange,提问作者user93804




