StructBERT文本相似度模型Python入门实战从零构建文本匹配系统你是不是遇到过这样的场景手头有一堆用户提问想快速找到最相似的客服答案或者想给文章自动推荐相关的内容但不知道从何下手。文本相似度计算就是解决这类问题的核心技术。今天我们就来一起动手用Python和StructBERT模型从零开始搭建一个属于自己的中文文本相似度计算系统。StructBERT是阿里推出的一款强大的预训练语言模型它在理解句子结构方面有独到之处特别适合做文本匹配和相似度判断。整个过程就像搭积木我会一步步带你走就算你是Python新手跟着做也能跑通。我们的目标很明确安装好环境加载模型写几段代码最后让程序能告诉我们两句话到底有多像。准备好了吗我们开始吧。1. 动手之前环境与工具准备工欲善其事必先利其器。我们先来把“厨房”收拾好把需要的“食材”和“厨具”备齐。整个过程很简单就是几条命令的事。首先你需要一个Python环境。我强烈建议使用Python 3.8 或 3.9的版本这两个版本和后续要安装的包兼容性最好。你可以打开命令行Windows上是CMD或PowerShellMac/Linux上是终端输入python --version来检查。接下来我们需要一个包管理工具。这里我们用pip它是Python自带的通常不用单独安装。最重要的“食材”就是深度学习框架。StructBERT模型可以用PyTorch也可以用TensorFlow来加载为了简单直观我们这次选择PyTorch。安装PyTorch的命令稍微有点讲究因为它和你的电脑有没有显卡GPU有关。如果你电脑没有独立显卡或者想先确保能跑起来安装CPU版本就够了pip install torch torchvision torchaudio如果你有NVIDIA显卡并且想体验更快的计算速度可以去PyTorch官网https://pytorch.org/get-started/locally/根据你的系统配置生成安装命令。不过对于入门学习CPU版本完全够用速度也不慢。安装好PyTorch后我们还需要几个帮手pip install transformers pip install numpy pip install pandas pip install scikit-learn pip install matplotlib我来简单说说它们都是干嘛的transformers这是Hugging Face公司出的神器里面集成了成千上万个预训练模型包括我们的StructBERT我们直接用就行省去了自己从头训练的麻烦。numpy和pandas处理数据和表格的好帮手。scikit-learn机器学习工具箱我们用它来计算一些评估指标。matplotlib画图工具最后我们可以把结果可视化出来。一条条执行这些安装命令可能需要几分钟时间。如果遇到网络慢或者某个包装不上的情况可以试试在命令后面加上-i https://pypi.tuna.tsinghua.edu.cn/simple来使用国内的镜像源速度会快很多。全部安装完成后我们可以写个简单的测试脚本确保环境没问题。新建一个Python文件比如叫test_env.py写入以下内容import torch import transformers print(fPyTorch版本: {torch.__version__}) print(fTransformers版本: {transformers.__version__}) print(环境测试通过)运行它如果没报错并且能看到版本号输出那么恭喜你环境搭建成功2. 核心概念五分钟入门在写代码之前我们花五分钟搞清楚我们要用的东西到底是什么这样后面每一步你都知道自己在干什么。文本相似度计算顾名思义就是量化两段文本之间的相似程度。比如“今天天气真好”和“阳光明媚的一天”虽然字不一样但意思很接近相似度就应该很高。而“今天天气真好”和“我喜欢编程”相似度就应该很低。这个相似度通常用一个0到1之间的数字来表示1代表完全相同0代表完全无关。那么StructBERT是怎么做到的呢你可以把它想象成一个读过海量中文书籍和文章的“语言专家”。它不光知道每个词的意思还特别擅长理解句子的结构。比如“猫追老鼠”和“老鼠被猫追”词序变了但意思基本一样。StructBERT通过它的训练方式能很好地捕捉到这种结构上的等价关系所以在判断句子是否相似时比只看词语的模型更准。我们这次要用的具体模型是structbert-base-chinese这是一个中文基础版大小适中效果不错非常适合我们入门学习。整个计算流程可以概括为三步预处理把原始的中文句子转换成模型能“吃”下去的格式一堆数字。模型推理把处理好的数据喂给StructBERT模型让它“思考”并产出两个句子的综合向量表示。相似度计算比较这两个向量算出它们之间的余弦相似度这个值就是我们的最终结果。听起来是不是没那么复杂了接下来我们就用代码把这三步实现出来。3. 分步实战搭建你的相似度计算器现在进入最核心的动手环节。我们会一步步创建几个函数最终组合成一个完整的文本相似度计算工具。我建议你跟着我一起写每一步都运行一下看看结果。3.1 第一步请出我们的主角——加载模型首先我们需要从transformers库中把StructBERT模型和它配套的分词器“请”出来。分词器的作用是把句子切分成词或字元并转换成模型认识的ID。新建一个Python文件命名为text_similarity.py。我们开始写代码from transformers import AutoTokenizer, AutoModel import torch import numpy as np # 1. 加载预训练模型和分词器 model_name alibaba-pai/structbert-base-chinese print(f正在加载模型和分词器: {model_name}...) tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModel.from_pretrained(model_name) print(模型加载成功)这里我们用了AutoTokenizer和AutoModel这两个类它们很智能只要给出模型的名字就能自动识别并加载对应的架构和权重。alibaba-pai/structbert-base-chinese就是我们要用的模型在Hugging Face模型库上的地址。第一次运行这段代码时它会从网上下载模型文件大约400MB所以需要一点时间。下载完成后模型就会保存在本地下次再运行就快了。3.2 第二步给句子“化妆”——文本预处理函数模型不能直接处理汉字我们需要通过分词器把句子转换成“输入张量”。同时对于相似度任务我们通常需要处理两个句子。# 2. 定义文本预处理函数 def preprocess_texts(text_a, text_b): 将两个中文句子预处理为模型需要的输入格式。 # 使用分词器对句子进行编码 # return_tensorspt 表示返回PyTorch张量 # truncationTrue 表示如果句子太长就截断 # paddingTrue 表示如果句子长度不一就填充到一样长 encoded_inputs tokenizer(text_a, text_b, return_tensorspt, truncationTrue, paddingTrue, max_length128) # 设置最大长度为128个token return encoded_inputs # 我们来测试一下这个函数 test_sentence1 深度学习非常有趣。 test_sentence2 机器学习是一个有趣的领域。 inputs preprocess_texts(test_sentence1, test_sentence2) print(预处理后的输入键名:, inputs.keys()) print(输入ID的形状:, inputs[input_ids].shape)运行后你会看到输出类似input_ids和attention_mask这样的键。input_ids就是句子转换成的数字ID序列attention_mask告诉模型哪些位置是真实的词哪些是填充的。这就是模型的标准“食粮”。3.3 第三步让模型“思考”——获取句子向量模型吃下“食粮”后会输出每个输入token的向量表示。我们需要从中提取出整个句子的一个综合向量。一个简单有效的方法是取出模型输出的第一个token[CLS] token的向量它通常被训练用于代表整个句子的语义。# 3. 定义函数获取句子的向量表示 def get_sentence_vectors(text_a, text_b): 输入两个句子返回它们对应的向量。 # 预处理 inputs preprocess_texts(text_a, text_b) # 不计算梯度加快推理速度 with torch.no_grad(): # 模型前向传播 outputs model(**inputs) # 取最后一层隐藏状态形状为 (batch_size, sequence_length, hidden_size) last_hidden_states outputs.last_hidden_state # 我们取每个句子第一个token ([CLS]) 的向量作为句子表示 # 因为输入是两个句子所以batch_size是1我们取第0个 vector_a last_hidden_states[0, 0, :] # 第一个句子的[CLS]向量 vector_b last_hidden_states[0, 1, :] # 第二个句子的[CLS]向量等等这里不对 # 注意上面的取法不对当两个句子一起输入时它们被拼接成了一个序列。 # 正确的做法是我们分别对每个句子单独获取向量。 return vector_a, vector_b # 修正后的函数分别处理每个句子 def get_single_sentence_vector(text): 获取单个句子的向量 inputs tokenizer(text, return_tensorspt, truncationTrue, paddingTrue, max_length128) with torch.no_grad(): outputs model(**inputs) # 取[CLS] token的向量 cls_vector outputs.last_hidden_state[0, 0, :] return cls_vector def get_sentence_vectors_correct(text_a, text_b): 分别获取两个句子的向量 vector_a get_single_sentence_vector(text_a) vector_b get_single_sentence_vector(text_b) return vector_a, vector_b # 测试修正后的函数 vec1, vec2 get_sentence_vectors_correct(test_sentence1, test_sentence2) print(句子1向量形状:, vec1.shape) print(句子2向量形状:, vec2.shape)看我们得到了两个形状为(768,)的向量。768就是这个模型隐藏层的大小你可以理解为模型用768个数字来编码这个句子的所有语义信息。3.4 第四步计算“亲密度”——相似度计算函数有了两个句子的向量怎么衡量它们的相似度呢最常用的方法是计算它们的余弦相似度。你可以想象两个向量是两个箭头余弦相似度就是看这两个箭头方向有多接近。方向越一致值越接近1方向垂直值为0方向相反值接近-1。对于表示语义的向量我们通常关注正方向。# 4. 定义余弦相似度计算函数 def cosine_similarity(vec_a, vec_b): 计算两个向量的余弦相似度。 # 将PyTorch张量转换为numpy数组以便计算 if torch.is_tensor(vec_a): vec_a vec_a.numpy() if torch.is_tensor(vec_b): vec_b vec_b.numpy() # 点积 dot_product np.dot(vec_a, vec_b) # 模长 norm_a np.linalg.norm(vec_a) norm_b np.linalg.norm(vec_b) # 避免除以零 if norm_a 0 or norm_b 0: return 0.0 similarity dot_product / (norm_a * norm_b) return similarity # 5. 整合所有步骤一个完整的相似度计算函数 def calculate_similarity(text_a, text_b): 一站式计算两个中文文本的相似度。 print(f计算相似度\n A: {text_a}\n B: {text_b}) # 获取向量 vec_a, vec_b get_sentence_vectors_correct(text_a, text_b) # 计算余弦相似度 sim_score cosine_similarity(vec_a, vec_b) print(f 余弦相似度得分: {sim_score:.4f}) return sim_score3.5 第五步开箱即用——测试你的系统所有零件都造好了现在让我们组装起来试试效果。在同一个文件的最后我们写一个测试部分# 6. 测试一些例子 if __name__ __main__: print(*50) print(StructBERT文本相似度计算系统测试) print(*50) # 例子1同义句 score1 calculate_similarity(今天天气真好, 阳光明媚的一天) # 例子2反义句 score2 calculate_similarity(我喜欢吃苹果, 我讨厌吃苹果) # 例子3不相关句 score3 calculate_similarity(深度学习需要GPU, 西湖的景色非常美丽) # 例子4长句测试 score4 calculate_similarity( 自然语言处理是人工智能的一个重要分支它使计算机能够理解、解释和生成人类语言。, NLP技术致力于让机器读懂人类的文字和语言是AI领域的核心方向之一。 ) print(\n测试完成)运行你的text_similarity.py文件。你会看到程序依次加载模型然后对四组句子输出相似度得分。不出意外的话第一组和第四组的得分会比较高可能0.7-0.9第二组次之第三组应该最低可能低于0.3。这说明我们的系统已经能像模像样地工作啦4. 让结果更直观简单可视化数字可能不够直观我们用一个简单的条形图把刚才测试的结果画出来这样一眼就能看出差别。我们在同一个文件中添加一个可视化函数需要先安装matplotlibimport matplotlib.pyplot as plt def visualize_results(text_pairs, scores): 可视化相似度结果。 text_pairs: 列表每个元素是一个元组 (text_a, text_b) scores: 对应的相似度分数列表 labels [f例{i1} for i in range(len(scores))] plt.figure(figsize(10, 6)) bars plt.bar(labels, scores, colorskyblue) # 在每个条形上添加数值 for bar, score in zip(bars, scores): height bar.get_height() plt.text(bar.get_x() bar.get_width()/2., height 0.01, f{score:.3f}, hacenter, vabottom) plt.axhline(y0.5, colorr, linestyle--, alpha0.5, label阈值 (0.5)) plt.ylim(0, 1.1) plt.ylabel(余弦相似度) plt.title(文本相似度计算结果可视化) plt.legend() plt.grid(axisy, alpha0.3) plt.tight_layout() plt.show() # 修改主测试部分收集结果并可视化 if __name__ __main__: print(*50) print(StructBERT文本相似度计算系统测试) print(*50) test_cases [ (今天天气真好, 阳光明媚的一天), (我喜欢吃苹果, 我讨厌吃苹果), (深度学习需要GPU, 西湖的景色非常美丽), (自然语言处理是人工智能的一个重要分支它使计算机能够理解、解释和生成人类语言。, NLP技术致力于让机器读懂人类的文字和语言是AI领域的核心方向之一。) ] scores [] for i, (text_a, text_b) in enumerate(test_cases): print(f\n[例子 {i1}]) score calculate_similarity(text_a, text_b) scores.append(score) # 可视化结果 visualize_results(test_cases, scores) print(\n测试完成结果已可视化。)再次运行这次不仅会输出数字还会弹出一个图表窗口清晰地展示四个例子的相似度高低红色虚线可以作为一个简单的参考阈值。5. 你可能遇到的问题与小技巧第一次跑通很有成就感但实际用的时候可能会碰到一些小麻烦。这里我分享几个常见问题和处理技巧。问题1运行时报错CUDA out of memory或者特别慢。原因模型在GPU上运行但显存不够或者你希望用CPU。解决在加载模型后显式指定使用CPU。model AutoModel.from_pretrained(model_name) model model.to(cpu) # 强制使用CPU或者在计算时确保输入张量也在CPU上。问题2句子太长结果好像不准。原因我们预处理时设置了max_length128超过的部分被截断了。解决对于长文本如段落可以考虑其他策略比如将长文本分句计算每句的相似度再综合或者使用专门处理长文本的模型。对于入门可以先确保输入的句子不要太长。问题3我想批量计算很多句子对的相似度怎么办解决你可以修改get_single_sentence_vector函数让它接受一个句子列表并利用批处理能力。核心是分词时一个列表传进去并且模型会批量处理。def get_batch_vectors(text_list): inputs tokenizer(text_list, return_tensorspt, truncationTrue, paddingTrue, max_length128) with torch.no_grad(): outputs model(**inputs) # 取出每个句子的[CLS]向量形状是 (batch_size, hidden_size) batch_vectors outputs.last_hidden_state[:, 0, :] return batch_vectors然后一次性计算所有向量再两两计算相似度效率会高很多。提升效果小技巧尝试不同的句子向量提取方法除了用[CLS]也可以试试对所有token的向量取平均mean pooling或取最大值max pooling有时候效果会不一样。微调模型如果你有特定领域的数据比如医疗问答对、法律条文可以用这些数据对StructBERT进行微调让它在你关心的领域表现更好。不过这属于进阶内容了。整体走下来你会发现用Python和现成的模型库搭建一个文本相似度系统并没有想象中那么难。关键是把流程拆解清楚准备环境、加载模型、处理数据、计算向量、比较相似度。我们完成的这个系统虽然简单但已经具备了核心功能你可以把它用到自己的小项目里比如做一个简单的问答匹配或者给文章做去重。当然这只是一个起点。StructBERT还有很多能力可以挖掘比如它本身就可以直接用于句子对分类任务判断是否相似。transformers库也提供了更高级的接口比如AutoModelForSequenceClassification可以直接输出相似与否的概率你可以去探索一下。最重要的是你亲手跑通了整个流程这种体验比读十篇教程都有用。接下来就试着用你自己的句子去测试看看它的表现吧。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
StructBERT文本相似度模型Python入门实战:从零构建文本匹配系统
StructBERT文本相似度模型Python入门实战从零构建文本匹配系统你是不是遇到过这样的场景手头有一堆用户提问想快速找到最相似的客服答案或者想给文章自动推荐相关的内容但不知道从何下手。文本相似度计算就是解决这类问题的核心技术。今天我们就来一起动手用Python和StructBERT模型从零开始搭建一个属于自己的中文文本相似度计算系统。StructBERT是阿里推出的一款强大的预训练语言模型它在理解句子结构方面有独到之处特别适合做文本匹配和相似度判断。整个过程就像搭积木我会一步步带你走就算你是Python新手跟着做也能跑通。我们的目标很明确安装好环境加载模型写几段代码最后让程序能告诉我们两句话到底有多像。准备好了吗我们开始吧。1. 动手之前环境与工具准备工欲善其事必先利其器。我们先来把“厨房”收拾好把需要的“食材”和“厨具”备齐。整个过程很简单就是几条命令的事。首先你需要一个Python环境。我强烈建议使用Python 3.8 或 3.9的版本这两个版本和后续要安装的包兼容性最好。你可以打开命令行Windows上是CMD或PowerShellMac/Linux上是终端输入python --version来检查。接下来我们需要一个包管理工具。这里我们用pip它是Python自带的通常不用单独安装。最重要的“食材”就是深度学习框架。StructBERT模型可以用PyTorch也可以用TensorFlow来加载为了简单直观我们这次选择PyTorch。安装PyTorch的命令稍微有点讲究因为它和你的电脑有没有显卡GPU有关。如果你电脑没有独立显卡或者想先确保能跑起来安装CPU版本就够了pip install torch torchvision torchaudio如果你有NVIDIA显卡并且想体验更快的计算速度可以去PyTorch官网https://pytorch.org/get-started/locally/根据你的系统配置生成安装命令。不过对于入门学习CPU版本完全够用速度也不慢。安装好PyTorch后我们还需要几个帮手pip install transformers pip install numpy pip install pandas pip install scikit-learn pip install matplotlib我来简单说说它们都是干嘛的transformers这是Hugging Face公司出的神器里面集成了成千上万个预训练模型包括我们的StructBERT我们直接用就行省去了自己从头训练的麻烦。numpy和pandas处理数据和表格的好帮手。scikit-learn机器学习工具箱我们用它来计算一些评估指标。matplotlib画图工具最后我们可以把结果可视化出来。一条条执行这些安装命令可能需要几分钟时间。如果遇到网络慢或者某个包装不上的情况可以试试在命令后面加上-i https://pypi.tuna.tsinghua.edu.cn/simple来使用国内的镜像源速度会快很多。全部安装完成后我们可以写个简单的测试脚本确保环境没问题。新建一个Python文件比如叫test_env.py写入以下内容import torch import transformers print(fPyTorch版本: {torch.__version__}) print(fTransformers版本: {transformers.__version__}) print(环境测试通过)运行它如果没报错并且能看到版本号输出那么恭喜你环境搭建成功2. 核心概念五分钟入门在写代码之前我们花五分钟搞清楚我们要用的东西到底是什么这样后面每一步你都知道自己在干什么。文本相似度计算顾名思义就是量化两段文本之间的相似程度。比如“今天天气真好”和“阳光明媚的一天”虽然字不一样但意思很接近相似度就应该很高。而“今天天气真好”和“我喜欢编程”相似度就应该很低。这个相似度通常用一个0到1之间的数字来表示1代表完全相同0代表完全无关。那么StructBERT是怎么做到的呢你可以把它想象成一个读过海量中文书籍和文章的“语言专家”。它不光知道每个词的意思还特别擅长理解句子的结构。比如“猫追老鼠”和“老鼠被猫追”词序变了但意思基本一样。StructBERT通过它的训练方式能很好地捕捉到这种结构上的等价关系所以在判断句子是否相似时比只看词语的模型更准。我们这次要用的具体模型是structbert-base-chinese这是一个中文基础版大小适中效果不错非常适合我们入门学习。整个计算流程可以概括为三步预处理把原始的中文句子转换成模型能“吃”下去的格式一堆数字。模型推理把处理好的数据喂给StructBERT模型让它“思考”并产出两个句子的综合向量表示。相似度计算比较这两个向量算出它们之间的余弦相似度这个值就是我们的最终结果。听起来是不是没那么复杂了接下来我们就用代码把这三步实现出来。3. 分步实战搭建你的相似度计算器现在进入最核心的动手环节。我们会一步步创建几个函数最终组合成一个完整的文本相似度计算工具。我建议你跟着我一起写每一步都运行一下看看结果。3.1 第一步请出我们的主角——加载模型首先我们需要从transformers库中把StructBERT模型和它配套的分词器“请”出来。分词器的作用是把句子切分成词或字元并转换成模型认识的ID。新建一个Python文件命名为text_similarity.py。我们开始写代码from transformers import AutoTokenizer, AutoModel import torch import numpy as np # 1. 加载预训练模型和分词器 model_name alibaba-pai/structbert-base-chinese print(f正在加载模型和分词器: {model_name}...) tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModel.from_pretrained(model_name) print(模型加载成功)这里我们用了AutoTokenizer和AutoModel这两个类它们很智能只要给出模型的名字就能自动识别并加载对应的架构和权重。alibaba-pai/structbert-base-chinese就是我们要用的模型在Hugging Face模型库上的地址。第一次运行这段代码时它会从网上下载模型文件大约400MB所以需要一点时间。下载完成后模型就会保存在本地下次再运行就快了。3.2 第二步给句子“化妆”——文本预处理函数模型不能直接处理汉字我们需要通过分词器把句子转换成“输入张量”。同时对于相似度任务我们通常需要处理两个句子。# 2. 定义文本预处理函数 def preprocess_texts(text_a, text_b): 将两个中文句子预处理为模型需要的输入格式。 # 使用分词器对句子进行编码 # return_tensorspt 表示返回PyTorch张量 # truncationTrue 表示如果句子太长就截断 # paddingTrue 表示如果句子长度不一就填充到一样长 encoded_inputs tokenizer(text_a, text_b, return_tensorspt, truncationTrue, paddingTrue, max_length128) # 设置最大长度为128个token return encoded_inputs # 我们来测试一下这个函数 test_sentence1 深度学习非常有趣。 test_sentence2 机器学习是一个有趣的领域。 inputs preprocess_texts(test_sentence1, test_sentence2) print(预处理后的输入键名:, inputs.keys()) print(输入ID的形状:, inputs[input_ids].shape)运行后你会看到输出类似input_ids和attention_mask这样的键。input_ids就是句子转换成的数字ID序列attention_mask告诉模型哪些位置是真实的词哪些是填充的。这就是模型的标准“食粮”。3.3 第三步让模型“思考”——获取句子向量模型吃下“食粮”后会输出每个输入token的向量表示。我们需要从中提取出整个句子的一个综合向量。一个简单有效的方法是取出模型输出的第一个token[CLS] token的向量它通常被训练用于代表整个句子的语义。# 3. 定义函数获取句子的向量表示 def get_sentence_vectors(text_a, text_b): 输入两个句子返回它们对应的向量。 # 预处理 inputs preprocess_texts(text_a, text_b) # 不计算梯度加快推理速度 with torch.no_grad(): # 模型前向传播 outputs model(**inputs) # 取最后一层隐藏状态形状为 (batch_size, sequence_length, hidden_size) last_hidden_states outputs.last_hidden_state # 我们取每个句子第一个token ([CLS]) 的向量作为句子表示 # 因为输入是两个句子所以batch_size是1我们取第0个 vector_a last_hidden_states[0, 0, :] # 第一个句子的[CLS]向量 vector_b last_hidden_states[0, 1, :] # 第二个句子的[CLS]向量等等这里不对 # 注意上面的取法不对当两个句子一起输入时它们被拼接成了一个序列。 # 正确的做法是我们分别对每个句子单独获取向量。 return vector_a, vector_b # 修正后的函数分别处理每个句子 def get_single_sentence_vector(text): 获取单个句子的向量 inputs tokenizer(text, return_tensorspt, truncationTrue, paddingTrue, max_length128) with torch.no_grad(): outputs model(**inputs) # 取[CLS] token的向量 cls_vector outputs.last_hidden_state[0, 0, :] return cls_vector def get_sentence_vectors_correct(text_a, text_b): 分别获取两个句子的向量 vector_a get_single_sentence_vector(text_a) vector_b get_single_sentence_vector(text_b) return vector_a, vector_b # 测试修正后的函数 vec1, vec2 get_sentence_vectors_correct(test_sentence1, test_sentence2) print(句子1向量形状:, vec1.shape) print(句子2向量形状:, vec2.shape)看我们得到了两个形状为(768,)的向量。768就是这个模型隐藏层的大小你可以理解为模型用768个数字来编码这个句子的所有语义信息。3.4 第四步计算“亲密度”——相似度计算函数有了两个句子的向量怎么衡量它们的相似度呢最常用的方法是计算它们的余弦相似度。你可以想象两个向量是两个箭头余弦相似度就是看这两个箭头方向有多接近。方向越一致值越接近1方向垂直值为0方向相反值接近-1。对于表示语义的向量我们通常关注正方向。# 4. 定义余弦相似度计算函数 def cosine_similarity(vec_a, vec_b): 计算两个向量的余弦相似度。 # 将PyTorch张量转换为numpy数组以便计算 if torch.is_tensor(vec_a): vec_a vec_a.numpy() if torch.is_tensor(vec_b): vec_b vec_b.numpy() # 点积 dot_product np.dot(vec_a, vec_b) # 模长 norm_a np.linalg.norm(vec_a) norm_b np.linalg.norm(vec_b) # 避免除以零 if norm_a 0 or norm_b 0: return 0.0 similarity dot_product / (norm_a * norm_b) return similarity # 5. 整合所有步骤一个完整的相似度计算函数 def calculate_similarity(text_a, text_b): 一站式计算两个中文文本的相似度。 print(f计算相似度\n A: {text_a}\n B: {text_b}) # 获取向量 vec_a, vec_b get_sentence_vectors_correct(text_a, text_b) # 计算余弦相似度 sim_score cosine_similarity(vec_a, vec_b) print(f 余弦相似度得分: {sim_score:.4f}) return sim_score3.5 第五步开箱即用——测试你的系统所有零件都造好了现在让我们组装起来试试效果。在同一个文件的最后我们写一个测试部分# 6. 测试一些例子 if __name__ __main__: print(*50) print(StructBERT文本相似度计算系统测试) print(*50) # 例子1同义句 score1 calculate_similarity(今天天气真好, 阳光明媚的一天) # 例子2反义句 score2 calculate_similarity(我喜欢吃苹果, 我讨厌吃苹果) # 例子3不相关句 score3 calculate_similarity(深度学习需要GPU, 西湖的景色非常美丽) # 例子4长句测试 score4 calculate_similarity( 自然语言处理是人工智能的一个重要分支它使计算机能够理解、解释和生成人类语言。, NLP技术致力于让机器读懂人类的文字和语言是AI领域的核心方向之一。 ) print(\n测试完成)运行你的text_similarity.py文件。你会看到程序依次加载模型然后对四组句子输出相似度得分。不出意外的话第一组和第四组的得分会比较高可能0.7-0.9第二组次之第三组应该最低可能低于0.3。这说明我们的系统已经能像模像样地工作啦4. 让结果更直观简单可视化数字可能不够直观我们用一个简单的条形图把刚才测试的结果画出来这样一眼就能看出差别。我们在同一个文件中添加一个可视化函数需要先安装matplotlibimport matplotlib.pyplot as plt def visualize_results(text_pairs, scores): 可视化相似度结果。 text_pairs: 列表每个元素是一个元组 (text_a, text_b) scores: 对应的相似度分数列表 labels [f例{i1} for i in range(len(scores))] plt.figure(figsize(10, 6)) bars plt.bar(labels, scores, colorskyblue) # 在每个条形上添加数值 for bar, score in zip(bars, scores): height bar.get_height() plt.text(bar.get_x() bar.get_width()/2., height 0.01, f{score:.3f}, hacenter, vabottom) plt.axhline(y0.5, colorr, linestyle--, alpha0.5, label阈值 (0.5)) plt.ylim(0, 1.1) plt.ylabel(余弦相似度) plt.title(文本相似度计算结果可视化) plt.legend() plt.grid(axisy, alpha0.3) plt.tight_layout() plt.show() # 修改主测试部分收集结果并可视化 if __name__ __main__: print(*50) print(StructBERT文本相似度计算系统测试) print(*50) test_cases [ (今天天气真好, 阳光明媚的一天), (我喜欢吃苹果, 我讨厌吃苹果), (深度学习需要GPU, 西湖的景色非常美丽), (自然语言处理是人工智能的一个重要分支它使计算机能够理解、解释和生成人类语言。, NLP技术致力于让机器读懂人类的文字和语言是AI领域的核心方向之一。) ] scores [] for i, (text_a, text_b) in enumerate(test_cases): print(f\n[例子 {i1}]) score calculate_similarity(text_a, text_b) scores.append(score) # 可视化结果 visualize_results(test_cases, scores) print(\n测试完成结果已可视化。)再次运行这次不仅会输出数字还会弹出一个图表窗口清晰地展示四个例子的相似度高低红色虚线可以作为一个简单的参考阈值。5. 你可能遇到的问题与小技巧第一次跑通很有成就感但实际用的时候可能会碰到一些小麻烦。这里我分享几个常见问题和处理技巧。问题1运行时报错CUDA out of memory或者特别慢。原因模型在GPU上运行但显存不够或者你希望用CPU。解决在加载模型后显式指定使用CPU。model AutoModel.from_pretrained(model_name) model model.to(cpu) # 强制使用CPU或者在计算时确保输入张量也在CPU上。问题2句子太长结果好像不准。原因我们预处理时设置了max_length128超过的部分被截断了。解决对于长文本如段落可以考虑其他策略比如将长文本分句计算每句的相似度再综合或者使用专门处理长文本的模型。对于入门可以先确保输入的句子不要太长。问题3我想批量计算很多句子对的相似度怎么办解决你可以修改get_single_sentence_vector函数让它接受一个句子列表并利用批处理能力。核心是分词时一个列表传进去并且模型会批量处理。def get_batch_vectors(text_list): inputs tokenizer(text_list, return_tensorspt, truncationTrue, paddingTrue, max_length128) with torch.no_grad(): outputs model(**inputs) # 取出每个句子的[CLS]向量形状是 (batch_size, hidden_size) batch_vectors outputs.last_hidden_state[:, 0, :] return batch_vectors然后一次性计算所有向量再两两计算相似度效率会高很多。提升效果小技巧尝试不同的句子向量提取方法除了用[CLS]也可以试试对所有token的向量取平均mean pooling或取最大值max pooling有时候效果会不一样。微调模型如果你有特定领域的数据比如医疗问答对、法律条文可以用这些数据对StructBERT进行微调让它在你关心的领域表现更好。不过这属于进阶内容了。整体走下来你会发现用Python和现成的模型库搭建一个文本相似度系统并没有想象中那么难。关键是把流程拆解清楚准备环境、加载模型、处理数据、计算向量、比较相似度。我们完成的这个系统虽然简单但已经具备了核心功能你可以把它用到自己的小项目里比如做一个简单的问答匹配或者给文章做去重。当然这只是一个起点。StructBERT还有很多能力可以挖掘比如它本身就可以直接用于句子对分类任务判断是否相似。transformers库也提供了更高级的接口比如AutoModelForSequenceClassification可以直接输出相似与否的概率你可以去探索一下。最重要的是你亲手跑通了整个流程这种体验比读十篇教程都有用。接下来就试着用你自己的句子去测试看看它的表现吧。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。