Code Llama

🚨 弃用说明

本模型已过时,不再进行维护,并将在 1.6.0 版本下架。如需使用此模型,建议根据官方文档中的 模型库 选择合适的版本进行使用。

如有任何问题或建议,请通过 社区Issue 提交反馈。感谢您的理解与支持!

模型描述

Code Llama是基于Llama 2的一系列大型代码语言模型,它在开源模型中提供了最先进的性能、填充能力、对大型输入上下文的支持以及zero-shot指令跟随能力,用于编程任务。现有多种不同版本来覆盖广泛的应用领域:基础模型(Code Llama)、Python专业化模型(Code Llama - Python)和指令跟随模型(Code Llama - Instruct),每个模型分别具有7B、13B和34B个参数。所有模型都是在16k标记序列上进行训练,并对高达100k标记的输入显示出改进效果。7B和13B版本的Code Llama以及Code Llama - Instruct变体支持基于周围内容的填充功能。Code Llama是通过对Llama 2进行更高比例的代码取样进行微调而开发的。

Code Llama: Open Foundation Models for Code

模型性能

以下模型性能均由Atlas 800T A2硬件环境下测试得出。

Config Task SeqLength Datasets Performance Phase
codellama_34b_32p text_generation 4096 belle 667 tokens/s/p Finetune
codellama_34b text_generation 4096 / 139 tokens/s Predict

以下模型性能均由Atlas 900 A2 PoDc硬件环境下测试得出。

Config Task SeqLength Datasets Performance Phase
codellama_34b_16p text_generation 4096 code-alpaca 669 tokens/s/p Finetune
codellama_34b_32p text_generation 4096 code-alpaca 747 tokens/s/p Finetune

模型文件

Code Llama 基于 mindformers 实现,本仓库当前支持34b模型配置,主要涉及的文件有:

  1. 模型具体实现:

    mindformers/models/llama
        ├── __init__.py
        ├── convert_reversed.py         # 权重逆向转换
        ├── convert_weight.py           # llama权重转换
        ├── llama.py                    # 模型实现
        ├── llama_config.py             # 模型配置项
        ├── llama_interleave.py         # interleave优化
        ├── llama_layer.py              # llama网络层定义
        ├── llama_processor.py          # llama预处理
        ├── llama_tokenizer.py          # tokenizer
        ├── llama_tokenizer_fast.py     # fast tokenizer
        └── llama_transformer.py        # transformer层实现
    
  2. 模型配置:

    configs/codellama
        ├── pretrain_codellama_34b.yaml             # 34b模型预训练启动配置
        ├── finetune_codellama_34b_16p.yaml         # 34b模型2机16p微调启动配置
        ├── finetune_codellama_34b_32p.yaml         # 34b模型4机32p微调启动配置
        └── predict_codellama_34b.yaml              # 34b模型推理配置
    
  3. 数据预处理脚本:

    mindformers/tools/dataset_preprocess/llama/
        ├── alpaca_converter.py     # 基于fschat的alpaca数据集格式转换脚本
        ├── conversation.py         # 对话提示模板生成脚本
        └── llama_preprocess.py     # llama模型的mindrecord数据处理脚本
    

环境及数据准备

安装环境

MindFormers软硬件配套关系以及安装参考环境安装指南版本匹配关系

注:34b推理使用Atlas 800T A2 至少使用2卡,全量微调至少需要2机16卡,建议4机32卡。

数据及权重准备

数据集下载

MindFormers提供Wikitext2作为预训练数据集,code-alpaca作为微调数据集。

数据集名称 适用模型 适用阶段 下载链接
Wikitext2 CodeLlama_34b Pretrain Link
code-alpaca CodeLlama_34b Finetune Link
HumanEval CodeLlama_34b Evaluate Link

数据预处理中所用的tokenizer.model可以点击链接进行下载。

  • Wikitext2 数据预处理

    使用mindformers/tools/dataset_preprocess/llama/llama_preprocess.py对下载后的数据进行预处理,并生成Mindrecord数据。

    python llama_preprocess.py \
      --dataset_type wiki \
      --input_glob /{path}/wiki.train.tokens \
      --model_file /{path}/tokenizer.model \
      --seq_length 4096 \
      --output_file /{path}/wiki4096.mindrecord
    
    # 参数说明
    dataset_type: 预处理数据类型
    input_glob:   输入下载后wiki.train.tokens的文件路径
    model_file:   模型tokenizer.model文件路径
    seq_length:   输出数据的序列长度
    output_file:  输出文件的保存路径
    
  • code-alpaca 数据预处理

  1. 执行mindformers/tools/dataset_preprocess/llama/alpaca_converter.py,将原始数据集转换为多轮对话格式。

    python alpaca_converter.py \
     --data_path /{path}/code_alpaca_data.json \
     --output_path /{path}/code-alpaca-data-conversation.json
    
    # 参数说明
    data_path:   下载的alpaca数据路径
    output_path: 输出转换后对话格式的数据路径
    
  2. 执行mindformers/tools/dataset_preprocess/llama/llama_preprocess.py,进行数据预处理、Mindrecord数据生成,将带有prompt模板的数据转换为mindrecord格式。

    python llama_preprocess.py \
     --dataset_type qa \
     --input_glob /{path}/code-alpaca-data-conversation.json \
     --model_file /{path}/tokenizer.model \
     --seq_length 4096 \
     --output_file /{path}/code-alpaca-fastchat4096.mindrecord
    

模型权重下载

MindFormers提供下载HuggingFace官方权重的下载链接,用户可通过链接下载权重并经过模型权重转换后进行使用。

词表下载链接:tokenizer.model

模型名称 HuggingFace权重
CodeLlama-34b Link
CodeLlama-34b-Python Link
CodeLlama_34b-Instruct Link

模型权重转换

下载完成后,运行转换脚本mindformers/convert_weight.py,将huggingface的权重转换为完整的ckpt权重。

# 使用transformers = 4.34.0,torch>=2.0进行转换
python convert_weight.py --model llama --input_path TORCH_CKPT_DIR --output_path {path}/MS_CKPT_NAME

# 参数说明
model:       模型名称
input_path:  下载HuggingFace权重的文件夹路径
output_path: 转换后的MindSpore权重文件保存路径

预训练

MindFormers提供了Code Llama 34b多机预训练示例,使用Wikitext2数据集对模型进行预训练,数据集可以参考数据集下载获得。

Code Llama 34b由于模型规模较大,仅支持多机预训练,至少使用2机16卡进行训练。

  1. 修改配置文件config/codellama/pretrain_codellama_34b.yaml

    根据服务器节点数等信息,修改相应的并行配置。

    parallel_config:
      data_parallel: 1
      model_parallel: 8
      pipeline_stage: 2
      use_seq_parallel: True
      micro_batch_num: 128
      vocab_emb_dp: True
      gradient_aggregation_group: 4
    
  2. 在分布式节点上执行脚本

    多机多卡训练需要不同节点上执行启动命令,将参数MASTER_ADDR设置为主节点的ip地址, 所有节点设置的ip地址相同,不同节点之间仅参数NODE_RANK不同,具体可参考使用指南

    # 节点0,节点ip为{ip_addr},作为主节点,总共16卡且每个节点8卡
    bash scripts/msrun_launcher.sh "run_mindformer.py \
     --config configs/codellama/pretrain_codellama_34b.yaml \
     --train_dataset_dir /path/wiki4096.mindrecord \
     --run_mode train" \
    16 8 {ip_addr} 8118 0 output/msrun_log False 300
    
    # 节点1,节点0与节点1启动命令仅参数NODE_RANK不同
    bash scripts/msrun_launcher.sh "run_mindformer.py \
     --config configs/codellama/pretrain_codellama_34b.yaml \
     --train_dataset_dir /path/wiki4096.mindrecord \
     --run_mode train" \
    16 8 {ip_addr} 8118 1 output/msrun_log False 300
    
    # 参数说明
    config:            配置文件路径
    train_dataset_dir: 训练数据集路径
    run_mode:          运行模式, 预训练时设置为train
    

微调

MindFormers提供Code Llama 34b的微调示例,使用code-alpaca数据集对模型进行微调,数据集可以参考数据集下载获得。

全参微调

Code Llama 34b由于模型规模较大,仅支持多机微调,至少使用2机16卡进行训练。

  1. 生成多机分布式权重

    如果使用共享存储,可以将模型完整权重放在共享存储内,同时设置配置文件或脚本参数auto_trans_ckpt=True,使用权重自动转换功能。

    如果不使用共享存储,可以参考多卡权重之间的转换完成分布式权重转换后拉起预训练任务。

  2. 修改配置文件config/codellama/finetune_codellama_34b_16p.yaml

    根据服务器节点数等信息,修改相应的并行配置。

    parallel_config:
      data_parallel: 1
      model_parallel: 8
      pipeline_stage: 2
      use_seq_parallel: True
      micro_batch_num: 128
      vocab_emb_dp: True
      gradient_aggregation_group: 4
    
  3. 在分布式节点上执行脚本,进行2机16卡微调

    多机多卡训练需要不同节点上执行启动命令,将参数MASTER_ADDR设置为主节点的ip地址, 所有节点设置的ip地址相同,不同节点之间仅参数NODE_RANK不同,具体可参考使用指南

    示例使用共享存储并开启auto_trans_ckpt进行权重自动转换。

    # 节点0,节点ip为{ip_addr},作为主节点,总共16卡且每个节点8卡
    bash scripts/msrun_launcher.sh "run_mindformer.py \
     --config configs/codellama/finetune_codellama_34b_16p.yaml \
     --load_checkpoint /path/codellama_34b.ckpt \
     --auto_trans_ckpt True \
     --train_dataset_dir /path/code-alpaca-fastchat4096.mindrecord \
     --run_mode finetune" \
    16 8 {ip_addr} 8118 0 output/msrun_log False 300
    
    # 节点1,节点0与节点1启动命令仅参数NODE_RANK不同
    bash scripts/msrun_launcher.sh "run_mindformer.py \
     --config configs/codellama/finetune_codellama_34b_16p.yaml \
     --load_checkpoint /path/codellama_34b.ckpt \
     --auto_trans_ckpt True \
     --train_dataset_dir /path/code-alpaca-fastchat4096.mindrecord \
     --run_mode finetune" \
    16 8 {ip_addr} 8118 1 output/msrun_log False 300
    
    # 参数说明
    config:            配置文件路径
    load_checkpoint:   模型权重文件路径
    auto_trans_ckpt:   是否开启自动权重转换
    train_dataset_dir: 训练数据集路径
    run_mode:          运行模式, 微调时设置为finetune
    

分布式训练权重合并

分布式训练(微调)后所得到的权重文件为根据策略切分后的权重,可以手动将切分权重合一,以用于评估和推理。

MindFormers提供自动权重转换和离线权重转换功能,可参考自动转换离线权重转换进行分布式模型权重转换。

推理

MindFormers提供CodeLlama_34b的快速推理脚本,脚本主要通过generate高阶接口实现,支持多卡以及多batch推理。

# 脚本使用
bash scripts/examples/codellama/run_codellama_predict.sh CONFIG_PATH CKPT_PATH TOKENIZER_PATH DEVICE_NUM

# 参数说明
CONFIG_PATH: 模型配置文件路径
CKPT_PATH:   模型权重文件路径
TOKENIZER_PATH: tokenizer.model文件路径
DEVICE_NUM:  使用卡数

CodeLlama_34b仅支持多卡推理,以CodeLlama_34b4卡推理为例。

执行脚本如下:

bash scripts/examples/codellama/run_codellama_predict.sh \
 configs/codellama/predict_codellama_34b.yaml \
 path/to/codellama_34b.ckpt \
 path/to/tokenizer.model 4

# 推理结果
# <s>def bubble_sort(arr):
#     n = len(arr)
#     for i in range(n):
# ...
# def selection_sort(arr):
#     n = len(arr)
#     for i in range(n):
# ...

评测

Code Llama当前支持的评测任务如下:

任务类型 评测指标 数据集
代码生成 Pass@1 HumanEeval

代码生成

评测使用HumanEval数据集可通过数据集下载获得,使用git下载代码仓。

  1. 代码下载完成后,安装HumanEval依赖。

    pip install -e human-eval
    
  2. 构建如下preprocess.py脚本放入数据集代码仓中的human-eval文件夹中,进行数据集预处理。

    处理得到的data_list列表总共包含164组测试数据。

    每组测试数据格式为{"task_id": xx, "prompt": xx, "canonical_solution": xx, "test": xx, "entry_point": xx}

    # preprocess.py
    import argparse
    
    from data import stream_jsonl
    
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser("copy prompt")
        parser.add_argument("--data_path", default="", type=str)
        args = parser.parse_args()
    
        data_list = []
        for data in stream_jsonl(args.data_path):
            data_list.append(data)
    
       # 保存第一组数据的"task_id"和"prompt"值做评测
       print(data_list[0])
    
    

    执行preprocess.py脚本。

     python preprocess.py --data_path path/to/HumanEval.jsonl.gz
    

    取出task_idprompt值。

    'task_id': 'HumanEval/0',
    'prompt': 'from typing import List\n\n\ndef has_close_elements(numbers: List[float], threshold: float) -> bool:\n    """ Check if in given list of numbers, are any two numbers closer to each other than\n    given threshold.\n    >>> has_close_elements([1.0, 2.0, 3.0], 0.5)\n    False\n    >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)\n    True\n    """\n',
    
  3. 使用prompt数据进行推理并将推理结果用completion字段保存,整理为samples.jsonl

    run_codellama_generate.py中修改inputs内容,改为prompt数据(注意字符串转义)。

    inputs = ["from typing import List\n\n\ndef has_close_elements(numbers: List[float], threshold: float) -> bool:\n    \"\"\" Check if in given list of numbers, are any two numbers closer to each other than\n    given threshold.\n    >>> has_close_elements([1.0, 2.0, 3.0], 0.5)\n    False\n    >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)\n    True\n    \"\"\"\n"]
    

    执行命令得到推理结果。

    bash scripts/examples/codellama/run_codellama_predict.sh \
    configs/codellama/predict_codellama_34b.yaml \
    path/to/codellama_34b.ckpt \
    path/to/tokenizer.model 4
    
    

    将推理结果去除prompt数据后保存至completion字段,整理成samples.jsonl文件。

    {"task_id": "HumanEval/0", "completion": "    for i in range(len(numbers) - 1):\n        for j in range(i + 1, len(numbers)):\n            if abs(numbers[i] - numbers[j]) < threshold:\n                return True\n    return False"}
    
  4. 生成测试分数

    evaluation.py中将assert len(completion_id) == len(problems), "Some problems are not attempted."注释掉。

    # assert len(completion_id) == len(problems), "Some problems are not attempted."
    

    执行评测脚本。

     evaluate_functional_correctness /path/to/samples.jsonl
     # {'pass@1': 测试分数}