刘 磊, 王 昊, 孙 凯, 郜山权, 刘宣彤
(1. 吉林大学 计算机科学与技术学院, 长春 130012; 2. 外交学院 英语系, 北京 100037)
Node包管理器NPM是node.js默认的, 用JavaScript编写的软件包管理系统. 开源开发人员可基于NPM平台共享或者借用软件包. 为帮助开发人员更高效地搜索到所需的软件包, NPM提供了一种标签搜索机制, 根据具体的标签推荐相关的软件包. 因此, NPM平台通常要求开发人员在发布或更新软件包时为其分配标签. 目前, 主流的标签推荐方法都是利用物体的文本特征实现标签推荐[1-2], 如EncTagRec++[3]和FastTagRec[4]等. 这些文本特征主要包括Readme文档或描述文本. 但在NPM软件包的标签推荐场景下, 包的Readme文档主要用于介绍包的使用说明和安装说明等, 这种类型的文本信息对标签推荐的作用较小, 且包的描述信息过短, 表达的信息不充足. 本文统计了58 753个软件包的描述信息, 统计结果表明, 76.7%的包描述文本不超过10个单词. 因此, 这些传统的利用Readme文档或描述文本的标签方法在NPM软件包标签推荐场景下性能较差. 为解决传统方法在NPM软件包标签推荐场景下的局限性, 本文从包的代码角度出发推荐标签. 与Readme文本以及描述文本相比, 包的代码信息能更直观和具体地描述包的行为. 此外, 文献[5]对比了传统标签推荐方法和深度学习标签推荐方法在相同标签工作下的性能, 实验结果表明, 选择合适的深度学习方法可能会获得更有效的结果. 因此, 本文从包的代码角度出发, 利用深度学习模型为NPM软件包推荐标签. 首先, 通过程序分析技术构建出NPM软件包的函数调用图, 利用图遍历算法遍历该函数调用图, 从而将软件包转化为一组具有语义信息的函数调用序列; 其次, 利用seq2seq模型将函数体字符序列映射为函数名称序列[6], 通过训练seq2seq模型将包含语义信息的软件包函数调用序列映射到软件包的标签序列上, 从而完成标签的推荐工作.
本文采用加入了注意力机制[1]的seq2seq模型完成NPM软件包的标签推荐工作. Seq2seq模型[2]是一种将输入序列映射到输出序列的深度学习模型, 广泛应用于机器翻译领域[7-8]. 该模型通常会引入注意力机制提高模型性能. 在本文提出的标签推荐方法中, 首先利用ECMAScript开发工具解析NPM软件包的源代码, 构建出软件包的函数调用图, 通过图的深度优先遍历得到一组能反映软件包功能语义信息的函数调用关系序列, 并用该序列作为seq2seq模型的输入; 其次, 再训练seq2seq模型, 该模型以软件包的标签序列作为输出. 模型训练结束后, 对于一个新的软件包, 训练好的seq2seq模型会将该包的函数调用序列映射到一组预测的标签序列上, 预测序列中的标签将会作为推荐标签推荐给该软件包. 图1为本文方法的整体流程.
图1 本文方法流程Fig.1 Flow chart of proposed method
数据处理部分为标签推荐模型准备训练数据, 该部分主要完成以下两项任务: 1) 将NPM软件包表示成函数调用序列的形式; 2) 抽取软件包的标签序列信息. 对于任意一个NPM软件包p, 经过数据处理后都会对应一组序列对(s,t):p→(s,t), 其中s是p对应的函数调用关系序列,t表示p拥有的标签序列.
1.1.1 函数调用序列
为将NPM软件包表示成序列的形式, 本文选择构建包的函数调用图, 遍历该调用图, 从而得到包的函数调用序列, 并用该序列作为包的表示. 由于函数调用图能反映包的函数调用关系, 具有软件包功能相关的语义信息, 因此用函数调用序列表示一个NPM软件包合理.
在构建函数调用图的过程中, 利用程序静态分析技术解析NPM软件包的源代码, 这些代码是基于JavaScript(JS)语言实现的. ECMAScript开发工具可以帮助解析JS代码, 其中Esprima为JS代码生成对应的抽象语法树, Estravese用于遍历语法树并定位到函数相关的节点抽取出函数名称. 由于一个NPM包由多个文件模块组成, Madge工具用于帮助分析模块之间的依赖关系决定模块分析的顺序, 因此在整个分析过程中, 利用information-matching的方法构建NPM软件包的函数调用图. 最后通过图的深度优先遍历, NPM软件包最终被表示成函数调用序列的形式.
利用Estraverse工具遍历抽象语法树时, 首先需定位语法树中函数相关的节点才能抽取对应的函数名称. 函数相关的节点主要是函数声明和函数调用, 而在JS语言中函数声明和函数调用的格式有很多种, 其在语法树中的表现形式也不同. 因此, 为能准确定位到函数相关节点抽取出的函数名称, 本文参考了JS函数的基础语法和Esprima官方文档, 针对不同语法格式的函数声明和函数调用制定相应的抽取规则定位语法树中函数相关的节点, 从而抽取出函数名称及相对应的文件模块信息.
1.1.2 包标签序列
软件包标签序列的获取相对容易, CommonJS规范规定NPM软件包的根目录下必须默认存在一个配置文件package.json, 该配置文件包含了软件包的基本信息, 其中包括标签信息. 因此, 只需要找到根目录下的配置文件, 分析配置文件的keywords属性即可获取软件包的标签序列.
收集NPM软件包对应的序列对信息后, 标签推荐模型的输入和输出可以确定. 训练时, 模型以软件包的函数调用序列作为输入, 软件包的标签序列作为输出. 训练完成后, 对于一个新的软件包的函数调用序列, 模型可以预测一组标签序列, 将该标签序列作为软件包的推荐标签. 本文方法使用seq2seq模型进行标签推荐, 该模型基于编码器和解码器构建, 编码器和解码器均为循环神经网络、 长短期神经网络(LSTM)或门控循环单元(GRU). 本文选择计算能力消耗相对少的GRU循环神经网络. 为优化模型性能, 在seq2seq模型中加入了注意力机制. 注意力机制的优势在于该机制能为模型解码器端计算动态的注意力向量进行标签预测, 这种注意力向量能极大地保留输入序列的信息, 从而使模型的推荐结果更准确合理. 而不采用注意力机制的seq2seq模型只能基于一个固定的上下文向量进行标签预测. 这种没有注意力机制的模型通常存在两个局限性: 1) 当输入序列过长时, 固定的上下文向量很难包含整个序列的信息, 而是偏向于表达序列末尾的信息; 2) 使用固定的上下文向量无法帮助模型明确输入序列和输出序列之间的对应关系, 使输入序列中的所有词汇对预测结果的贡献相同. 这两种局限性都会影响模型的预测结果, 因此本文引入注意力机制优化标签推荐模型. 图2为标签推荐模型的基本结构.
图2 标签推荐模型结构Fig.2 Architecture of tag recommendation model
对于一个包p的函数调用序列s, 编码器首先通过嵌入层将s转换成向量的表示形式, 编码器端的循环神经网络利用该向量计算出不同时期的隐藏状态h.解码器端在预测标签时, 会根据已预测的标签以及注意力向量计算当前预测标签yi的概率p,p的计算公式为
p(yi|y
其中:x为输入序列的向量表示;y为已预测标签的向量表示;oi为当前解码器的状态;ci为当前状态下的注意力向量, 注意力向量ci是由注意力函数根据隐藏状态hi和解码器状态oi计算得到的.在Softmax计算结果中最大概率值对应的标签为当前模型的预测标签yi.
在数据收集过程中, 首先通过爬虫程序在NPM平台上收集到3 833个NPM软件包的基本信息, 利用命令行安装指令将这3 833个包安装到本地计算机. 经过数据处理后, 最终得到3 833条有效的函数调用序列信息和标签序列信息对, 这些序列对将用于标签推荐模型的训练和测试. 本文按照传统的二八划分将数据集划分为不相交训练集和测试集.
图3 损失函数曲线Fig.3 Loss function curve
为使模型表现更优, 收敛更快, 本文结合已有的实现方法设置seq2seq模型的参数: 学习率为0.006, 嵌入层维度为64, 隐藏层神经元为1 024, 最大序列长度为100, 损失函数采用稀疏分类交叉熵. 常用的注意力机制主要有additive机制和dot-production机制两种, 本文采用后者. 图3为训练过程中损失函数值的变化曲线. 由图3可见, 在迭代到约40轮时模型已经趋于收敛了, 整个100轮迭代过程约需耗时70 min.
参考文献[9], 本文定义两种指标R1和R2评估模型.对于指标R1, 只要预测标签序列与原始标签序列之间交集不为空, 即模型至少预测对一个标签即认为预测结果有效, 统计有效结果在测试集中的比例, 该比例作为R1指标下的准确率.其公式定义为
其中:Tp为测试集合;TSO函数返回包p原始标签序列;TSP函数返回包p预测标签序列; 函数J判断序列是否有交集, 有交集则返回1, 反之返回0.本文模型在R1评价指标下的准确率为82.6%.
对于指标R2, 只有当预测序列和原始标签序列重合, 即只有当模型预测对所有的标签才能认定当前预测结果有效, 统计有效结果在测试集中的比例, 该比例作为R2指标下的准确率.其公式定义为
其中: 函数F判断序列是否重合, 重合则返回1, 反之返回0; 其他参数含义与R1相同.本文模型在R2评价指标下的准确率为33.7%.由于R2指标要求模型完全预测标签, 所以该准确率也合理.
图4为部分软件包原始标签序列与预测标签序列的对比结果. 由图4可见, 本文模型的确能为软件包推荐合理的标签, 验证了本文方法的有效性. 尽管本文方法能为NPM软件包推荐合理的标签, 但由实验结果可见, 这种推荐方法存在一定的缺陷, 如在预测标签序列中会出现重复的标签, 这与实际情况不符. 出现这种情况的原因是模型在预测当前标签时只计算了输出序列中每个标签的概率值, 输出最大概率值对应的标签, 而未考虑该标签是否已经出现在输出序列中了.
图4 原始标签序列与预测标签序列对比结果Fig.4 Comparison results of original tag sequences and predicted tag sequences
综上所述, 针对NPM平台上存在大量的软件包没有标签或标记不完善的问题, 本文提出了一种基于seq2seq模型的标签推荐方法. 该方法从NPM软件包的源代码出发, 利用静态程序分析技术构建出软件包的函数调用图, 通过图遍历算法将其转换成一组语义信息的函数调用序列. 训练好的seq2seq模型将软件包的函数调用序列映射到一组预测的标签序列上, 从而完成软件包的标签推荐工作. 实验结果表明, 本文方法能为NPM软件包推荐合理的标签, 准确率可达82.6%.