Page 127 - 《软件学报》2026年第2期
P. 127
606 软件学报 2026 年第 37 卷第 2 期
large 模型 (https://huggingface.co/BAAI/bge-reranker-large) 基础上来构建语义重排序模型.
训练数据构造: 由于深度神经网络模型遵循数据驱动的编程范式 [26] , 因此深度神经网络模型的构建往往需要
大量的训练数据. 为了收集充足的训练数据用于语义重排序模型训练, 首先从诸如 GitHub 和 Gitee 等代码开源平
台中爬取了大量的开源项目. 然后, 通过静态分析等技术手段, 从爬取得到的开源项目中提取出所有函数源代码及
其相应的注释. 最后, 对提取得到的数据进行清洗, 排除了那些无法编译的噪声数据, 从而得到用于语义重排序模
型训练的训练数据集.
基于构造的训练数据集, 下一步便是如何构造用于对比学习的训练数据. 对比学习的目标是使得同类型数据
具有相似的特征表示而不同类型数据的特征表示尽可能不同 [19] . 为此, 对比学习往往需要构造正负样本对, 从而
通过最小化锚点样本与其对应正例样本间相似度的同时最大化与其对应负例样本间相似度来实现模型训练. 一般
来说, 对比学习中常见的正负样本对构造方式是对锚点样本进行数据增强来生成正样本, 而将从训练数据集中除
锚点样本外的数据中随机采样的样本作为负例样本. 然而, 这种正负样本对构造方式并不能很好地适用于 SRBCS
中的语义重排序模型. 对于 SRBCS 中的语义重排序模型, 其锚点样本为训练数据集中一个函数源代码-代码注释
对. 此时, 如果我们简单地通过数据增强技术对锚点样本中的代码注释进行变换 (如随机替换或删除) 来生成正例
样本, 那么注释与函数源代码之间的语义相关性很容易遭到破坏, 导致得到的正例样本失效. 同时, 随机采样得到
的负例注释通常与锚点样本中的函数源代码具有较大的语义差异, 使得模型无法有效学习源代码与注释之间的语
义关系, 从而影响模型对同一源代码的不同语义关联度的注释进行区分.
为了避免上述问题, 构造高质量的正负样本对来训练语义重排序模型, 本文提出了一种词法检索、语义检索
和随机采样相结合的多维度正负样本对构造方法. 该方法的核心思想是利用词法检索和语义检索来更好地采样训
练数据中与锚点样本语义相近的样本, 从而提升随机采样得到的正负样本对的质量. 图 3 展示了所提出的多维度
正负样本对构造方法的具体流程.
代码词元 词法检
分词器 序列 索库
代码 & 注释
代码语义 语义检
代码模型 特征 索库
正例注释
基于 BM25 的 注释1
词法检索 注释3
注释1 BLEU>τ ...
// Golden: computes the length of a vector 注释2
public static double length (double x, double y, double z){ 基于余弦相似 注释3
return Math.sqrt(x*x +y*y + z*z); 度的词法检索 基于 BLEU 反例注释
} ... 的注释评估
锚点样本 随机采样 BLEU≤τ 注释2
...
多维度检索
图 3 多维度正负样本对构造流程
词法检索重点关注那些由于代码克隆、代码模板等原因而存在的形式相近且语义相似的源代码. 直觉上, 这
类源代码应当具有相似的代码注释. 为了进行高效词法检索, 首先借助 Lucene (http://lucene.apache.org) 这一被广
泛使用的开源检索引擎来构建词法检索库 [16] . 具体而言, 首先利用基于词法分析实现的分词器将源代码解析为词
元序列. 然后, 将词元序列存储为 Lucene 中的 Document 数据结构, 并利用 IndexWriter 构建索引. 在构建完成词法
检索库之后, 便可对检索库进行查询来得到与锚点样本中源代码词法相近的样本. 更具体来说, 使用 BM25 算法 [27]
计算锚点样本中源代码与检索库中代码的相似度实现词法检索. 选择使用 BM25 算法的原因是其被基于信息检索
的代码注释生成方法所广泛采用 [12−15,28] .

