Meta 发布 Code Llama:Llama 2 的代码专用版本并接入 Hugging Face 生态
Code Llama: Llama 2 learns to code
Meta 发布 Code Llama,这是基于 Llama 2 初始化、在 5000 亿 token 代码数据上训练的开源代码模型系列,提供 7B、13B、34B 三个参数版本,另有 Python 专用版(额外 1000 亿 token)和指令微调版,采用与 Llama 2 相同的许可协议并允许商用。
梳理 Code Llama 三个参数版本、Python 与 Instruct 变体的训练构成及生态集成方式,方便对照选型。
引言
Code Llama 是一系列先进的开源版本 Llama 2,专门针对代码任务进行了优化,我们非常高兴地宣布已在 HF Mirror 生态系统中集成了它!Code Llama 与 Llama 2 采用相同的宽松社区许可证发布,并可供商业使用。
今天,我们激动地宣布发布:
- Hub 上的模型及其模型卡和许可证
- Transformers 集成
- 与 Text Generation Inference 集成,实现快速高效的生产级推理
- 与 Inference Endpoints 集成
- 与 VS Code 扩展集成
- 代码基准测试
代码大语言模型对软件工程师来说是一个令人兴奋的发展,因为它们可以通过 IDE 中的代码补全来提高生产力,处理重复或烦人的任务,如编写文档字符串,或创建单元测试。
目录
什么是 Code Llama?
Code Llama 发布引入了一系列模型,参数规模分别为 70 亿、130 亿和 340 亿。基础模型从 Llama 2 初始化,然后在 5000 亿个代码数据标记上进行训练。Meta 针对两种不同风格对这些基础模型进行了微调:一种是 Python 专家(额外 1000 亿个标记),另一种是指令微调版本,能够理解自然语言指令。
这些模型在 Python、C++、Java、PHP、C#、TypeScript 和 Bash 中展现出最先进的性能。70 亿和 130 亿参数的基础版和指令版变体支持基于周围内容的填充,使其非常适合作为代码助手。
Code Llama 在 16k 上下文窗口上进行训练。此外,三个模型变体还进行了额外的长上下文微调,使它们能够处理高达 100,000 个标记的上下文窗口。
将 Llama 2 的 4k 上下文窗口增加到 Code Llama 的 16k(可外推至 100k)得益于 RoPE 缩放的最新进展。社区发现 Llama 的位置嵌入可以线性插值或在频域中插值,这通过微调简化了向更大上下文窗口的过渡。在 Code Llama 的情况下,频域缩放采用了一种松弛方式:微调长度是缩放预训练长度的一小部分,赋予了模型强大的外推能力。
所有模型最初都在近去重的公开可用代码数据集上训练了 5000 亿个标记。数据集还包含一些自然语言数据集,例如关于代码的讨论和代码片段。遗憾的是,没有更多关于数据集的信息。
对于指令模型,他们使用了两个数据集:为 Llama 2 Chat 收集的指令微调数据集和一个自指令数据集。自指令数据集是通过使用 Llama 2 创建面试编程问题,然后使用 Code Llama 生成单元测试和解决方案,之后通过执行测试进行评估而创建的。
如何使用 Code Llama?
Code Llama 现已在 HF Mirror 生态系统中提供,从 transformers 版本 4.33 开始。
演示
你可以在 这个 Space 中轻松尝试 Code Llama 模型(130 亿参数!),或在下方嵌入的 playground 中试用:
在底层,这个 playground 使用了 HF Mirror 的 文本生成推理,这也是驱动 HuggingChat 的同一技术,我们将在后续部分分享更多内容。
如果你想尝试更大的、经指令微调的 34B 模型,它现在已在 HuggingChat 上线!你可以在这里试用:hf.co/chat。请确保指定 Code Llama 模型。你也可以查看这个基于聊天的演示并将其复制用于你的用途——它是自包含的,因此你可以查看源代码并按需修改!
Transformers
从 transformers 4.33 开始,你可以使用 Code Llama 并利用 HF 生态系统中的所有工具,例如:
- 训练和推理脚本及示例
- 安全的文件格式(
safetensors) - 与
bitsandbytes(4 位量化)和 PEFT(参数高效微调)等工具的集成 - 用于运行模型生成的实用工具和辅助函数
- 将模型导出以供部署的机制
!pip install --upgrade transformers
关于 dtypes 的说明
使用像 Code Llama 这样的模型时,查看模型的数据类型非常重要。
- 32 位浮点数(
float32):PyTorch 在模型初始化时的惯例是以float32加载模型,无论模型权重以何种精度存储。transformers也遵循此惯例,以与 PyTorch 保持一致。 - 16 位 Brain 浮点数(
bfloat16):Code Llama 以此精度训练,因此我们建议将其用于进一步训练或微调。 - 16 位浮点数(
float16):我们建议使用此精度进行推理,因为它通常比bfloat16更快,且评估指标显示相对于bfloat16没有可察觉的退化。你也可以使用bfloat16进行推理,我们建议你在微调后同时检查float16和bfloat16的推理结果。
如上所述,transformers 使用 float32 加载权重(无论模型以何种精度存储),因此在加载模型时指定所需的 dtype 非常重要。如果你想微调 Code Llama,建议使用 bfloat16,因为使用 float16 可能导致溢出和 NaN。如果进行推理,我们建议使用 float16,因为 bfloat16 可能更慢。
代码补全
7B 和 13B 模型可用于文本/代码补全或填充。以下代码片段使用 pipeline 接口来演示文本补全。只要选择 GPU 运行时,它就能在 Colab 的免费层级上运行。
from transformers import AutoTokenizer
import transformers
import torch
tokenizer = AutoTokenizer.from_pretrained("codellama/CodeLlama-7b-hf")
pipeline = transformers.pipeline(
"text-generation",
model="codellama/CodeLlama-7b-hf",
torch_dtype=torch.float16,
device_map="auto",
)
sequences = pipeline(
'def fibonacci(',
do_sample=True,
temperature=0.2,
top_p=0.9,
num_return_sequences=1,
eos_token_id=tokenizer.eos_token_id,
max_length=100,
)
for seq in sequences:
print(f"Result: {seq['generated_text']}")
这可能会产生如下输出:
Result: def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
def fibonacci_memo(n, memo={}):
if n == 0:
return 0
elif n == 1:
return
Code Llama 专注于代码理解,但它本身也是一个语言模型。你可以使用相同的生成策略来自动补全注释或一般文本。
代码填充
这是代码模型特有的一项专门任务。该模型经过训练,能够生成与现有前缀和后缀最匹配的代码(包括注释)。这是代码助手通常使用的策略:它们被要求根据光标位置前后的内容来填充当前光标位置。
此任务适用于 7B 和 13B 模型的 base 和 instruction 变体。它不适用于任何 34B 模型或 Python 版本。
要成功使用此功能,您需要密切关注用于训练此任务模型的格式,因为它使用特殊分隔符来标识提示的不同部分。幸运的是,transformers 的 CodeLlamaTokenizer 使其变得非常简单,如下所示:
from transformers import AutoTokenizer, AutoModelForCausalLM
import transformers
import torch
model_id = "codellama/CodeLlama-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16
).to("cuda")
prompt = '''def remove_non_ascii(s: str) -> str:
""" <FILL_ME>
return result
'''
input_ids = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
output = model.generate(
input_ids,
max_new_tokens=200,
)
output = output[0].to("cpu")
filling = tokenizer.decode(output[input_ids.shape[1]:], skip_special_tokens=True)
print(prompt.replace("<FILL_ME>", filling))
def remove_non_ascii(s: str) -> str:
""" Remove non-ASCII characters from a string.
Args:
s: The string to remove non-ASCII characters from.
Returns:
The string with non-ASCII characters removed.
"""
result = ""
for c in s:
if ord(c) < 128:
result += c
return result
在底层,分词器 自动按 <FILL_ME> 分割,以创建遵循 原始训练模式 的格式化输入字符串。这比您自己准备模式更稳健:它避免了诸如 token 粘连等非常难以调试的陷阱。
对话指令
基础模型可用于补全和填充,如所述。Code Llama 版本还包括一个指令微调模型,可用于对话界面。
要为这项任务准备输入,我们必须使用类似我们在 Llama 2 博客文章中描述的提示模板,我们在此再次复制如下:
<s>[INST] <<SYS>>
{{ system_prompt }}
<</SYS>>
{{ user_msg_1 }} [/INST] {{ model_answer_1 }} </s><s>[INST] {{ user_msg_2 }} [/INST]
注意,系统提示是可选的——模型没有它也能正常工作,但您可以使用它来进一步配置其行为或风格。例如,如果您总是希望得到 JavaScript 格式的答案,可以在此处说明。在系统提示之后,您需要提供对话中所有之前的交互:用户提出了什么以及模型回答了什麼。如同填充情况一样,您需要注意使用的分隔符。输入的最后一个组成部分必须始终是新的用户指令,这将是模型提供答案的信号。
以下代码片段展示了模板在实践中如何工作。
- 第一个用户查询,无系统提示
user = 'In Bash, how do I list all text files in the current directory (excluding subdirectories) that have been modified in the last month?'
prompt = f"<s>[INST] {user.strip()} [/INST]"
inputs = tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to("cuda")
- 第一个用户查询,带系统提示
system = "Provide answers in JavaScript"
user = "Write a function that computes the set of sums of all contiguous sublists of a given list."
prompt = f"<s>[INST] <<SYS>>\\n{system}\\n<</SYS>>\\n\\n{user}[/INST]"
inputs = tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to("cuda")
- 与以往答案的 ongoing 对话
过程与 Llama 2 中相同。为了最大清晰度,我们没有使用循环或泛化此示例代码:
system = "System prompt"
user_1 = "user_prompt_1"
answer_1 = "answer_1"
user_2 = "user_prompt_2"
answer_2 = "answer_2"
user_3 = "user_prompt_3"
prompt = f"<<SYS>>\n{system}\n<</SYS>>\n\n{user_1}"
prompt = f"<s>[INST] {prompt.strip()} [/INST] {answer_1.strip()} </s>"
prompt += f"<s>[INST] {user_2.strip()} [/INST] {answer_2.strip()} </s>"
prompt += f"<s>[INST] {user_3.strip()} [/INST]"
inputs = tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to("cuda")
4-bit 加载
将 Code Llama 集成到 Transformers 中意味着您可以立即获得对 4-bit 加载等高级功能的支持。这使您可以在消费级 GPU(如 NVIDIA 3090 卡)上运行大型 32B 参数模型!
以下是如何在 4-bit 模式下运行推理:
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
import torch
model_id = "codellama/CodeLlama-34b-hf"
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=quantization_config,
device_map="auto",
)
prompt = 'def remove_non_ascii(s: str) -> str:\n """ '
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
output = model.generate(
inputs["input_ids"],
max_new_tokens=200,
do_sample=True,
top_p=0.9,
temperature=0.1,
)
output = output[0].to("cpu")
print(tokenizer.decode(output))
使用文本生成推理和推理端点
文本生成推理 是 HF Mirror 开发的一个生产就绪的推理容器,用于轻松部署大型语言模型。它具有连续批处理、令牌流式传输、用于在多个 GPU 上快速推理的张量并行性以及生产就绪的日志记录和跟踪等功能。
您可以在自己的基础设施上试用文本生成推理,或者使用 HF Mirror 的 推理端点。要部署 Codellama 2 模型,请转到 模型页面 并点击 部署 -> 推理端点 小部件。
- 对于 7B 模型,我们建议您选择“GPU [medium] - 1x Nvidia A10G”。
- 对于 13B 模型,我们建议您选择“GPU [xlarge] - 1x Nvidia A100”。
- 对于 34B 模型,我们建议您选择启用
bitsandbytes量化的“GPU [1xlarge] - 1x Nvidia A100”或“GPU [2xlarge] - 2x Nvidia A100”
注意:您可能需要通过电子邮件向 [email protected] 请求配额升级以访问 A100
你可以在我们的博客中了解更多关于如何使用 HF Mirror Inference Endpoints 部署 LLMs的信息。该 博客 包含有关支持的超参数以及如何使用 Python 和 Javascript 进行流式响应的信息。
使用 VS Code 扩展
HF Code Autocomplete 是一个用于测试开源代码补全模型的 VS Code 扩展。该扩展是作为 StarCoder 项目 的一部分开发的,并已更新以支持中等规模的基座模型 Code Llama 13B。请在此处了解更多关于如何安装并使用该扩展与 Code Llama 一起运行的信息。
评估
代码语言模型通常在如 HumanEval 等数据集上进行基准测试。该数据集由编程挑战组成,其中模型会收到一个函数签名和文档字符串,并被要求补全函数体。随后,通过运行一组预定义的单元测试来验证所提出的解决方案。最后,报告通过率,该通过率描述了有多少解决方案通过了所有测试。pass@1 通过率描述了模型在只有一次机会时生成通过解决方案的频率,而 pass@10 则描述了在 10 个提议候选方案中至少有一个通过的频率。
虽然 HumanEval 是一个 Python 基准测试,但已有大量工作致力于将其翻译成更多编程语言,从而实现更全面的评估。其中一种方法是 MultiPL-E,它将 HumanEval 翻译成十多种语言。我们基于它托管了一个多语言代码排行榜,以便社区可以跨不同语言比较模型,从而评估哪种模型最适合他们的使用场景。
| 模型 | 许可证 | 已知数据集 | 商业使用? | 预训练长度 [tokens] | Python | JavaScript | 排行榜平均分数 |
|---|---|---|---|---|---|---|---|
| CodeLlaMa-34B | Llama 2 许可证 | ❌ | ✅ | 2,500B | 45.11 | 41.66 | 33.89 |
| CodeLlaMa-13B | Llama 2 许可证 | ❌ | ✅ | 2,500B | 35.07 | 38.26 | 28.35 |
| CodeLlaMa-7B | Llama 2 许可证 | ❌ | ✅ | 2,500B | 29.98 | 31.8 | 24.36 |
| CodeLlaMa-34B-Python | Llama 2 许可证 | ❌ | ✅ | 2,620B | 53.29 | 44.72 | 33.87 |
| CodeLlaMa-13B-Python | Llama 2 许可证 | ❌ | ✅ | 2,620B | 42.89 | 40.66 | 28.67 |
| CodeLlaMa-7B-Python | Llama 2 许可证 | ❌ | ✅ | 2,620B | 40.48 | 36.34 | 23.5 |
| CodeLlaMa-34B-Instruct | Llama 2 许可证 | ❌ | ✅ | 2,620B | 50.79 | 45.85 | 35.09 |
| CodeLlaMa-13B-Instruct | Llama 2 许可证 | ❌ | ✅ | 2,620B | 50.6 | 40.91 | 31.29 |
| CodeLlaMa-7B-Instruct | Llama 2 许可证 | ❌ | ✅ | 2,620B | 45.65 | 33.11 | 26.45 |
| StarCoder-15B | BigCode-OpenRail-M | ✅ | ✅ | 1,035B | 33.57 | 30.79 | 22.74 |
| StarCoderBase-15B | BigCode-OpenRail-M | ✅ | ✅ | 1,000B | 30.35 | 31.7 | 22.4 |
| WizardCoder-15B | BigCode-OpenRail-M | ❌ | ✅ | 1,035B | 58.12 | 41.91 | 32.07 |
| OctoCoder-15B | BigCode-OpenRail-M | ✅ | ✅ | 1,000B | 45.3 | 32.8 | 24.01 |
| CodeGeeX-2-6B | CodeGeeX 许可证 | ❌ | ❌ | 2,000B | 33.49 | 29.9 | 21.23 |
| CodeGen-2.5-7B-Mono | Apache-2.0 | ✅ | ✅ | 1400B | 45.65 | 23.22 | 12.1 |
| CodeGen-2.5-7B-Multi | Apache-2.0 | ✅ | ✅ | 1400B | 28.7 | 26.27 | 20.04 |
注意:上表中呈现的分数来源于发布时的代码排行榜。由于模型之间会相互比较,随着新模型的发布,分数会发生变化。更多详情,请参考排行榜。
其他资源
来源:Hugging Face Blog · hf-mirror.com

