Code Llama: Llama 2 学会编程

发布日期:2023 年 8 月 25 日
在 GitHub 上更新

引言

Code Llama 是 Llama 2 的一套先进的开放访问版本,专门用于代码任务,我们很高兴能在 Hugging Face 生态系统中发布集成!Code Llama 已以与 Llama 2 相同的宽松社区许可发布,并可用于商业用途。

今天,我们很高兴发布:

  • Hub 上的模型及其模型卡和许可证
  • Transformers 集成
  • 与 Text Generation Inference 集成,用于快速高效的生产级推理
  • 与推理端点集成
  • 与 VS Code 扩展集成
  • 代码基准测试

代码 LLM 对软件工程师来说是一项激动人心的发展,因为它们可以通过 IDE 中的代码自动补全、处理编写文档字符串等重复或繁琐的任务,或创建单元测试来提高生产力。

目录

什么是 Code Llama?

Code Llama 发布了 70 亿、130 亿和 340 亿参数的模型家族。基础模型在 Llama 2 的基础上进行初始化,然后使用 5000 亿个代码数据令牌进行训练。Meta 对这些基础模型进行了两种不同的微调:一种是 Python 专家(额外 1000 亿个令牌),另一种是指令微调版本,可以理解自然语言指令。

这些模型在 Python、C++、Java、PHP、C#、TypeScript 和 Bash 中表现出最先进的性能。7B 和 13B 基础模型以及指令变体支持基于周围内容的填充,使其成为代码助手的理想选择。

Code Llama 在 16k 上下文窗口上进行了训练。此外,这三种模型变体还进行了额外的长上下文微调,使其能够管理高达 100,000 个令牌的上下文窗口。

将 Llama 2 的 4k 上下文窗口扩展到 Code Llama 的 16k(可推断到 100k)得益于 RoPE 扩展的最新发展。社区发现 Llama 的位置嵌入可以线性插值或在频域中插值,这通过微调简化了到更大上下文窗口的转换。在 Code Llama 的情况下,频域缩放是在松弛状态下完成的:微调长度是缩放后的预训练长度的一部分,这赋予了模型强大的外推能力。

Training Process

所有模型最初都在一个接近去重化的公开可用代码数据集上使用 5000 亿个令牌进行训练。该数据集还包含一些自然语言数据集,例如关于代码和代码片段的讨论。不幸的是,没有更多关于该数据集的信息。

对于指令模型,他们使用了两个数据集:为 Llama 2 Chat 收集的指令微调数据集和一个自指令数据集。自指令数据集是使用 Llama 2 创建面试编程问题,然后使用 Code Llama 生成单元测试和解决方案,这些解决方案随后通过执行测试进行评估。

如何使用 Code Llama?

Code Llama 已在 Hugging Face 生态系统中使用,从 transformers 4.33 版开始。

演示

您可以在 此空间 或下面的嵌入式操场中轻松试用 Code Llama 模型(130 亿参数!)

该操场在底层使用了 Hugging Face 的 Text Generation Inference,与 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 位脑浮点数(bfloat16):Code Llama 以此精度进行训练,因此我们建议将其用于进一步训练或微调。
  • 16 位浮点数(float16):我们建议使用此精度进行推理,因为它通常比 bfloat16 快,并且评估指标显示与 bfloat16 相比没有明显退化。您也可以使用 bfloat16 进行推理,我们建议您在微调后使用 float16bfloat16 检查推理结果。

如上所述,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 模型的基础和指令变体中可用。它不适用于任何 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> 进行分割,以创建遵循原始训练模式的格式化输入字符串。这比自己准备模式更健壮:它避免了诸如令牌粘连之类的难以调试的陷阱。

会话指令

基础模型可以用于补全和填充,如前所述。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 获得答案,您可以在此处声明。在系统提示之后,您需要提供对话中所有先前的交互:用户提问的内容和模型回答的内容。与填充情况一样,您需要注意使用的分隔符。输入的最后一部分必须始终是新的用户指令,这将是模型提供答案的信号。

以下代码片段演示了该模板在实践中是如何工作的。

  1. 第一个用户查询,没有系统提示
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")
  1. 带有系统提示的第一个用户查询
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")
  1. 与先前答案进行的持续对话

过程与 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 位加载

Code Llama 在 Transformers 中的集成意味着您可以立即获得高级功能支持,例如 4 位加载。这允许您在 Nvidia 3090 等消费级 GPU 上运行大型 32B 参数模型!

以下是在 4 位模式下运行推理的方法:

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))

使用 text-generation-inference 和 Inference Endpoints

Text Generation Inference 是 Hugging Face 开发的生产级推理容器,可轻松部署大型语言模型。它具有连续批处理、令牌流式传输、用于在多个 GPU 上进行快速推理的张量并行化以及生产级日志记录和跟踪等功能。

您可以在自己的基础设施上试用 Text Generation Inference,也可以使用 Hugging Face 的 Inference Endpoints。要部署 Codellama 2 模型,请访问 模型页面 并单击 部署 -> Inference Endpoints 小部件。

  • 对于 7B 模型,我们建议您选择“GPU [中] - 1x Nvidia A10G”。
  • 对于 13B 模型,我们建议您选择“GPU [xlarge] - 1x Nvidia A100”。
  • 对于 34B 模型,我们建议您选择“GPU [1xlarge] - 1x Nvidia A100”并启用 bitsandbytes 量化,或选择“GPU [2xlarge] - 2x Nvidia A100”。

注意:您可能需要通过电子邮件向 api-enterprise@huggingface.co 申请配额升级才能访问 A100。

您可以在我们的博客中了解更多关于如何使用 Hugging Face Inference Endpoints 部署 LLM 的信息。该博客包含有关支持的超参数以及如何使用 Python 和 Javascript 流式传输响应的信息。

使用 VS Code 扩展

HF Code Autocomplete 是一个 VS Code 扩展,用于测试开源代码补全模型。该扩展是 StarCoder 项目的一部分,并已更新以支持中型基础模型 Code Llama 13B。有关如何安装和使用 Code Llama 扩展的更多信息,请参阅此处

VS Code extension

评估

代码语言模型通常在 HumanEval 等数据集上进行基准测试。它包括编程挑战,其中模型会获得一个函数签名和文档字符串,并被要求完成函数体。然后,通过运行一组预定义的单元测试来验证所提出的解决方案。最后,报告一个通过率,它描述了有多少解决方案通过了所有测试。pass@1 率描述了模型在一次尝试中生成通过解决方案的频率,而 pass@10 描述了在 10 个提出的候选方案中至少有一个解决方案通过的频率。

虽然 HumanEval 是一个 Python 基准测试,但已经有很多努力将其翻译成更多的编程语言,从而实现更全面的评估。其中一种方法是 MultiPL-E,它将 HumanEval 翻译成十多种语言。我们正在基于它托管一个多语言代码排行榜,以便社区可以比较不同语言的模型,以评估哪个模型最适合其用例。

模型 许可证 已知数据集 商业用途? 预训练长度 [令牌] 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

注意: 上表中的分数来源于发布时我们的代码排行榜。分数会随着新模型的发布而变化,因为模型之间会进行比较。欲了解更多详情,请参阅排行榜

附加资源

社区

注册登录 发表评论