在Amazon SageMaker JumpStart上对Llama 2进行微调,用于文本生成
在Amazon SageMaker JumpStart上微调Llama 2,用于文本生成
今天,我们很高兴地宣布,通过使用Amazon SageMaker JumpStart,可以对Llama 2模型进行微调。 Llama 2系列的大型语言模型(LLM)是一系列经过预训练和微调的生成文本模型,其规模从70亿到700亿个参数不等。 经过微调的LLM,称为Llama-2-chat,是针对对话使用情况进行了优化的。 您可以轻松尝试这些模型,并使用SageMaker JumpStart与其一起使用,SageMaker JumpStart是一个机器学习(ML)中心,提供访问算法、模型和ML解决方案的功能,以便您可以快速开始使用ML。 现在,您还可以使用Amazon SageMaker Studio UI或使用SageMaker Python SDK在SageMaker JumpStart上对70亿、130亿和700亿参数的Llama 2文本生成模型进行微调。
生成式AI基础模型一直是大多数机器学习和人工智能研究和用例的重点已经有一年多了。 这些基础模型在生成任务(如文本生成、摘要、问答、图像和视频生成等)中表现非常好,因为它们的规模大,并且它们是在多个大型数据集和数百个任务上进行训练的。 尽管这些模型具有很强的泛化能力,但通常会出现一些具有非常特定领域数据(例如医疗保健或金融服务)的用例,因此这些模型可能无法为这些用例提供良好的结果。 这就需要进一步对这些生成式AI模型进行微调,以适应特定用例和领域特定的数据。
在本文中,我们将介绍如何通过SageMaker JumpStart对Llama 2预训练文本生成模型进行微调。
Llama 2是什么
Llama 2是一个使用优化的Transformer架构的自回归语言模型。 Llama 2适用于英语的商业和研究用途。 它有多个参数大小可供选择,包括70亿、130亿和700亿,并且有预训练和微调的变体。 根据Meta的说法,微调版本使用了有监督的微调(SFT)和强化学习与人类反馈(RLHF),以与人类偏好的帮助性和安全性保持一致。 Llama 2在公开可用的数据源上预训练了2万亿个标记的数据。 这些微调模型适用于类似助手的聊天,而预训练模型可以用于各种自然语言生成任务。 无论开发人员使用模型的哪个版本,Meta的负责任使用指南可以帮助引导额外的微调,以定制和优化模型并采取适当的安全措施。
目前,Llama 2在以下地区提供:
- 提供预训练模型的地区:
"us-west-2"
、"us-east-1"
、"us-east-2"
、"eu-west-1"
、"ap-southeast-1"
、"ap-southeast-2"
- 微调并部署微调模型的地区:
“us-east-1”
、“us-west-2”
、“eu-west-1”
SageMaker JumpStart是什么
通过SageMaker JumpStart,ML从业者可以从广泛的公开可用基础模型中进行选择。 ML从业者可以将基础模型部署到专用的Amazon SageMaker实例中,这些实例位于网络隔离环境中,并使用SageMaker自定义模型进行模型训练和部署。 您现在可以在SageMaker Studio中通过几次点击或通过SageMaker Python SDK以编程方式发现和部署Llama 2,从而能够使用SageMaker功能(如Amazon SageMaker Pipelines、Amazon SageMaker Debugger或容器日志)派生模型性能和MLOps控制。 模型在AWS安全环境中部署,并在您的VPC控制下,有助于确保数据安全。 此外,您还可以通过SageMaker JumpStart对Llama2的70亿、130亿和700亿预训练文本生成模型进行微调。
微调Llama2模型
您可以使用SageMaker Studio UI或SageMaker Python SDK对模型进行微调。我们在本节中介绍了这两种方法。
通过SageMaker Studio UI进行无代码微调
在SageMaker Studio中,您可以通过SageMaker JumpStart访问Llama 2模型,路径为Models, notebooks, and solutions,如下面的截图所示。
如果您找不到Llama 2模型,请关闭并重新启动SageMaker Studio以更新版本。有关版本更新的更多信息,请参阅关闭和更新Studio应用。
您还可以选择Explore all Text Generation Models或在搜索框中搜索llama来查找其他四个模型变体。
在此页面上,您可以指向包含用于微调的训练和验证数据集的Amazon Simple Storage Service(Amazon S3)存储桶。此外,您还可以配置微调的部署配置、超参数和安全设置。然后,您可以选择Train在SageMaker ML实例上启动训练作业。上述截图显示了Llama-2 7B模型的微调页面;但是,您可以使用它们各自的模型页面对13B和70B Llama 2文本生成模型进行微调。要使用Llama 2模型,您需要接受最终用户许可协议(EULA)。当您选择Train时,它将显示在下面的截图中。选择I have read and accept EULA and AUP以开始微调作业。
部署模型
模型微调完成后,您可以使用SageMaker JumpStart上的模型页面进行部署。在微调完成后,将出现部署微调模型的选项,如下面的截图所示。
使用SageMaker Python SDK进行微调
您还可以使用SageMaker Python SDK对Llama 2模型进行微调。以下是一个示例代码,用于对您的数据集进行Llama 2 7B的微调:
import os
import boto3
from sagemaker.session import Session
from sagemaker.jumpstart.estimator import JumpStartEstimator
# 要微调13B/70B模型,请将model_id更改为 `meta-textgeneration-llama-2-13b`/`meta-textgeneration-llama-2-70b`。
model_id = "meta-textgeneration-llama-2-7b"
estimator = JumpStartEstimator(
model_id=model_id, environment={"accept_eula": "true"}
)
# 默认情况下,指导调优设置为false。因此,要使用指导调优数据集,您可以使用
estimator.set_hyperparameters(instruction_tuned="True", epoch="5")
estimator.fit({"training": train_data_location})
您可以直接从估算器部署微调模型:
finetuned_predictor = estimator.deploy()
您还可以在SageMaker JumpStart上找到Fine-tune LLaMA 2模型的代码。其中包括数据集准备、在自定义数据集上训练以及部署微调模型。它演示了在Dolly数据集的子集上进行摘要任务的微调。以下是带有来自微调和非微调的响应以及地面真实响应的示例输入:
模型的输入:
下面是一个描述任务的说明,配以提供进一步上下文的输入。请写一个恰当地完成请求的回答。
### 说明:
Felix Luna是在什么时候去世的?
### 输入:
Félix César Luna(1925年9月30日 - 2009年11月5日)是一位阿根廷作家、歌词作者和历史学家。
### 回答:
真实回答:
Felix Luna于2009年11月5日去世。
未经微调的模型回答:
Félix César Luna(1925年9月30日 - 2009年11月5日)是一位阿根廷作家、歌词作者和历史学家。
Luna是在什么时候去世的?
### 解释:
我们使用输入的出生日期和死亡日期回答了这个问题。
### 解决方案:1102
经过微调的模型回答:
Félix Luna于2009年11月5日去世。
有关Dolly和Dialogsum数据集上不同模型的性能基准,请参阅本文后附录中的性能基准部分。
微调技术
Llama等语言模型的大小超过10GB,甚至达到100GB。对这些大模型进行微调需要具有显著高CUDA内存的实例。此外,训练这些模型可能非常缓慢,因为模型的大小。因此,为了有效地进行微调,我们采用以下优化方法:
- Low-Rank Adaptation(LoRA) – 这是一种用于高效微调大模型的参数高效微调(PEFT)类型。在此方法中,我们冻结整个模型,并只向模型中添加一小组可调参数或层。例如,对于Llama 2 7B,我们只需微调不到1%的参数,而不是训练全部70亿个参数。这有助于显著减少内存需求,因为我们只需要存储1%参数的梯度、优化器状态和其他与训练相关的信息。此外,这也有助于减少训练时间和成本。有关该方法的更多详细信息,请参阅LoRA:Large Language Models的低秩适应。
- Int8量化 – 即使进行了LoRA等优化,Llama 70B等模型仍然太大而无法进行训练。为了在训练过程中减少内存占用,我们可以在训练过程中使用Int8量化。量化通常会降低浮点数据类型的精度。尽管这会减少存储模型权重所需的内存,但由于信息的丢失,它会降低性能。Int8量化仅使用四分之一的精度,但不会降低性能,因为它不仅仅是舍弃位数,还会将数据从一种类型舍入到另一种类型。有关Int8量化的详细信息,请参阅LLM.int8():在规模上用于Transformer的8位矩阵乘法。
- Fully Sharded Data Parallel(FSDP) – 这是一种数据并行训练算法,将模型的参数分片到数据并行工作器上,并可以选择将部分训练计算卸载到CPU上。尽管参数在不同的GPU上进行了分片,但每个微批次的计算仍在GPU工作器上进行。它更均匀地分片参数,并通过训练期间的通信和计算重叠来实现优化性能。
下表比较了不同方法与三个Llama 2模型。
, | 默认实例类型 | 支持的默认配置实例类型 | 默认设置 | LORA + FSDP | LORA + 无FSDP | Int8量化 + LORA + 无FSDP |
Llama 2 7B | ml.g5.12xlarge | ml.g5.12xlarge, ml.g5.24xlarge, ml.g5.48xlarge | LORA + FSDP | 是 | 是 | 是 |
Llama 2 13B | ml.g5.12xlarge | ml.g5.24xlarge, ml.g5.48xlarge | LORA + FSDP | 是 | 是 | 是 |
Llama 2 70B | ml.g5.48xlarge | ml.g5.48xlarge | INT8 + LORA + 无FSDP | 否 | 否 | 是 |
请注意,Llama模型的微调是基于以下GitHub存储库提供的脚本。
训练数据集格式
SageMaker JumpStart目前支持领域适应格式和指令调整格式的数据集。在本节中,我们将指定两种格式的示例数据集。有关更多详细信息,请参阅附录中的数据集格式化部分。
领域适应格式
文本生成Llama 2模型可以在任何特定领域的数据集上进行微调。在对特定领域的数据集进行微调后,该模型被期望能够生成特定领域的文本,并通过有限的提示解决各种NLP任务。使用此数据集,输入包括CSV、JSON或TXT文件。例如,输入数据可以是亚马逊的SEC文件作为文本文件:
此报告包括估计、预测、与我们的业务计划、目标和预期运营结果有关的陈述,这些陈述是根据1995年私人证券诉讼改革法案、1933年证券法第27A条和1934年证券交易法第21E条的“前瞻性陈述”而制定的。前瞻性陈述可能出现在本报告的各个部分中,包括以下部分:“业务”(本10-K表第I部分第1项)、“风险因素”(本10-K表第I部分第1A项)和“管理讨论与分析财务状况及运营结果”(本10-K表第II部分第7项)。这些前瞻性陈述通常通过以下词语来识别:“相信”、“预测”、“期望”、“预计”、“估计”、“打算”、“战略”、“未来”、“机会”、“计划”、“可能”、“应该”、“将会”、“将继续”、“可能导致的结果”和类似表达方式。
指令调整格式
在指令微调中,模型根据使用指令描述的一组自然语言处理(NLP)任务进行微调。这有助于提高模型在未见任务的情况下使用零提示的性能。在指令调整数据集格式中,您需要指定描述输入和输出格式的template.json
文件。例如,文件train.jsonl
中的每一行如下所示:
{"instruction": "什么是色散棱镜?",
"context": "在光学中,色散棱镜是一种用于分散光线的光学棱镜,即将光线分离为其光谱组成部分(即彩虹的颜色)。不同波长(颜色)的光线将以不同的角度被棱镜偏折。这是由于棱镜材料的折射率随波长(色散)而变化所致。通常,较长的波长(红色)比较短的波长(蓝色)发生较小的偏转。棱镜将白光分散成彩色,这使得艾萨克·牛顿爵士得出结论,白光由不同颜色的混合物组成。",
"response": "色散棱镜是一种光学棱镜,它将光的不同波长以不同的角度分散。当白光通过一个色散棱镜时,它会分离成彩虹的不同颜色。"}
附加文件template.json
的内容如下:
{
"prompt": "以下是描述任务的指令,与提供进一步上下文的输入配对。"
"编写一个适当完成请求的响应。\n\n"
"### 指令:\n{instruction}\n\n### 输入:\n{context}\n\n",
"completion": " {response}",
}
支持的训练超参数
Llama 2微调支持多个超参数,每个超参数都会影响微调模型的内存需求、训练速度和性能:
- epoch – 微调算法在训练数据集上进行的次数。必须是大于1的整数。默认值为5。
- learning_rate – 在处理每批训练样例后,模型权重更新的速率。必须是大于0的正浮点数。默认值为1e-4。
- instruction_tuned – 是否对模型进行指令训练。必须是‘
True
’或‘False
’。默认值为‘False
’。 - per_device_train_batch_size – 每个GPU核心/CPU的训练批量大小。必须是正整数。默认值为4。
- per_device_eval_batch_size – 每个GPU核心/CPU的评估批量大小。必须是正整数。默认值为1。
- max_train_samples – 用于调试或更快的训练,将训练样例的数量截断为此值。值-1表示使用所有训练样本。必须是正整数或-1。默认值为-1。
- max_val_samples – 用于调试或更快的训练,将验证样例的数量截断为此值。值-1表示使用所有验证样本。必须是正整数或-1。默认值为-1。
- max_input_length – 标记化后的最大输入序列长度。长度超过此值的序列将被截断。如果为-1,则
max_input_length
设置为1024和令牌化器定义的最大模型长度之间的较小值。如果设置为正值,则max_input_length
设置为提供的值和令牌化器定义的model_max_length
之间的较小值。必须是正整数或-1。默认值为-1。 - validation_split_ratio – 如果验证通道为
none
,则从训练数据中划分训练验证比例必须在0-1之间。默认值为0.2。 - train_data_split_seed – 如果没有验证数据,此参数用于随机将输入训练数据拆分为训练和验证数据。必须是整数。默认值为0。
- preprocessing_num_workers – 用于预处理的进程数。如果为
None
,则主进程用于预处理。默认值为None
。 - lora_r – Lora R。必须是正整数。默认值为8。
- lora_alpha – Lora Alpha。必须是正整数。默认值为32
- lora_dropout – Lora Dropout。必须是介于0和1之间的正浮点数。默认值为0.05。
- int8_quantization – 如果为
True
,则模型以8位精度加载进行训练。7B和13B的默认值为False
。70B的默认值为True
。 - enable_fsdp – 如果为
True
,则训练使用FSDP。7B和13B的默认值为True
。70B的默认值为False
。请注意,FSDP不支持int8_quantization
。
实例类型和兼容超参数
微调过程中的内存需求可能会根据以下几个因素而变化:
- 模型类型 – 7B模型的GPU内存需求最小,而70B模型的内存需求最大
- 最大输入长度 – 输入长度较大会导致一次处理更多的标记,因此需要更多的CUDA内存
- 批量大小 – 较大的批量大小需要更大的CUDA内存,因此需要更大的实例类型
- Int8量化 – 如果使用Int8量化,模型将以低精度加载,因此需要较少的CUDA内存
为了帮助您入门,我们提供了一组不同实例类型、超参数和模型类型的组合,可以成功进行微调。您可以根据您的要求和实例类型的可用性选择配置。我们在Dolly数据集的子集上使用三个时期对所有三个模型进行了各种设置的微调,其中包括摘要示例。
7B模型
以下表格总结了对7B模型进行微调的选项。
实例类型 | 最大输入长度 | 每设备批量大小 | Int8量化 | 启用FSDP | 花费时间(分钟) |
ml.g4dn.12xlarge | 1024 | 8 | TRUE | FALSE | 166 |
ml.g4dn.12xlarge | 2048 | 2 | TRUE | FALSE | 178 |
ml.g4dn.12xlarge | 1024 | 4 | FALSE | TRUE | 120 |
ml.g4dn.12xlarge | 2048 | 2 | FALSE | TRUE | 143 |
ml.g5.2xlarge | 1024 | 4 | TRUE | FALSE | 61 |
ml.g5.2xlarge | 2048 | 2 | TRUE | FALSE | 68 |
ml.g5.2xlarge | 1024 | 4 | FALSE | TRUE | 43 |
ml.g5.2xlarge | 2048 | 2 | FALSE | TRUE | 49 |
ml.g5.4xlarge | 1024 | 4 | FALSE | TRUE | 39 |
ml.g5.4xlarge | 2048 | 2 | FALSE | TRUE | 50 |
ml.g5.12xlarge | 1024 | 16 | TRUE | FALSE | 57 |
ml.g5.12xlarge | 2048 | 4 | TRUE | FALSE | 64 |
ml.g5.12xlarge | 1024 | 4 | FALSE | TRUE | 26 |
ml.g5.12xlarge | 2048 | 4 | FALSE | TRUE | 23 |
ml.g5.48xlarge | 1024 | 16 | TRUE | FALSE | 59 |
ml.g5.48xlarge | 2048 | 4 | TRUE | FALSE | 67 |
ml.g5.48xlarge | 1024 | 8 | FALSE | TRUE | 22 |
ml.g5.48xlarge | 2048 | 4 | FALSE | TRUE | 21 |
13B
下表总结了13B模型的微调选项。
实例类型 | 最大输入长度 | 每个设备批处理大小 | Int8量化 | 启用FSDP | 耗时(分钟) |
ml.g4dn.12xlarge | 1024 | 4 | 是 | 否 | 283 |
ml.g4dn.12xlarge | 2048 | 2 | 是 | 否 | 328 |
ml.g5.12xlarge | 1024 | 8 | 是 | 否 | 92 |
ml.g5.12xlarge | 2048 | 4 | 是 | 否 | 104 |
ml.g5.48xlarge | 1024 | 8 | 是 | 否 | 95 |
ml.g5.48xlarge | 2048 | 4 | 是 | 否 | 107 |
ml.g5.48xlarge | 1024 | 8 | 否 | 是 | 35 |
ml.g5.48xlarge | 2048 | 2 | 否 | 是 | 41 |
70B
下表总结了70B模型的微调选项。
实例类型 | 最大输入长度 | 每个设备批处理大小 | Int8量化 | 启用FSDP | 耗时(分钟) |
ml.g5.48xlarge | 1024 | 4 | 是 | 否 | 396 |
ml.g5.48xlarge | 2048 | 1 | 是 | 否 | 454 |
实例类型和超参数的建议
在调整模型的准确性时,请记住以下事项:
- 较大的模型(如70B)比7B提供更好的性能
- 没有Int8量化的性能优于有Int8量化的性能
请注意以下训练时间和CUDA内存需求:
- 设置
int8_quantization=True
会减少内存需求并加快训练速度。 - 减小
per_device_train_batch_size
和max_input_length
会减少内存需求,因此可以在较小的实例上运行。然而,设置过低的值可能会增加训练时间。 - 如果不使用Int8量化(
int8_quantization=False
),请使用FSDP(enable_fsdp=True
)进行更快和更高效的训练。
在选择实例类型时,请考虑以下因素:
- G5实例在支持的实例类型中提供最高效的训练。因此,如果您有可用的G5实例,应该使用它们。
- 训练时间在很大程度上取决于GPU数量和CUDA内存的数量。因此,使用相同数量的GPU进行训练(例如,ml.g5.2xlarge和ml.g5.4xlarge)大致相同。因此,您可以使用更便宜的实例进行训练(ml.g5.2xlarge)。
- 使用p3实例进行训练时,将使用32位精度进行训练,因为这些实例不支持bfloat16。因此,与在g5实例上进行训练相比,p3实例上的训练作业将消耗双倍的CUDA内存。
要了解每个实例的训练成本,请参阅Amazon EC2 G5实例。
如果数据集采用指令调优格式,输入+完成序列很小(例如50-100个单词),则max_input_length
的较大值会导致性能非常差。该参数的默认值为-1,对应于Llama模型的max_input_length
为2048。因此,我们建议如果您的数据集包含小样本,请使用较小的max_input_length
值(例如200-400)。
最后,由于G5实例的高需求,您可能在您的地区无法使用这些实例,并显示错误消息“CapacityError: Unable to provision requested ML compute capacity. Please retry using a different ML instance type.”
如果遇到此错误,请重试训练作业或尝试使用其他地区。
微调非常大模型时的问题
在本节中,我们讨论微调非常大模型时遇到的两个问题。
禁用输出压缩
默认情况下,训练作业的输出是一个在上传到Amazon S3之前以.tar.gz格式压缩的训练模型。然而,由于模型的大小,这一步可能需要很长时间。例如,压缩和上传70B模型可能需要超过4个小时。为了避免这个问题,您可以在SageMaker训练平台上使用禁用输出压缩功能。在这种情况下,模型将以无压缩的方式上传,进一步用于部署:
estimator = JumpStartEstimator(
model_id=model_id, environment={"accept_eula": "true"}, disable_output_compression=True
)
SageMaker Studio内核超时问题
由于Llama 70B模型的大小,训练作业可能需要几个小时,而SageMaker Studio内核可能在训练阶段中断。然而,在此期间,训练仍在SageMaker中运行。如果出现这种情况,您仍然可以使用训练作业名称部署端点,使用以下代码:
from sagemaker.jumpstart.estimator import JumpStartEstimator
training_job_name = <<<INSERT_TRAINING_JOB_NAME>>>
attached_estimator = JumpStartEstimator.attach(training_job_name, model_id)
attached_estimator.logs()
attached_estimator.deploy()
要找到训练作业名称,请导航到SageMaker控制台,在导航窗格中选择训练,然后选择训练作业。识别训练作业名称并将其替换到上述代码中。
结论
在本篇文章中,我们讨论了使用SageMaker JumpStart来微调Meta的Llama 2模型。我们展示了您可以使用SageMaker Studio中的SageMaker JumpStart控制台或SageMaker Python SDK来进行模型的微调和部署。我们还讨论了微调技术、实例类型和支持的超参数。此外,我们根据我们进行的各种测试,提出了优化训练的建议。微调三个模型在两个数据集上的结果显示在本文末尾的附录中。从这些结果中我们可以看出,与未经微调的模型相比,微调能够改善摘要生成的效果。作为下一步,您可以尝试使用GitHub存储库中提供的代码,在您自己的数据集上对这些模型进行微调,以测试和评估适用于您的用例的结果。
作者们要感谢Christopher Whitten、Xin Huang、Kyle Ulrich、Sifei Li、Amy You、Adam Kozdrowicz、Evan Kravitz、Benjamin Crabtree、Haotian An、Manan Shah、Tony Cruz、Ernev Sharma、Jonathan Guinegagne和June Won的技术贡献。