背景
2023年可以称之为大模型元年,也是AI模型在开源历史上最受关注的一年。各大企业、机构、高校纷纷发布了自研大模型,展示多年来AI能力的积累和从量变到质变的过程。大模型的出现突破了许多人对NLP、对AI算法的过往认识,越来越多的人开始相信大模型能够很好的理解人类自然语言并与人类交互,人工智能离我们更近了一大步。当然,大模型的能力不仅如此,它甚至可以读懂程序员以及机器生成的代码。
代码数据是高度逻辑思维下的产物,是信息时代的精粹,是计算机领域人与人之间、人与机器之间的连接纽带。解决好大模型的代码能力,就能解决好大模型与所有计算机信息系统的交互问题。目前大语言模型 (LLM) 已经发展到了熟练掌握自然语言的程度,通过在特定领域的数据集上进行训练,可以进一步衍生出各种下游任务。
其中一个应用便是基于代码训练的 LLMs (Code LLMs),通过与模型的交互,由自然语言指令进行程序合成、代码补全、代码调试和生成文档。生成式代码大模型可以提高代码工作者的工作效率,对未来的计算机产业产生深远影响。目前,微软的 Copilot 已经吸引了超过100万的代码开发人员,GitHub报告指出,这些开发者依赖Copilot编写了 35% 的代码。
在这种背景下,HuggingFace BigCode团队和Meta团队也分别推出了自己的开源代码大模型:StarCoder和CodeLlama。本文我们会详细介绍这两种模型的技术细节,复现HumanEval benchmark评测结果以及横向对比两类模型在实际应用(题解生成、代码补全、单元测试)中的生成效果。
除此之外,OpenCSG算法团队分别将两类模型作为基座模型,在精选的优质数据集上进行微调训练。相比于原版的starcoder,codellama系列模型,微调后的opencsg-starcoder, opencsg-codellama模型,在HumanEval python pass@1 benchmark上均有一定程度的提升,这些结果也同时证明了StarCoder和CodeLlama模型具备较大的潜力,为我们团队后续在开源社区贡献更强大的代码生成模型打下坚实的基础。
02
深入了解StarCoder模型
StarCoder系列模型是由 Hugging Face 和 ServiceNow 共同领导的开源项目组织 BigCode 所建立,该组织致力于开发代码大模型 (CodeLLM),于2023年5月推出了 StarCoder 和 StarCoderBase 两个模型,具有 8K 上下文长度、填充 (infilling) 功能和快速大批量推理能力。
其中 StarCoderBase 使用 1 万亿个 token 进行训练,训练数据来源于 GitHub 上的授权数据,其中包括 86 种编程语言、Jupyter笔记本、GitHub issues和 commits,StarCoder 是使用35B的python token数据在基础模型 StarCoderBase 上微调而成。接下来让我们来逐步解密Starcoder模型的产生细节吧。
解密StarCoder预训练数据管理和清洗
BigCode团队对StarCoder模型的训练数据做了非常清晰介绍及解释。这一部分我们会讨论starcoder在训练数据集的选择,不同代码数据的清洗处理方式,不同语言在训练数据集中的采样分布以及数据去重等内容。
训练集
StarCoder 和 StarCoderBase 的训练集来自于公开数据集 The Stack v1.2 (https://huggingface.co/datasets/bigcode/the-stack),其中包含 6TB 的授权数据,覆盖358种编程语言。
StarCoder团队经过启发式过滤、人工检查筛选、清洗等处理之后还剩余 783GB 的代码数据,包含86种编程语言,其中有54GB的github issues数据和13GB jupyter notebook脚本和text-code数据对,32GB 的github commits数据,总计将近250B tokens。Bigcode组织秉承开源精神公开了清洗后的数据集——Starcoderdata (https://huggingface.co/datasets/bigcode/starcoderdata)。
数据选择
StarCoder团队从 The Stack 公开代码数据集的 358 种编程语言中选择了 86 种语言,并根据文件扩展名对编程语言分类,保留超过 500 MB,以及在 Github 2.0 或 2022 年 12 月 TIOBE 编程语言流行度指数上排名前 50 的语言,其中也包含了像JSON 和 YAML 等数据文件,但对这方面的数据做了数量限制以平衡整个数据集的分布,并且剔除了配置语言 (如Nix、Puppet 等)以及已经被时代废弃的的语言如ActionScript。Starcoder团队对不同类型的编程语言有个性化的处理逻辑,下文我们进一步分析了具体的处理方法。
人工检查
为了筛选出高质量的数据,StarCoder团队通过人工检查的方式进行数据处理。首先从 The Stack 数据集中为每种编程语言随机选择 30,000 个文件,按扩展名对它们进行分类,并为每个扩展名保留最多 1,000 个文件。StarCoder团队招募了一些标注员,指导他们抽样检查其中 50-100 个文件,确认是否是人类编写的正常代码,而不是文本、数据或一长串自动生成的代码。标注员需要确定是否应该对某一种语言使用字母数字过滤器 (要求有超过 25% 的字母数字符号) 和长行文本过滤器 (要求每行少于 1,000 个字符) 。
XML 过滤器
StarCoder 团队实现了一个简单的 XML 过滤器,用于检查文件的前 100 个字符中是否存在“<?xml version=”。使用此工具对除了 XSLT (XSLT 语法与 XML 相同)之外的所有编程语言进行过滤。
字母过滤器
在代码数据场景中,像MATLAB 类型的数据中通常有大量包含大型tensor的数据文件。为了过滤这种文件,StarCoder 团队开发了一个字母过滤器,可以删除字母字符少于 25% 的文件。但是这个过滤器在某些编程语言 (例如汇编语言) 中的误报率很高,所以团队最后决定重点关注检测次数最多的 25 个编程语言,并通过人工确认是否应该在此编程语言上应用字母过滤器。
HTML 过滤器
Starcoder团队设计了一个 HTML 过滤器,只保留可见文本至少占 20% 且最小长度为 100 个字符的文件。这样可以避免保留下来的文档中出现过多 HTML 标签和链接。
JSON and YAML 清理
对于 YAML 文件,保留 50-5000 个字符、平均行长度小于 100、最大行长度小于 1000,并且字母字符超过 50% 的文件,这使得 YAML 文件减少了大约 20% 的文件和 90% 的体积。类似地,对于 JSON 文件,保留 50-5000 个字符且超过 50% 字母字符的文件,这使得 JSON 文件减少了大约 70% 的文件和 98% 的体积。
Jupyter
Jupyter笔记本的数据主要包括两种:
1.第一种是 Jupyter scripts,使用 Jupytext 工具将笔记本转换为 Jupyter scripts。从每个笔记本的meta信息里可以获取编程语言类别,Jupytext可以根据这个信息识别不同语言的代码段。但是有超过 30,000 个笔记本缺少编程语言信息,所以StarCoder团队结合使用了 Guesslang 工具进行识别,该工具使用了机器学习方法识别代码片段所属的编程语言。
2.第二种是 Jupyter – structured,创建这类数据首先需要过滤掉不包含 Python 代码也不包含 Markdown 文本的笔记本,只有meta信息中明确标记为“Python”语言的笔记本会被留下。在每个笔记本内部,连续的 Markdown 块或代码块会合并为一个大的 Markdown 或代码块,最终得到连续的按时间顺序排列的代码-文本对。包含 Python 代码的代码块与 Markdown 文本紧邻,形成天然的指令对。
GitHub issues
从 The Stack v1.2 中收集来自 GitHub issues 和 pull request 的自然语言对话,每个对话都包含一系列操作事件,例如开启问题、创建评论和关闭问题。每个事件都包括作者的用户名、消息、操作和创建日期。删除了用户通过电子邮件回复问题时自动生成的文本,也删除了少于 200 个字符的问题。删除机器人生成的评论,机器人生成的问题往往很长,并且包含大量日志和链接。按照参与对话的用户数量进行过滤,保留两个及两个以上数量用户的对话,最后使用 fasttext 工具过滤掉非英语的问题。
Git commits
由于这部分数据会包含用户提交的更改前以及更改后大量重复的代码片段,为了避免模型在学习相同内容上花费过多的计算资源,StarCoder团队决定仅在 20% 的时间内使用完整文件,而在其余 80% 的时间内,对第一个和最后一个更改行周围的 0 到 32 行之间的窗口进行采样。
去重处理
Starcoder团队在去重方法上首先采用了MinHash,即计算所有代码文件的 MinHashes,然后使用本地敏感哈希 (LSH) 将相似的代码文件映射到同一存储桶。对所有编程语言和 Jupyter 笔记本都进行了去重,但是由于时间限制没有应用于 Git commits。不过 Git commits 不太可能发现重复项,所以StarCoder团队认为这部分数据不需要进行去重。
数据集的权重
一般地,数量比较多的数据基本都来自于相对更流行的编程语言,StarCoder团队认为不需要对现有的数据分布进行大幅度的重新加权,在训练过程中按照数据的原始分布比例对数据源进行采样,这样训练出来的模型也能够照顾到这些流行语言的用户。但在这其中 JSON、YAML 和 CSS 格式是例外,因为 LLM 应该重点学习这些语言的数据格式,而不是浪费计算资源来记住其中的数据。所以StarCoder团队重新分配了这几种语言的大小,JSON 和 YAML 为 1 GB,CSS 为 3 GB。
StarCoder模型训练方法和技巧
在上文我们了解了预训练数据的准备流程后,我们再来了解一下StarCoder模型在训练过程当中运用的具体方法,涉及数据格式构造、Tokenizer选择以及模型框架搭建。
数据格式
在这部分我们会详细介绍StarCoder团队如何构造预训练数据的格式,其中<token>指的是特殊令牌 (special token),metadata和data则是数据字段的占位符。
代码
代码部分的数据一共包含三个meta信息和代码正文 (code),meta信息分别为存储库名称 (reponame)、文件名 (filename) 以及星级 (stars),格式为<reponame>reponame<filename>filename<gh_stars>starsncode<|endoftext|>
StarCoder 将meta信息添加到代码文件的上下文中。为了使模型能够在没有meta信息的情况下进行推理,这三类meta信息被独立添加前缀,概率均为 0.2。将中间填充变换 (Fill-in-the-Middle Transformation, FIM) 以字符级应用于源代码文件,覆盖率为0.5,其中一半使用前缀-后缀-中间 (prefix-suffix-middle, PSM) 模式,一半使用后缀-前缀-中间 (suffix-prefix-middle, SPM) 模式。
GitHub issues
GitHub上面的每个仓库 (repository) 都有“错误跟踪器”,称为“issues”,供仓库创建者、贡献者、使用者或任何想参与讨论的人在使用开源项目发现代码bug或出现问题时使用。一个 GitHub issues 实例见下图。
这部分数据被处理为以下格式:
<issue_start>Title:titlenusername_id0:comment0<issue_comment>username_id1:comment1 … <issue_closed(optional)> <|endoftext|>
通过<issue_comment>来分离一系列评论,并在评论前放置一个匿名化的说话人标识符。为了区分不同对话轮,使用comment1,id1分别指代第二个评论和与之对应的匿名说话人id。
Jupyter
1.Jupyter – scripts
Jupyter – scripts 是由Jupyter笔记本转换为脚本文件而得。内容形式如下 (以ipynb为例)。
1.# example_notebook.ipynb
2.
3.# %%
4.print(“Hello, Jupyter-Script!”)
5.
6.# %%
7.name = “Amelia
8.”print(f”Welcome, {name}!”)
9.
这部分的数据结构与代码部分结构相同:<reponame>reponame<filename>filename<gh_stars>starsncode<|endoftext|>
2.Jupyter – structured
Jupyter – structured 部分的数据包含 Python 代码块和与之相邻的 Markdown 文本,形成天然的指令对,其格式为
<jupyter_start><jupyter_text>text0<jupyter_code>code0<jupyter_output>output0<jupyter_text> ... <|endoftext|>
解析出来的 Jupyter 笔记本以文本 (text)、代码 (code) 和输出 (output) 为链,以标记每一对 text-code-output 的开始,text2,code2,output2 用来指代笔记本中的第3个三元组。
Git commits
在 Git 管理中,“commits”(提交)是一种保存项目更改的方式。每个提交都代表了项目在某一时间点的状态,包含了文件的变更信息。提交可以记录编程者对项目所做的修改,包括添加、删除或修改文件。一个 Git commit 实例见下图。
这部分数据被处理为以下格式:
<commit_before>code_before<commit_msg>message<commit_after>code_after<|endoftext|>
以 commit_before、commit_msg 和 commit_after 为链。以 20% 的概率使用完整文件,不使用完整文件的时候就在变化的行周围使用一个小窗口 (0 ~ 32行)。
分词器
StarCoder 使用 Hugging Face Tokenizers 库训练一个字节级的字节对编码 (BBPE)的分词器,共49152个token。
模型框架
StarCoder 采用与 SantaCoder 架构相同的15.5 B参数模型。它是一个 decoder-only 的 Transformer,运用多查询注意力 (MQA),学习绝对位置embedding。将中间填充 (Fill-in-the-Middle, FIM) 变换应用在训练数据上,并使用Flash Attention 来加速注意力计算并减少其内存占用,使得上下文长度可以扩展到8K。
StarCoder模型评测详解
StarCoder 团队列出了包括 StarCoder 和 StarCoderBase 等一些模型在 Human Eval、MBPP 和 DS - 1000 benchmark上的Python语言得分,同时也评测了多种编程语言的benchmark。
StarCoder: Python Evaluation
HumanEval和MBPP基准
StarCoder 团队将 StarCoder 和 StarCoderBase 与几种模型在 HumanEval 和 MBPP 基准上进行了比较。测试结果如下图。
可以看到,在这两个基准上进行测试的结果中,StarCoder 是表中分数最高的开源模型。尽管StarCoder的规模比PaLM,LaMDA和LLaMA等模型的规模小很多,但是其分数却优于这些规模较大的模型。StarCoderBase 对 Python 的理解也很出色,与 CodeGen-16B-Mono (一个在Python上微调的类似大小的开源模型) 不相上下。同时,StarCoder 也优于 OpenAI 推出的 code-cushman-001 (12B) 模型。
DS-1000 python数据科学基准
HumanEval 和 MBPP 的局限性在于它们只包含编程题,而编程题中的代码并不能代表大多数程序员所写的代码。相比之下,DS-1000 更贴近实际应用中会出现的代码,它涵盖了7个Python库 (如NumPy、Pandas等) 的相关问题和答案。测试结果如下图。
从 DS-1000 基准来看,StarCoder 在数据科学问题上的表现优于 StarCoderBase,二者同时远远优于其他所有模型。与此同时,StarCoder团队还有进一步的发现:在 HumanEval 和 MBPP 基准测试中性能表现好的模型并不一定能在 DS-1000 基准测试中拥有同样好的表现。例如,CodeGen-Mono 在 HumanEval 和 MBPP 上的性能略优于 code-cushman-001 和 StarCoder 模型,但在 DS-1000 上明显较差。这证明了在一系列基准上评估模型的重要性。
The ODEX 开放域编程基准 (Open-Domain Coding Benchmark)
上文评估要么侧重于封闭域 (例如内置 Python 函数,如 MBPP 和 HumanEval基准) ,要么侧重于特定域 (例如数据科学,如 DS-1000基准) 。为了更广泛评估模型在 Python 库上生成代码的能力,StarCoder 团队使用 ODEX 基准进一步进行测试,测试集包含 505 个开放域和 440 个封闭域 Python 编程问题,采用四种自然语言——英语、西班牙语、日语和俄语——基于测试用例进行评估。测试结果如下。
StarCoder 在开放域编程方面远远优于所有其他模型。StarCoderBase 紧随其后,其性能也优于其他所有模型,甚至在 ODEX 英语子集中优于 StarCoder,但在其他语言中稍微落后。
StarCoder and StarCoderBase: Multi-Language Evaluation
尽管 StarCoder 是在 Python 上进行微调得到的,但它仍是一个非常强大的多语言代码 LLM,甚至在某些语言上的表现优于 StarCoderBase。
使用 MultiPL-E 在 19 种编程语言上进行评估
StarCoder 团队使用 MultiPL-E 评测集评估 StarCoder 将自然语言转换为多种编程语言的能力。MultiPL-E 将 HumanEval 和 MBPP 中的 Python 语言翻译成了其他 18 种编程语言。各模型在总共19种编程语言上的表现如下图。
从所有 19 种编程语言测试的结果整体来看,StarCoderBase 的性能优于其他开源模型,有时甚至表现出超过 2 倍的性能。除了少部分语言,StarCoderBase 与 code-cushman-001 的表现不相上下。与此同时,尽管 StarCoder 是在 Python 上进行微调得到的,但其在大多数语言上的表现仍然很出色,优于其他开源模型,甚至 StarCoder 在某些语言上的表现要略胜于 StarCoderBase。
“Asleep at the Keyboard” 安全基准
代码大模型的一个局限性在于它们有可能生成具有安全漏洞的代码。Asleep at the Keyboard 基准包含 89 个与安全相关的情景以供测试。测试结果如下。
StarCoderBase 的代码有效率最高。InCoder-6B 的不安全代码生成率略低,但这可能是由于其代码有效率较低。在有效代码超过 95% 的模型中,StarCoder 的不安全率最低。
Fill in the Middle 基准
StarCoder 模型支持中间填充 (Fill in the Middle, FIM) ,即模型根据前后文 (prefix, suffix) 在插入点周围进行代码生成。StarCoder团队根据4个FIM基准进行了测试。
(1) Python、Java 和 JavaScript 的单行填充
StarCoderBase 的性能明显优于其他两个规模较小的模型。
(2) Python 返回类型预测
StarCoder 和 StarCoderBase 在 Python 返回类型预测方面优于其他模型。但是由于该评测集中的函数取自 GitHub 存储库,因此它们可能与 SantaCoder 和 StarCoder 模型的训练数据重叠。
(3) TypeScript 类型预测
StarCoderBase 的表现优于 InCoder。
(4) Python Docstring 生成
StarCoder 和 StarCoderBase 在docstring生成方面有更好的表现。但此评估数据集与用于训练 SantaCoder 和 StarCoder 模型的数据之间可能存在重叠。
StarCoder 如何保障数据隐私安全?
StarCoder 采用一种个人身份信息修正 (Personally Identifiable Information redaction, PII redaction) 机制,从训练数据中删除个人身份信息。收集并标注 PII 数据集,将其用于 PII 检测模型的训练,最终得到 PII 检测模型。
数据收集
Starcoder团队召集了来自 35 个国家的 1,399 名众包人员来注释源代码中的 PII 数据集。PII 类型包括姓名、用户名、电子邮件、IP 地址、密钥、密码和用户名。
数据组成
PII 数据集包括 12,000 个文件,31 种编程语言,每个文件包含大约 50 行代码。在这其中,为了增加密钥、IP地址等稀有 PII 类型的代表性,团队预过滤了7100个文件,使用 detect-secrets 工具以及正则表达式来检测电子邮件、IPv4和IPv6地址。为了防止标注结果过度依赖检测工具,还从数据集中随机选择了没有进行过预过滤的5100个文件。
区分 PII
根据 PII 出现的上下文来区分 PII 是否需要被掩盖,包括是否存在于代码的许可证头中、是否被用作占位符以及是否构成机密数据。之所以要进行这样的区分,是因为许可证中的 PII 通常是由作者自愿提供的,而占位符也没有私密性,所以出现在这两处的 PII 都不需要被掩盖。只需将这种区分应用于姓名、电子邮件、用户名。
质量评估
Starcoder团队通过人工检查了300个包含各种 PII 类型的文件,并计算了每种类型的查全率和查准率。标注用户名经常出现错误标注,所以StarCoder团队决定将该类别排除在 PII 检测模型训练之外。
StarEncoder
StarCoder 为了 PII 检测专门训练了一个 encoder-only 模型,可以有效地针对代码和文本相关的任务进行微调。使用 BERT 中的基于掩盖的语言模型 (Masked Language Model, MLM) 和下句预测任务 (Next Sentence Prediction, NSP),预测输入句子中被盖住的 token 以及一对输入是否是文章中前后文。
PII 检测模型
PII 检测的总体思路是命名实体识别 (Named Entity Recognition, NER)。用标注过的 PII 数据集对 StarEncoder 进行微调。在模型顶部添加了一个线性层作为分类头,有6个目标类:姓名、电子邮件、密钥、密码、IP地址和用户名。
PII 占位符
占位符分别有<NAME>, <EMAIL>, <KEY>, <PASSWORD>。
至于 IP 地址的占位,从5个合成出来的私有 IP 地址中随机选择一个同类 IP 地址进行替换。
03
深入了解Code Llama模型
2023年08月,Meta 发布了 Code Llama,它是基于 Llama 2 衍生出来的代码生成模型,在开源模型中具有先进的填充能力、长上下文输入能力以及在编程任务中的 zero-shot 能力。它可以降低代码工作的门槛,辅助开发人员写出完善且高质量的代码,成为生产力工具和教育工具。
Code Llama系列模型 有多个版本:
-
基础模型(Code Llama)
-
Python专业化版本(Code Llama - Python)
-
指令跟随模型(Code Llama - Instruct)
每个版本都分别有三个尺寸,参数量各为7B、13B和34B,并支持多种编程语言。所有模型都是在16k token序列上进行训练的,并稳定支持最高10万个token的上下文生成。7B 和 13B 的 Code Llama 以及 Code Llama - Instruct 支持基于周围内容的填充。7B模型适合在单个GPU上运行,34B模型则提供了更好的编程辅助效果,但是相比较之下速度较慢。在面对比如实时代码补全这种低延迟轻量任务,更适合使用速度较快量级的7B和13B模型。
Code Llama 在多个代码基准测试中达到了开放模型中的最先进性能,分别在 HumanEval 和 MBPP 上取得了高达 53%和 55% 的分数 (优于 Llama2 70B),在 MultiPL-E 评测中的精度优于所有开源模型。
Meta 的方法是通过应用一系列训练和微调逐步提高 Llama 2 模型的能力并逐渐将其专业化。在预算相同的情况下,使用 Llama 2 初始化模型优于仅针对代码数据进行预训练的相同架构的模型。
解密CodeLlama微调方案
正如上文所介绍,CodeLlama通过一系列的训练和微调逐步提升模型能力,包括填充、长文本微调和指令微调。
填充
代码填充是指在给定周围上下文的情况下预测缺失部分。其应用包括代码补全、类型推断和生成代码内文档 (比如docstring) 。
按照因果掩码 (Causal Masking) 的概念来训练填充模型,序列的一部分被移到末尾,重新排序后的序列进行自回归预测。将训练数据在字符级别分成前缀 (prefix)、中间部分 (middle) 和后缀 (suffix)。分割位置在文档长度上从均匀分布中独立采样,采样概率为 0.9。随机将一半的分割以前缀-中间-后缀 (Prefix-Suffix-Middle, PSM) 格式进行格式化,将另一半以后缀-前缀-中间 (Suffix-Prefix-Middle, SPM) 格式进行格式化。
长文本微调
Code Llama 创建了一个长上下文微调 (LCFT) 阶段,模型的输入长度为 16,384 个 token的序列,比 Llama2 和初始代码训练阶段所使用的 4,096 个 token 要多。通过将处理长序列的训练时间限制在微调阶段,可以在不显著增加模型训练成本的情况下获得处理长距离注意的能力。
在使用旋转位置嵌入时,旋转频率的设置十分重要。Code Llama 改变了旋转位置嵌入 (rotary position embedding, RoPE) 的基础周期:
其中 n 表示位置,d 表示 embedding 维度,旋转频率的计算公式为 θi = θ^(−2i/d).
基础周期 θ 从 10,000 增加到 1,000,000,这样可以处理更长的序列并减少对短距离注意力的偏见。实验证实,Code Llama 模型不仅在微调过程中的序列长度内有效,而且还显示出外推能力,在 100,000 个 token 的超长序列上表现稳定。
指令微调
指令微调主要有三种数据集来源,专用数据集、self-instruct数据集以及代码与自然语言组合数据集。
(1) 专有数据集
采用 Llama2 中的 RLHF V5 版本数据集,该数据集包括数千个监督微调 (Supervised Fine-Tuning) 示例和数百万个拒绝采样 (Rejection Sampling) 示例。每个示例由用户 (user) 和助手 (assistant) 之间的多轮对话组成。
(2)Self-instruct 数据集
Meta 构建了约 14,000 个问题-测试-解决方案(question-tests-solution)三元组。构建方法如下:
-
通过提示 Llama 2 70B,生成 62,000 个面试形式的编程问题;
-
通过删除完全重复项来去除重复的问题集,从而剩下约 52,000 个问题;
-
对于每一个问题:
-
通过提示 Code Llama 7B 生成单元测试 (unit tests);
-
通过提示 Code Llama 7B 生成十个Python解决方案;
-
对这十个解决方案进行单元测试,将通过测试的第一个解决方案(及其相应的问题和测试)添加到 Self-instruct 数据集。
使用 Code Llama 7B 生成单元测试和解决方案的原因是它所消耗的计算资源更低,而且效果已经令人满意。
(3) 代码和自然语言组合数据集
为了防止模型在编程和语言理解能力方面出现退化,Code Llama - Instruct 使用代码数据集 (6%) 和自然语言数据集 (2%) 的配比的方式来进行训练。
CodeLlama的训练细节详解
优化参数设置
-
使用 AdamW 优化器,其中 β1 设置为 0.9,β2 设置为 0.95.
-
具有 1000 个预热步骤的余弦学习率,并将最终学习率设置为峰值学习率的 1/30.
-
batch size 是 4M 个 token,每 4, 096 个 token 为一个序列。
-
Meta团队并没有选择普遍使用的标准做法——在微调阶段使用比预训练阶段更低的学习率,而是保留 Llama 2 基础模型的原始学习率,经过试验发现这种做法可以获得最佳结果。
-
将这种做法应用于 13B 和 34B 模型,学习率分别设置为 3e^−4 和 1.5e^−4.
-
对于 python 微调,将初始学习率设置为 1e^−4.
-
Code Llama - Instruct 的 batch 大小是 524,288 个 token,总计 5B 个token。
长上下文微调 (Long context fine-tuning, LCFT)
-
使用 2e^−5 的学习率,16,384 的序列长度,并使用 θ = 10^6 的基值来重置 RoPE 频率。
-
对于 7B 模型和 13B 模型,batch 大小设置为 2M 个 token;对于 34B 模型,batch size 设置为 1M 个 token。
-
默认情况下,训练有 10,000 个梯度步骤。有些时候会出现下游性能不稳定的情况,因此将 34B 模型的梯度步数设置为 11,000,将 Code Llama 7B 的梯度步数设置为 3,000。
CodeLlama模型评测
Code Llama 34B 模型在 HumanEval 评测中取得了 53.7% 的通过率,在 MBPP 评测中的通过率则达到了 56.2%,接近 Chatgpt 的水平。
CodeLlama 如何保障模型安全?
Meta分别从诚实性 (Truthfulness)、有害性 (Toxicity) 和偏见 (Bias) 的角度用三个基准对 CodeLlama 的安全性进行了评估。
诚实性:使用 Truthful QA 来衡量模型的事实性和常识性。Truthful QA 基准包括817个问题,涵盖健康、金融、法律和政治等主题。这其中的有些问题十分具有挑战性,甚至人类在没有依据或者认知上存在错误的情况下也会答错。
有害性:使用 ToxiGen 来量化一段话具有危害性的程度,以及带有何种程度的仇恨。ToxiGen 数据集包含13个少数群体的隐性有害和良性句子。使用默认的 ToxiGen 分类器来衡量大模型产生输出的有害性。
偏见:使用开放语言生成数据集 (Bias in Open-Ended Language Generation Dataset, BOLD) 来研究模型输出所包含的情感。
测试结果如下图。
可以看到,微调后的 Code Llama - Instruct 在诚实性和有害性方面的表现比预训练的 Code Llama 更好。所有版本的 Code Llama 有害内容占比都低至几乎为 0%,在所有进行比较的模型中有害性最低。与 Falcon 和 MPT 微调模型相比,微调后的 Code Llama 在有害性和诚实性方面均表现出次优水平,仅次于 Llama 2 Chat。除此之外,Code Llama - Instruct 在微调后也表现出正向情感的整体增加。
04
StarCoder 和 CodeLlama 谁更适合作为基座模型?
StarCoder和CodeLlama是两种训练路线的生成代码模型。
StarCoderBase的预训练数据几乎全是代码数据,是从零开始预训练起来的代码生成模型;而CodeLlama是在Llama2通用模型上用代码数据微调而成。
在没有基于自然语言模型进行微调的基础上,StarCoder也表现出了不凡的自然语言理解能力。除此之外,StarCoder数据更加透明,利用opt-out机制让用户可以自行选择将自己仓库中的代码数据排除在数据集之外,数据安全性更高。
而CodeLlama用来训练的数据以及对于数据进行处理的细节都没有公开,具有不确定性,用户无法清楚得知有哪些数据被包含在模型训练当中以及在这个过程中该团队是如何保障数据隐私安全的。虽然CodeLlama对模型进行了数据安全的基准测试,但是这些基准都有其局限性,所以并不能完全证明CodeLlama具有全面的数据安全性。
单一评测基准经常有“偏好”上的局限性,因此在多个基准上评估模型非常重要。StarCoder团队在评测模型性能的时候就曾有发现:在 HumanEval 和 MBPP 基准测试中性能表现好的模型并不一定能在 DS-1000 基准测试中拥有同样好的表现。
例如,CodeGen-Mono 在 HumanEval 和 MBPP 上的性能略优于 code-cushman-001 和 StarCoder 模型,但在 DS-1000 上明显较差。不同评测基准难免具有自己的“偏见”,导致了评测结果的片面,在做模型评测的时候应该运用多种品测基准,且要辩证地看待评测结果。
StarCoder与CodeLlama 在HumanEval benchmark上的评测对比
OpenCSG团队深入研究了StarCoder以及CodeLlama这两种不同的代码生成模型训练方法,并且对StarCoder和CodeLlama系列模型进行了评测复现,结果如下表。
从结果可以看出,CodeLlama在HumanEval python pass@1的表现是随着模型的参数量增加,评测分数也逐步提升,其分数甚至高于starcoder这样的优秀代码生成模型。OpenCSG分析StarCoder分数不高的原因的是其对于humanEval这样做代码题解的评测问题上没有进一步的微调,它更加侧重于解决代码领域内通用的问题。
而CodeLlama通过Python专有数据微调过的codellama-13b-python和codellama-34b-python模型在HumanEval - Python评测中的表现都要更好,由此可见专用数据对于模型在垂类领域能力提升至关重要。
StarCoder与CodeLlama 在实际应用中的比较
除了评测之外,OpenCSG团队基于实际应用场景,在题解生成、代码补全和生成单元测试三个方面对StarCoder和CodeLlama-13b的生成结果进行了比较。
1.题解生成
(1) 生成快排算法
测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的生成结果:
两个模型虽然生成的有细节上的区别,但是经过测试都是合理正确的快排算法。在这个问题上可以说表现一致。
(2) 生成检查有效数独算法
测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的生成结果:
两个模型在算法代码题上的生成都很完整且正确。
2.代码补全
CodeLlama-13b-hf模型的测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的测试代码:
StarCoder模型的生成结果:
由于两个模型所使用的special token不相同,所以两份测试代码输入表示略有不同,两个模型对于快排算法补全的结果都是正确的。
3.生成单元测试
(1) 用英文注释作为prompt给快排函数生成单元测试
测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的生成结果:
CodeLlama-13b-Python-hf模型的生成结果:
在单元测试生成问题上,StarCoder成功理解了“只生成一个测试用例”中的“一个”,而 CodeLlama-13b 试图在设定的输出长度里持续输出多个测试用例。在这个测试中,StarCoder表现出了比 CodeLlama 更好的对自然语言(英语)的理解能力。
但同时我们也注意到,StarCoder生成的测试用例不如CodeLlama-13b-Python合理,该问题是一个排序算法,立项的生成结果应该为乱序的数组更为合理,而CodeLlama-13b-Python首先生成了乱序的数组,再对快排算法进行结果测试。
我们接下来测试了用中文进行prompt的结果。
(2) 用中文注释作为prompt给快排函数生成单元测试
测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的生成结果:
CodeLlama-13b-Python-hf模型的生成结果:
可以从CodeLlama-13b-hf的输出发现它极度依赖于用于训练的原始数据,用户的隐私信息也没有做合适的处理;而相比之下,专门处理过PII Redaction的StarCoder模型就不太会出现这种情况。
除此之外,在StarCoder的生成中,中文prompt生成的测试用例比英文prompt生成的测试用例更为合理——用于进行测试的数组应为乱序数组。
CodeLlama-13b-Python依旧是生成单元测试最合理的模型,比CodeLlama-13b生成的结果合理、完整很多,这说明在通用语言模型上训练而成的CodeLlama十分需要专业化的数据对模型专业化生成能力进行提升。
(3) 给打印“Hello world!”函数生成单元测试
测试代码:
CodeLlama-13b-hf模型的生成结果:
StarCoder模型的生成结果:
CodeLlama-13b-Python-hf模型的生成结果:
可以看到StarCoder模型和CodeLlama-13b-Python模型生成的代码较CodeLlama-13b更为合理。这进一步说明了CodeLlama对更专业化的数据十分data-hungry。
OpenCSG微调模型
OpenCSG团队用同一份包含多语言的精选题解数据集分别在 StarCoder 和 CodeLlama模型 上进行微调测试,结果如下表。
从上述结果可以看出,经过OpenCSG模型团队微调过的opencsg-StarCoder-v0.1模型, opencsg-codellama-7b-v0.1模型, opencsg-codellama-13b-v0.1模型, opencsg-codellama-34b-v0.1 模型这四个模型在HumanEval python pass@1 这个benchmark上均比原版的模型分数更高一些。
这个结果不仅是体现了StarCoder和CodeLlama还存在极大的性能提升的潜力,可用于训练的代码数据远远没有耗尽。
OpenCSG作为一家大模型开源社区,我们平台提供丰富的开源训练数据资产、模型资产可以供广大的爱好者免费获取。
同时,OpenCSG算法团队也会持续跟踪starcoder和codellama后续微调模型的工作,通过开源的方式不断迭代微调模型能力,也欢迎广大模型训练爱好者加入我们社区一起共建、共享、共同提升,以下是公司介绍以及联系OpenCSG的方式。
OpenCSG中 Open是开源开放;C 代表 Converged resources,整合和充分利用的混合异构资源优势,算力降本增效;S 代表 Software Refinement,重新定义软件的交付方式,通过大模型驱动软件开发,人力降本增效;G 代表 Generative LM,大众化、普惠化和民主化的可商用的开源生成式大模型。
OpenCSG的愿景是让每个行业、每个公司、每个人都拥有自己的模型。我们坚持开源开放的原则,将OpenCSG的大模型软件栈开源到社区。欢迎使用、反馈和参与共建,欢迎关注和Star⭐️,以下是和OpenCSG团队的沟通方式:
huggingface社区:https://huggingface.co/opencsg
OpenCSG社区:https://www.opencsg.com/
Github社区:https://github.com/OpenCSGs
参考链接
1.StarCoder: 最先进的代码大模型
https://huggingface.co/blog/zh/StarCoder
2.StarCoder: A State-of-the-Art LLM for Code
https://huggingface.co/blog/StarCoder
3.Creating a Coding Assistant with StarCoder
https://huggingface.co/blog/starchat-alpha
4.使用StarCoder创建一个编程助手
https://huggingface.co/blog/zh/starchat-alpha
5.StarCoder Memorization Experiment Highlights Privacy Risks of Fine-Tuning On Code
https://huggingface.co/blog/dhuynh95/StarCoder-memorization-experiment
6.Code Llama: Open Foundation Models for Code
https://arxiv.org/abs/2308.12950
7.StarCoder: may the source be with you!
https://arxiv.org/abs/2305.06161v2
我是朋克又极客的AI算法小姐姐rumor
北航本硕,NLP算法工程师,谷歌开发者专家
欢迎关注我,带你学习带你肝
一起在人工智能时代旋转跳跃眨巴眼
![post-qrcode](https://aigc.luomor.com/wp-content/uploads/2023/03/qrcode_for_gh_ada6dea0c7e9_258.jpeg)