跳到主要内容

LoRA & QLoRA

github地址 :https://github.com/ml-explore/mlx-examples/tree/main/llms

mlx-lm 包

您可以使用mlx-lm包来使用低秩适应(LoRA)对大型语言模型(LLM)进行微调以适应目标任务。示例还支持量化LoRA(QLoRA)。LoRA微调适用于以下模型系列:

  • Mistral
  • Llama
  • Phi2
  • Mixtral
  • Qwen2
  • Gemma
  • OLMo
  • MiniCPM
  • InternLM2

内容

  • 运行
    • 微调
    • 评估
    • 生成
  • 融合
  • 数据
  • 内存问题

运行

这里需要访问 HuggingFace 下载,可以使用国内镜像 https://hf-mirror.com/

export HF_ENDPOINT=https://hf-mirror.com

主要命令是mlx_lm.lora。要查看所有命令行选项的完整列表,请运行:

mlx_lm.lora --help

注意,在下面的示例中,--model参数可以是任何兼容的Hugging Face存储库或指向转换后的模型的本地路径。

您也可以使用-c/--config指定YAML配置文件。有关格式的更多信息,请参见示例YAML。例如:

mlx_lm.lora --config /path/to/config.yaml

如果同时使用命令行标志,它们将覆盖配置文件中的相应值。

微调

要微调模型,请使用:

mlx_lm.lora \
--model \
--train \
--data \
--iters 600

--data参数必须指定train.jsonl的路径,在--train时使用,以及在--test时指定test.jsonl的路径。有关数据格式的更多细节,请参见数据部分。

例如,要微调Mistral 7B,您可以使用--model mistralai/Mistral-7B-v0.1

如果--model指向的是一个量化模型,那么训练将使用QLoRA,否则将使用常规LoRA。

默认情况下,适配器配置和权重存储在adapters/目录下。您可以使用--adapter-path指定输出位置。

您可以使用--resume-adapter-file恢复现有适配器的微调。

评估

要计算测试集的困惑度,请使用:

mlx_lm.lora \
--model \
--adapter-path \
--data \
--test

生成

对于生成,请使用mlx_lm.generate

mlx_lm.generate \
--model \
--adapter-path \
--prompt ""

融合

您可以使用mlx_lm.fuse命令生成与低秩适配器融合的模型。此命令还允许您选择性地:

  • 将融合的模型上传到Hugging Face Hub。
  • 将融合的模型导出为GGUF格式。注意,GGUF支持限于fp16精度的Mistral、Mixtral和Llama风格的模型。

要查看支持的选项,请运行:

mlx_lm.fuse --help

要生成融合模型,请运行:

mlx_lm.fuse --model 

默认情况下,此命令将从adapters/加载适配器,并在lora_fused_model/路径下保存融合的模型。所有这些都是可配置的。

要上传融合模型,请向mlx_lm.fuse提供--upload-repo--hf-path参数。后者是原始模型的存储库名称,这对归因和模型版本控制很有用。

例如,要融合并上传一个衍生自Mistral-7B-v0.1的模型,请运行:

mlx_lm.fuse \
--model mistralai/Mistral-7B-v0.1 \
--upload-repo mlx-community/my-lora-mistral-7b \
--hf-path mistralai/Mistral-7B-v0.1

要将融合模型导出到GGUF,请运行:

mlx_lm.fuse \
--model mistralai/Mistral-7B-v0.1 \
--export-gguf

这将在lora_fused_model/ggml-model-f16.gguf中保存GGUF模型。您可以使用--gguf-path指定文件名。

数据

LoRA命令期望您使用--data提供数据集。MLX Examples GitHub存储库有一个WikiSQL数据的示例,格式正确。

数据集可以本地指定为*.jsonl文件,或从Hugging Face加载。

本地数据集

对于微调(--train),数据加载器期望在数据目录中有一个train.jsonl和一个valid.jsonl。对于评估(--test),数据加载器期望在数据目录中有一个test.jsonl

目前,*.jsonl文件支持三种数据格式:chatcompletionstext。以下是这些格式的三个示例:

chat

{
"messages": [
{
"role": "system",
"content": "你是一个有用的助手。"
},
{
"role": "user",
"content": "您好。"
},
{
"role": "assistant",
"content": "我今天能为您提供什么帮助?"
}
]
}

completions

{
"prompt": "法国的首都是哪里?",
"completion": "巴黎。"
}

text

{
"text": "这是模型的一个示例。"
}

请注意,数据集自动确定格式。同样请注意,每行中不被加载器预期的键将被忽略。

Hugging Face数据集

要使用Hugging Face数据集,首先安装datasets包:

pip install datasets

在YAML配置中指定Hugging Face数据集参数。例如:

hf_dataset:
name: "billsum"
prompt_feature: "text"
completion_feature: "summary"
  • 使用prompt_featurecompletion_feature指定completions数据集的键。使用text_feature指定text数据集的键。

  • 要指定训练、验证或测试拆分,请设置相应的{train,valid,test}_split参数。

  • config中指定的参数将作为关键字参数传递给datasets.load_dataset

通常,对于chatcompletions格式,Hugging Face 聊天模板被使用。这默认情况下应用了模型的聊天模板。如果模型没有聊天模板,那么Hugging Face将使用默认模板。例如,使用Hugging Face的默认模板,上面chat示例中的最终文本变为:

<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
Hello.<|im_end|>
<|im_start|>assistant
How can I assistant you today.<|im_end|>

如果您不确定要使用哪种格式,请从chatcompletions开始。对于数据集格式的自定义要求,请使用text格式自行组装内容。

内存问题

使用LoRA微调大型模型需要一台具有相当数量内存的机器。如果您需要减少内存使用,请尝试以下技巧:

  1. 尝试量化(QLoRA)。您可以通过使用convert.py-q标志生成量化模型来使用QLoRA。有关更多详细信息,请参见设置部分。

  2. 尝试使用--batch-size使用较小的批量大小。默认值为4,因此将其设置为21将减少内存消耗。这可能会稍微减慢速度,但也将减少内存使用。

  3. 使用--lora-layers减少微调的层数。默认值为16,所以您可以尝试84。这减少了反向传播所需的内存量。如果您使用大量数据微调,这也可能降低微调模型的质量。

  4. 更长的例子需要更多的内存。如果您的数据有意义,您可以做的事情之一是在制作{train, valid, test}.jsonl文件时将示例拆分成更小的序列。

  5. 梯度检查点可以让内存使用量减少(更少)以换取更多的计算(更多)通过重新计算而不是存储由反向传播所需的中间值。您可以通过传递--grad-checkpoint标志来使用梯度检查点。对于较大的批量大小或序列长度,梯度检查点对于较小或量化模型更有帮助。

例如,在32 GB的机器上,以下命令应该运行得相当快:

mlx_lm.lora \
--model mistralai/Mistral-7B-v0.1 \
--train \
--batch-size 1 \
--lora-layers 4 \
--data wikisql

上述命令在32 GB M1 Max上运行,大约每秒钟处理250个token,使用MLX示例wikisql数据集。