Project Icon

mistral-finetune

基于LoRA技术的Mistral模型高效微调框架

mistral-finetune是一个基于LoRA技术的轻量级框架,通过仅训练1-2%的额外权重来实现Mistral模型的高效微调。该框架支持多GPU单节点训练,适合A100或H100 GPU使用。它提供简化的数据格式要求和验证工具,支持指令跟随和函数调用等多种训练模式,适用于各类微调需求。

Mistral-微调

在Colab中打开

mistral-finetune是一个轻量级代码库,能够实现Mistral模型的内存高效和高性能微调。 它基于LoRA,这是一种训练范式,其中大部分权重被冻结,只有1-2%的额外权重以低秩矩阵扰动的形式被训练。

为了最大效率,建议使用A100或H100 GPU。该代码库针对多GPU单节点训练设置进行了优化, 但对于较小的模型,如7B,单个GPU就足够了。

注意

  • 本仓库的目标是提供一个简单的、有指导的入口点来微调Mistral模型。 因此,它相当有主见(特别是在数据格式方面),并不旨在涵盖 多种模型架构或硬件类型。 对于更通用的方法,你可以查看一些其他优秀的项目,如 torchtune

新闻

  • 2024年8月13日: Mistral Large v2现在与mistral-finetune兼容!

      1. 这里下载123B Instruct,并将model_id_or_path设置为下载的检查点目录。
      1. 由于模型规模更大,微调Mistral-Large v2需要显著更多的内存。目前,请将seq_len设置为<= 8192。
      1. 建议使用比其他模型更低的学习率,例如,lr=1e-6对大多数情况应该效果不错。
  • 2024年7月19日: Mistral Nemo现在与mistral-finetune兼容!

      1. 这里下载12B Base或Instruct,并将model_id_or_path设置为下载的检查点目录。
      1. 运行pip install --upgrade mistral-common以获取支持Tekkenizer的版本(>=1.3.1)。
      1. 由于词汇表更大,导致CE损失的峰值内存需求激增,目前微调Mistral-Nemo需要更多内存(我们很快会在这里添加一个改进的CE损失)。目前,请将seq_len设置为<= 16384。
      1. 建议使用与7B v3相同的超参数。

安装

要开始使用Mistral LoRA微调,请按以下步骤操作:

  1. 克隆此仓库:
cd $HOME && git clone https://github.com/mistralai/mistral-finetune.git
  1. 安装所有必需的依赖:
cd mistral-finetune
pip install -r requirements.txt

模型下载

我们建议微调以下官方Mistral模型之一,您可以在此处下载:

模型链接校验和
7B Base V37B Base0663b293810d7571dad25dae2f2a5806
7B Instruct v37B Instruct v380b71fcb6416085bcb4efad86dfb4d52
8x7B Base V18x7B Base(HF 链接)
8x7B Instruct V18x7B Instruct8e2d3930145dc43d3084396f49d38a3f
8x22 Instruct V38x22 Instruct471a02a6902706a2f1e44a693813855b
8x22B Base V38x22B Basea2fa75117174f87d1197e3a4eb50371a
12B Instruct12B Instruct (Mistral-Nemo)296fbdf911cb88e6f0be74cd04827fe7
12B Base12 Base (Mistral-Nemo)c5d079ac4b55fc1ae35f51f0a3c0eb83
Mistral Large 2123B Instruct (Large v2)fc602155f9e39151fba81fcaab2fa7c4

重要提示:对于8x7B Base V1和8x7B Instruct V1,在微调之前需要使用我们的v3分词器并将词汇表大小扩展到32768。有关此过程的详细说明,请参阅"模型扩展"部分。

例如,要下载7B-base模型,您可以运行以下命令:

mkdir -p ~/${HOME}/mistral_models
cd ${HOME} && wget https://models.mistralcdn.com/mistral-7b-v0-3/mistral-7B-v0.3.tar
tar -xf mistral-7B-v0.3.tar -C mistral_models

确保修改您的训练脚本,并将下载文件夹的路径添加为model_id_or_path

例如,修改example/7B.yaml以包含$HOME/mistral_models/7B的绝对路径:

model_id_or_path: "/Users/johndoe/mistral_models/7B"

准备数据集

为确保有效训练,mistral-finetune对训练数据的格式有严格要求。

所有数据文件必须以jsonl格式存储。

您可以构建两种类型的数据文件:

预训练

预训练数据对应于存储在"text"键中的纯文本数据。例如:

{"text": "文档1中包含的文本"}
{"text": "文档2中包含的文本"}

指令

目前支持两种不同类型的指令跟随数据:

  • 指令:以列表形式存储在"messages"键中的对话数据。每个列表项是一个包含"content""role"键的字典。"role"是一个字符串,可以是"user"、"assistant"或"system"之一。只有当"role" == "assistant"时才会计算损失。例如:
{
  "messages": [
    {
      "role": "user",
      "content": "文档1中包含的用户交互1"
    },
    {
      "role": "assistant",
      "content": "文档1中包含的机器人交互1"
    },
    {
      "role": "user",
      "content": "文档1中包含的用户交互2"
    },
    {
      "role": "assistant",
      "content": "文档1中包含的机器人交互2"
    }
  ]
}
{
  "messages": [
    {
      "role": "user",
      "content": "文档2中包含的用户交互1"
    },
    {
      "role": "assistant",
      "content": "文档2中包含的机器人交互1"
    },
    {
      "role": "user",
      "content": "文档2中包含的用户交互2"
    },
    {
      "role": "assistant",
      "content": "文档2中包含的机器人交互2",
      "weight": 0,  # 不对交互2进行训练
    },
    {
      "role": "user",
      "content": "文档2中包含的用户交互3"
    },
    {
      "role": "assistant",
      "content": "文档2中包含的机器人交互3"
    }
  ]
}
  • 函数调用:以列表形式存储在"messages"键中的对话数据。每个列表项是一个包含"role""content""tool_calls"键的字典。"role"是一个字符串,可以是"user"、"assistant"、"system"或"tool"之一。只有当"role" == "assistant"时才会计算损失。 注意:在函数调用中,"tool_calls"的"id"和"tool_call_id"是随机生成的恰好9个字符的字符串。我们建议在数据准备脚本中自动生成这些字符串,就像这里所做的那样。

例如:

{
  "messages": [
    {
      "role": "system",
      "content": "你是一个有权访问以下函数的有用助手,你可以在需要时使用这些函数来帮助用户"
    },
    {
      "role": "user",
      "content": "你能帮我生成"listen"这个词的字谜吗?"
    },
    {
      "role": "assistant",
      "tool_calls": [
        {
          "id": "TX92Jm8Zi",
          "type": "function",
          "function": {
            "name": "generate_anagram",
            "arguments": "{\"word\": \"listen\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "content": "{\"anagram\": \"silent\"}",
      "tool_call_id": "TX92Jm8Zi"
    },
    {
      "role": "assistant",
      "content": ""listen"这个词的字谜是"silent"。"
    },
    {
      "role": "user",
      "content": "太神奇了!你能为"race"这个词生成一个字谜吗?"
    },
    {
      "role": "assistant",
      "tool_calls": [
        {
          "id": "3XhQnxLsT",
          "type": "function",
          "function": {
            "name": "generate_anagram",
            "arguments": "{\"word\": \"race\"}"
          }
        }
      ]
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "generate_anagram",
        "description": "生成给定单词的字谜",
        "parameters": {
          "type": "object",
          "properties": {
            "word": {
              "type": "string",
              "description": "要生成字谜的单词"
            }
          },
          "required": [
            "word"
          ]
        }
      }
    }
  ]
}

验证数据集

在开始训练之前,你应该验证你的数据集格式是否正确,并估算训练时间。你可以使用./utils/validate_data脚本来完成这个任务。

注意,这一步对于确保数据格式正确至关重要。

指令遵循

让我们通过一个简单的例子来训练一个指令遵循模型:

创建数据文件夹并进入该文件夹。

cd $HOME && mkdir -p data && cd $HOME/data

将数据加载到Pandas DataFrame中。

注意:确保已安装pandas和pyarrow(pip install pandas pyarrow)。

import pandas as pd

df = pd.read_parquet('https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k/resolve/main/data/test_gen-00000-of-00001-3d4cd8309148a71f.parquet')
    1. 分割为训练集和评估集
df_train=df.sample(frac=0.95,random_state=200)
df_eval=df.drop(df_train.index)
    1. 将数据保存为jsonl格式
df_train.to_json("ultrachat_chunk_train.jsonl", orient="records", lines=True)
df_eval.to_json("ultrachat_chunk_eval.jsonl", orient="records", lines=True)
    1. 修改你的训练yaml文件,包含ultrachat数据集,并验证yaml文件

修改example/7B.yaml,包含$HOME/data/ultrachat_chunk_train.jsonl的绝对路径以及训练的数据集混合权重,并包含$HOME/data/ultrachat_chunk_eval.jsonl用于评估,例如:

data:
  instruct_data: "/Users/johndoe/data/ultrachat_chunk_train.jsonl"
  eval_instruct_data: "/Users/johndoe/data/ultrachat_chunk_eval.jsonl"

现在你可以验证你的训练yaml文件,确保数据格式正确,并估算训练时间。

cd $HOME/mistral-finetune
python -m utils.validate_data --train_yaml example/7B.yaml

完成后,你应该会看到一份错误报告,其中包含许多如下的错误:

数据集/Users/johndoe/data/ultrachat_chunk_eval.jsonl的第1412行格式不正确。最后一个角色应该是:[assistant]中的一个,但得到的是user
数据集/Users/johndoe/data/ultrachat_chunk_eval.jsonl的第1413行格式不正确。最后一个角色应该是:[assistant]中的一个,但得到的是user
数据集/Users/johndoe/data/ultrachat_chunk_eval.jsonl的第1414行格式不正确。最后一个角色应该是:[assistant]中的一个,但得到的是user
数据集/Users/johndoe/data/ultrachat_chunk_eval.jsonl的第1415行格式不正确。最后一个角色应该是:[assistant]中的一个,但得到的是user

许多对话似乎以'user'角色结束,这是不必要的,因为我们只训练'assistant'消息,这样会不必要地处理数据。

你可以使用./utils/reformat_data.py来修正数据:

cd $HOME/mistral-finetune
python -m utils.reformat_data $HOME/data/ultrachat_chunk_train.jsonl
python -m utils.reformat_data $HOME/data/ultrachat_chunk_eval.jsonl

你应该会看到一些样本被跳过。

    1. 可能需要更改训练步骤数

在修正数据集后,再次运行脚本

cd $HOME/mistral-finetune
python -m utils.validate_data --train_yaml example/7B.yaml

你应该会得到数据输入和训练参数的摘要:

训练状态
 --------------------
{
   "expected": {
       "eta": "00:52:44",
       "data_tokens": 25169147,
       "train_tokens": 131072000,
       "epochs": "5.21",
       "max_steps": 500,
       "data_tokens_per_dataset": {
           "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "25169147.0"
       },
       "train_tokens_per_dataset": {
           "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "131072000.0"
       },
       "epochs_per_dataset": {
           "/Users/johndoe/data/ultrachat_chunk_train.jsonl": "5.2"
       }
   },
}

max_steps设置为500会导致大约遍历数据集5次,这是合理的,但可能有点太多。下面显示了一个推荐的设置,在8xH100集群上只需30分钟。

函数调用

接下来,让我们看一个更高级的用例,即在函数调用上微调模型。 函数调用要求数据格式如上面所解释的。让我们看一个例子。

创建数据文件夹并进入该文件夹。

cd $HOME && mkdir -p data && cd $HOME/data

将数据加载到Pandas DataFrame中。

注意:确保已安装pandas和pyarrow(pip install pandas pyarrow)。

import pandas as pd

df = pd.read_parquet('https://huggingface.co/datasets/Locutusque/function-calling-chatml/resolve/main/data/train-00000-of-00001-f0b56c6983b4a78f.parquet')
    1. 分割为训练集和评估集
df_train=df.sample(frac=0.95,random_state=200)
df_eval=df.drop(df_train.index)
    1. 将数据保存为jsonl格式
df_train.to_json("glaive_train.jsonl", orient="records", lines=True)
df_eval.to_json("glaive_eval.jsonl", orient="records", lines=True)
    1. 重新格式化数据集

如我们所见,该数据集不符合所需的函数调用格式,因此需要重新格式化。除其他事项外,"from"应重命名为"user",多余的"\n"字符应被删除。 对于这个数据集,你可以使用./utils/reformat_data_glaive.py

cd $HOME/mistral-finetune
python -m utils.reformat_data_glaive $HOME/data/glaive_train.jsonl
python -m utils.reformat_data_glaive $HOME/data/glaive_eval.jsonl

运行这个命令将确保大多数样本符合正确的格式。

注意:不可能编写适用于所有类型数据集的重新格式化脚本。 如果你有尚未遵循上述所需格式的数据集,你很可能需要 自己创建一个重新格式化脚本(mistral-chat或chat-gpt是你最好的朋友!)。

    1. 验证数据集

现在你可以通过在example/7B.yaml中将data.instruct_datadata.eval_instruct_data分别设置为 $HOME/data/glaive_train.jsonl$HOME/data/glaive_eval.jsonl来验证数据集。

重新格式化的数据集仍然有一些错误,可以通过--create_corrected来移除。为此,确保添加 --create_corrected,如下所示:

cd $HOME/mistral-finetune
python -m utils.validate_data --train_yaml example/7B.yaml --create_corrected

运行此命令将显示几个错误并保存两个新数据集 $HOME/data/glaive_train.jsonl.corrected$HOME/data/glaive_eval.jsonl.corrected。确保在 example/7B.yaml 中使用这两个数据集并再次运行该命令。现在数据集应该格式正确了!

开始训练

在按照数据集验证部分操作后,我们现在可以开始训练了。 为了加快训练速度,我们建议将 max_steps 设置为仅 300。确保将 run_dir 定义为您的实验文件夹,并可选择设置 wandb_project 为 Weights & Biases 项目以进行日志记录,例如:

max_steps: 300
run_dir: "/Users/johndoe/ultra_chat_test"
wandb.project: ultra_chat

您也可以选择设置 wandb

保存训练配置并开始训练!确保将 --nproc-per-node 设置为可用的 GPU 数量。

cd $HOME/mistral-finetune
torchrun --nproc-per-node 8 --master_port $RANDOM -m train example/7B.yaml

在 8 个 H100 节点上训练 ultra-chat 应该需要大约 30 分钟,结果权重应该能得到约 6.3 的 MT Bench 分数。

在 8 个 H100 节点上训练 glaive 应该需要大约 1 小时,结果权重应该能很好地用于函数调用。

自定义训练配置

示例 mistral-finetune/examples/7B 定义了合理的学习率、权重衰减等参数...但建议您根据使用情况自定义这些设置。

通常,训练配置应填写以下参数:

  • model_id_or_path 定义开始训练的模型。这可以是预训练模型的路径或本地模型目录。
  • run_dir 定义存储训练检查点和指标的目录。
  • seq_len 定义训练的序列长度。这是模型将处理的输入序列的最大长度。样本会被打包以达到 seq_len 长度,以获得最大的训练效率。
  • batch_size 定义每个 GPU 使用的训练样本数。注意:所有 GPU 上的总有效批量大小(以 token 为单位)等于 num_gpus x batch_size x seq_len
  • max_steps 定义最大训练步数。这是训练过程将运行的总迭代次数。可以根据您的具体训练情况进行调整。训练期间看到的总 token 数是 max_steps x num_gpus x batch_size x seq_len
  • optim.lr 定义学习率。这是优化器的初始学习率。
  • optim.weight_decay 定义权重衰减。权重衰减是一种正则化技术,通过惩罚大权重来防止过拟合。我们建议保持在 0.1。
  • optim.pct_start 定义用于学习率预热阶段的总训练步数百分比,然后开始降低。它对应于 PyTorch 的 OneCycleLR 中的 pct_start。
  • lora.rank 定义 LoRA(低秩适应)适配器的大小。我们建议 64 或更小,这调整了 LoRA 中使用的低秩分解的秩。
  • seed 定义初始化和数据洗牌/采样的随机种子。设置种子确保结果的可重复性。
  • log_freq 定义日志记录频率。这指定多少步记录一次训练指标。
  • data.instruct_data 是用于训练的指令数据的路径。此字段必须按上述格式填写一个或多个数据源。每个数据源应该是一个 jsonl 文件的路径,或者是包含 jsonl 文件的目录路径,后面跟着一个权重来定义该数据集的重要性:<path/to/data_source>:<weight>。例如:data.instruct_data: "/path/to/data1.jsonl:5.,/path/to/data2.jsonl:1.,/path/to/dir_of_jsonls:1."
  • data.data 是可选的额外预训练数据的路径,格式如上所述。注意,此字段可以留空。
  • data.eval_instruct_data 是可选的评估指令数据的路径,用于在每 eval_freq 步进行交叉验证。交叉验证指标显示为 lossperplexity
  • eval_freq 定义多少步评估一次模型。这指定在验证集上评估模型的间隔。
  • no_eval 是启用或禁用中间评估的标志。将其设置为 False 可在训练期间进行定期评估。
  • ckpt_freq 定义多少步保存一次检查点。这指定保存模型状态的间隔。
  • save_adapters 定义是只保存训练好的 LoRA 检查点,还是将训练好的 LoRA 直接合并到基础模型中并保存。注意:当设置 save_adapters=False 时,确保您有足够的 CPU 和 GPU 内存在单个进程上保存完整模型(这通常只适用于 7B 模型)。
  • wandb.key 用于传递您的 Weights & Biases (wandb) API 密钥以进行日志记录。这允许您将训练指标记录到 wandb 仪表板。
  • wandb.project 定义 wandb 项目名称。训练运行将在 wandb 界面中的此项目中记录。

推理

一旦您的模型训练完成,您应该尝试进行推理。我们推荐使用 mistral-inference

确保正确安装了 mistral_inference

pip install mistral_inference

假设您的 lora.safetensors 保存在 $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors 下,您可以使用 mistral_inference 与模型聊天,例如:

mistral-chat /mnt/slow/runs/patrick/mistral-finetune/7B/ --max_tokens 256 --temperature 1.0 --instruct --lora_path $HOME/ultra_chat_test/checkpoints/checkpoint_000300/consolidated/lora.safetensors

添加 Weights and Biases (wandb) 支持

我们已添加了对 Weights and Biases 的明确支持,以帮助您监控和可视化您的训练运行。这种集成允许您轻松记录各种指标并跟踪实验。

设置 Weights and Biases

要在 mistral-finetune 中使用 Weights and Biases,请按照以下步骤操作:

  1. 安装 Weights and Biases:

    确保您已安装 wandb 库。您可以使用 pip 安装:

   pip install wandb

查看您的日志

一旦训练开始,您可以通过访问您的 wandb 项目仪表板实时监控进度。所有指标,包括训练损失、评估损失、学习率等,都将被记录和可视化。

有关如何使用 wandb 的更多详细信息,请访问 Weights and Biases 文档

模型扩展

重要提示:请注意,只能微调与 v3 分词器兼容的 mistral 模型,这意味着模型的词汇表大小为 32768 - 而不是 32000。但是,可以使用以下方法轻松将词汇表大小为 32000 的旧版本扩展到 32768:

python -m utils.extend_model_vocab --original_model_ckpt /folder/to/old/model --extended_model_ckpt /folder/to/extended/model

扩展完成后,可以使用 /folder/to/extended/model 中新创建的模型检查点进行微调。

常见问题:

  • 微调 MoE 的最佳实践是什么?

我们在微调 MoE 模型时观察到更高程度的性能变异。用不同的种子微调 MoE 模型导致性能高度变异并不罕见。我们没有在密集模型中观察到如此高的变异。因此,我们建议在 MoE 模型上运行多个相同的微调过程实例,并选择表现最好的一个。

  • 我如何确定模型训练过程中使用的 token 数量?

您可以使用以下脚本来查找:https://github.com/mistralai/mistral-finetune/blob/main/utils/validate_data.py。这个脚本接受一个 .yaml 训练文件作为输入,并返回模型正在训练的 token 数量。

  • 如果遇到 CUDA 内存不足错误,我该怎么办?

一个可能的解决方案是减少每个 GPU 的批量大小。批量大小等于 seq_len x batch_size。尝试将 batch_size 设置为 1 并减少 seq_len。您可以在 .yaml 文件中定义 batch_sizeseq_len

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号