Codex:使用注释生成代码.

1. 模型简介

本文提出了一个使用GitHub公开代码训练的GPT语言模型Codex,并评估了该模型的代码编写能力。Codex旨在从文档字符串(DocStrings)中生成程序,重点关注Python函数的生成。下面给出了三个程序生成的例子,给出函数定义及注释(Python注释由一对包含三个双引号的字符串构成),模型自动生成函数的主体部分(黄色背景)。

作者还收集了包含$164$个带有单元测试(unit test)的编程问题数据集HumanEval,用于测试从文档中合成程序的功能正确性。每个问题都包含函数签名(function signature)、文档字符串、主题和一些单元测试。平均每个问题包含$7.7$个单元测试。这些问题都是手工编写的,以避免存在于训练集(GitHub仓库)中,从而造成测试数据泄露问题。

2. 评估指标

通常的序列生成任务通常用BLEU指标进行评估,这种模糊的匹配指标不适于代码生成任务。作者比较了HumanEval数据集中的四个任务所对应的一些正确预测代码和错误预测代码,其对应的BLEU得分分布高度相似,这说明不应该采用BLEU指标。

作者采用了一种pass@k指标,对每个问题生成$k$个代码,如果有一个代码能够通过所有单元测试,则认为解决了问题。这种计算方式的方差较大,因此作者对每个问题首先生成$n=200$个代码,并从这些代码中采样$k\leq 100$个进行测试,若有$c$个通过测试,则pass@k指标计算为:

\[\text{pass@}k = \mathop{\Bbb{E}}_{\text{Problems}} [1-\frac{C_{n-c}^k}{C_n^k}]\]

直接计算上式会产生非常大的数值结果,造成数值不稳定。可以对其进行化简:

\[1-\frac{C_{n-c}^k}{C_n^k} = 1-\frac{\frac{(n-c)!}{k!(n-c-k)!}}{\frac{n!}{k!(n-k)!}} = 1-\frac{(n-c)!k!(n-k)!}{n!k!(n-c-k)!} \\ = 1-\frac{(n-c)!(n-k)!}{n!(n-c-k)!} = 1-\frac{(n-k)\cdots (n-c-k+1)}{n\cdots (n-c+1)} \\ = 1-\frac{\prod_{i=n-c-k+1}^{n-k} i}{\prod_{i=n-c+1}^{n} i} = 1-\frac{\prod_{i=n-c+1}^{n} i-k}{\prod_{i=n-c+1}^{n} i} \\ = 1-\prod_{i=n-c+1}^{n}\frac{ i-k}{ i} = 1-\prod_{i=n-c+1}^{n}(1-\frac{ k}{ i})\]

3. 结果分析

作者训练了一系列具有不同参数大小的模型,数据集为从GitHub中筛选的$159$GB代码文件,模型结构采用GPT-3模型,经过训练后的模型称为Codex模型。模型尺寸和训练损失近似服从幂律(power law):

Codex模型对生成的序列进行采样,直至遇到停止序列\nclass,\ndef,\n#,\nif,\nprint。采样方法使用核采样(nucleus sampling),即每次采样时保留概率之和超过$p=0.95$的预测token,以增加采样多样性并过滤概率极低的错误结果。

生成采样结果时可以控制温度参数$T$。温度$T$越高,生成的样本多样性越大,当采样数量$k$越大时更容易得到正确的结果。下图展示了不同的采样数量$k$和温度$T$对应的模型表现,不同的采样数量$k$对应不同的最佳温度$T$。

注意到原始的GPT-3模型无法解决该问题,而具有$120$亿参数的Codex模型能够解决$28.8\%$的问题,具有$3$亿参数的Codex模型也能够解决$11.4\%$的问题。作者进一步收集了一个与HumanEval类似的训练集进行微调,微调后的Codex-S模型能够解决$37.7\%$的问题。如果允许从模型中采样$100$个样本,其中存在能够解决问题的代码就算通过,则能够解决$77.5\%$的问题。即使从这$100$个样本中选择平均对数概率最高的样本,也能够解决$44.5\%$的问题。