Press "Enter" to skip to content

使用 QLoRA 对 Llama 2 进行微调,并在 Amazon SageMaker 上部署,配备 AWS Inferentia2

在本篇文章中,我们展示了使用参数高效微调(PEFT)方法对Llama 2模型进行微调,并在AWS Inferentia2上部署微调后的模型。我们使用AWS Neuron软件开发工具包(SDK)来访问AWS Inferentia2设备,并从其高性能中获益。然后,我们使用由Deep Java Library(DJLServing)提供支持的大型模型推断容器作为我们的模型服务解决方案。

解决方案概述

使用QLoRa高效微调Llama2

Llama 2系列大型语言模型(LLM)是一系列经过预训练和微调的生成文本模型,规模从70亿到700亿个参数不等。Llama 2是在来自公开可用来源的2万亿个令牌的数据上进行预训练的。AWS客户有时选择使用自己的数据对Llama 2模型进行微调,以获得更好的下游任务性能。然而,由于Llama 2模型具有大量参数,完全微调可能成本高昂且时间耗费巨大。参数高效微调(PEFT)方法可以通过仅微调少量额外的模型参数,并冻结预训练模型的大部分参数来解决这个问题。有关PEFT的更多信息,可以阅读这篇文章。在本文中,我们使用QLoRa对Llama 2 7B模型进行微调。

使用Amazon SageMaker在Inf2上部署微调模型

AWS Inferentia2是专为推断工作负载而设计的机器学习(ML)加速器,通过AWS上其他推断优化实例相比,为生成AI和LLM工作负载提供高性能的同时降低了高达40%的成本。在本文中,我们使用Amazon Elastic Compute Cloud(Amazon EC2)Inf2实例,该实例采用了AWS Inferentia2第二代加速器,每个加速器包含两个NeuronCores-v2。每个NeuronCore-v2是一个独立的异构计算单元,具有四个主要引擎:张量引擎、向量引擎、标量引擎和GPSIMD引擎。它还包括一个芯片上的软件管理SRAM内存,以最大程度地提高数据局部性。由于已经发布了关于Inf2的几篇博客,读者可以参考这篇文章和我们的文档来了解更多Inf2的信息。

要在Inf2上部署模型,我们需要AWS Neuron SDK作为运行在Inf2硬件之上的软件层。AWS Neuron是用于在AWS Inferentia和AWS Trainium基于实例上运行深度学习工作负载的SDK。它支持端到端的ML开发生命周期,包括构建新模型、训练和优化这些模型,并将它们部署到生产环境中。AWS Neuron包括一个深度学习编译器运行时工具,与TensorFlow和PyTorch等流行框架进行了本地集成。在本博客中,我们将使用transformers-neuronx,它是AWS Neuron SDK用于转换器解码器推断工作流的一部分。它支持一系列流行的模型,包括Llama 2。

通常我们使用一个包含所需库(如Neuron SDK和transformers-neuronx)以及模型服务组件的容器来在Amazon SageMaker上部署模型。Amazon SageMaker维护着需要使用流行的开源库来托管大型模型的深度学习容器(DLCs)。在本文中,我们使用Neuron的大型模型推断容器。这个容器中包含了在Inf2上部署Llama 2模型所需的一切。关于在Amazon SageMaker上开始使用LMI的资源,请参考我们关于这个主题的许多现有文章(博客 1博客 2博客 3)。简而言之,您可以在不编写任何额外代码的情况下运行该容器。您可以使用默认处理程序实现无缝用户体验,并传入支持的模型名称和任何加载时可配置的参数之一。这将在Inf2实例上编译和提供LLM。例如,要部署OpenAssistant/llama2-13b-orca-8k-3319,您可以提供以下配置(作为serving.properties文件)。在serving.properties中,我们指定了模型类型为llama2-13b-orca-8k-3319,批处理大小为4,张量并行度为2,就是这样。有关可配置参数的完整列表,请参阅所有DJL配置选项

# 要使用的引擎:MXNet、PyTorch、TensorFlow、ONNX、PaddlePaddle、DeepSpeed等。engine = Python # 用于模型服务的默认处理程序option.entryPoint = djl_python.transformers_neuronx# 模型的Hugging Face ID或模型工件的s3 URL。option.model_id = meta-llama/Llama-2-7b-chat-hf# 动态批处理大小,默认为1。option.batch_size=4# 此选项指定模型上执行的张量并行分区数。option.tensor_parallel_degree=2# 输入序列长度option.n_positions=512# 使用“auto”、“scheduler”、“lmi-dist”之一启用迭代级批处理option.rolling_batch=auto# 您计划将模型转换为的数据类型 默认是option.dtype=fp16# worker加载模型超时option.model_loading_timeout=1500

或者,您可以自己编写模型处理程序文件,如本示例所示,但这需要实现模型加载和推断方法,作为DJLServing API之间的桥梁。

先决条件

以下列表概述了部署本博客文章中描述的模型所需的先决条件。您可以从AWS管理控制台或使用最新版本的AWS命令行界面(AWS CLI)进行实施。

演练

在接下来的部分,我们将分两部分讲解代码:

  1. 对Llama2-7b模型进行微调,并将模型组件上传到指定的Amazon S3存储桶位置。
  2. 将模型部署到使用Amazon SageMaker中托管的DJL serving容器中的Inferentia2。

完整的代码示例和说明可以在这个GitHub存储库中找到。

第1部分:使用PEFT对Llama2-7b模型进行微调

我们将使用Tim Dettmers等人在论文QLoRA: Quantization-aware Low-Rank Adapter Tuning for Language Generation中介绍的最新方法。QLoRA是一种在微调期间减少大型语言模型内存占用的新技术,而不降低性能。

注意:以下所示的llama2-7b模型的微调是在使用Python 2.0 GPU Optimized Kernel的ml.g5.2xlarge实例类型的Amazon SageMaker Studio Notebook上进行测试的。作为最佳实践,我们建议在您自己的Amazon Virtual Private Cloud(Amazon VPC)中启动的Amazon SageMaker Studio集成开发环境(IDE)中使用。这样可以使用标准的AWS网络和安全功能,控制、监控和检查VPC内部和外部的网络流量。有关更多信息,请参见使用私有VPC保护Amazon SageMaker Studio连接

将基础模型量化

我们首先使用Huggingface transformers库加载一个带有4位量化的量化模型,代码如下:

# 用于微调的基础预训练模型
model_name = "NousResearch/Llama-2-7b-chat-hf"
# 用于训练的数据集
dataset_name = "mlabonne/guanaco-llama2-1k"
# 激活4位精度的基础模型加载
use_4bit = True
bnb_4bit_compute_dtype = "float16"
bnb_4bit_quant_type = "nf4"
use_nested_quant = False
compute_dtype = getattr(torch, bnb_4bit_compute_dtype)
bnb_config = BitsAndBytesConfig(
    load_in_4bit=use_4bit,
    bnb_4bit_quant_type=bnb_4bit_quant_type,
    bnb_4bit_compute_dtype=compute_dtype,
    bnb_4bit_use_double_quant=use_nested_quant,
)
# 加载基础模型和分词器
model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=bnb_config, device_map=device_map)
model.config.pretraining_tp = 1
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

加载训练数据集

接下来,我们加载数据集以供模型进行微调步骤,代码如下:

# 加载数据集(您可以在此处进行处理)
dataset = load_dataset(dataset_name, split="train")

添加一个适配器层

在这里,我们添加一个小型可训练的适配器层,配置为在Hugging Face的peft库中定义的LoraConfig。

# 包含线性层以将LoRA应用到模型
modules = find_all_linear_names(model)
## 设置LoRA配置
lora_r = 64 # LoRA缩放的Alpha参数
lora_alpha = 16 # LoRA层的Dropout概率
lora_dropout = 0.1
peft_config = LoraConfig(
    lora_alpha=lora_alpha,
    lora_dropout=lora_dropout,
    r=lora_r,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=modules
)

训练模型

使用上面展示的LoRA配置,我们将对Llama2模型进行微调,并调整超参数。下面是训练模型的代码片段:

# 设置训练参数training_arguments = TrainingArguments(...)trainer = SFTTrainer(model=model,train_dataset=dataset,peft_config=peft_config, # LoRA configdataset_text_field="text",max_seq_length=max_seq_length,tokenizer=tokenizer,args=training_arguments,packing=packing,)# 训练模型trainer.train()# 保存训练后的模型trainer.model.save_pretrained(new_model)

合并模型权重

上述执行的微调模型创建了一个包含训练后的LoRA适配器权重的新模型。在下面的代码片段中,我们将合并适配器和基础模型,以便可以使用微调后的模型进行推理。

# 重新加载FP16模型并与LoRA权重合并base_model = AutoModelForCausalLM.from_pretrained(model_name,low_cpu_mem_usage=True,return_dict=True,torch_dtype=torch.float16,device_map=device_map,)model = PeftModel.from_pretrained(base_model, new_model)model = model.merge_and_unload()save_dir = "merged_model"model.save_pretrained(save_dir, safe_serialization=True, max_shard_size="2GB")# 重新加载分词器并保存tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)tokenizer.pad_token = tokenizer.eos_tokentokenizer.padding_side = "right"tokenizer.save_pretrained(save_dir)

将模型权重上传至Amazon S3

在第一部分的最后一步,我们将合并后的模型权重保存到指定的Amazon S3位置。模型权重将由Amazon SageMaker中的模型服务容器使用,在Inferentia2实例上托管模型。

model_data_s3_location = "s3://<bucket_name>/<prefix>/"!cd {save_dir} && aws s3 cp —recursive . {model_data_s3_location}

第2部分:使用SageMaker LMI容器在AWS Inf2上托管QLoRA模型进行推理

在本节中,我们将演示如何将QLoRA微调后的模型部署到Amazon SageMaker托管环境中。我们将使用SageMaker的DJL serving容器,该容器与transformers-neuronx库集成,以托管此模型。这样设置可以方便地将模型加载到AWS Inferentia2加速器上,将模型并行化处理在多个NeuronCores上,并通过HTTP端点提供服务。

准备模型构件

DJL支持许多深度学习优化库,包括DeepSpeedFasterTransformer等。对于特定模型的配置,我们提供了一个包含关键参数的serving.properties文件,例如tensor_parallel_degreemodel_id,用于定义模型加载选项。其中,model_id可以是Hugging Face模型ID,也可以是存储模型权重的Amazon S3路径。在我们的示例中,我们提供了微调后模型的Amazon S3位置。以下代码片段显示了用于模型服务的属性:

%%writefile serving.propertiesengine=Pythonoption.entryPoint=djl_python.transformers_neuronxoption.model_id=<model data s3 location>option.batch_size=4option.neuron_optimize_level=2option.tensor_parallel_degree=8option.n_positions=512option.rolling_batch=autooption.dtype=fp16option.model_loading_timeout=1500

有关通过serving.properties进行配置的更多信息,请参阅文档。请注意,本博客中我们使用option.n_position=512以加快AWS Neuron编译速度。如果要尝试更大的输入标记长度,我们建议读者提前编译模型(参见在EC2上AOT预编译模型)。否则,如果编译时间过长,可能会遇到超时错误。

在定义serving.properties文件之后,我们将将文件打包成tar.gz格式,如下所示:

%%shmkdir mymodelmv serving.properties mymodel/tar czvf mymodel.tar.gz mymodel/rm -rf mymodel

然后,我们将tar.gz上传到Amazon S3存储桶位置:

s3_code_prefix = "large-model-lmi/code"bucket = sess.default_bucket()  # 存储artifacts的存储桶code_artifact = sess.upload_data("mymodel.tar.gz", bucket, s3_code_prefix)print(f"S3 Code or Model tar ball uploaded to --- > {code_artifact}")

创建Amazon SageMaker模型端点

要使用Inf2实例进行serving,我们使用带有DJL neuronX支持的Amazon SageMaker LMI容器。有关使用DJL NeuronX容器进行推理的更多信息,请参阅此文章。以下代码展示了如何使用Amazon SageMaker Python SDK部署模型:

# 获取DJL-neuronx docker映像 URIimage_uri = image_uris.retrieve(framework="djl-neuronx",region=sess.boto_session.region_name,version="0.24.0")# 定义Inf2实例类型以用于servinginstance_type = "ml.inf2.48xlarge"endpoint_name = sagemaker.utils.name_from_base("lmi-model")# 部署推理模型model.deploy(initial_instance_count=1,instance_type=instance_type,container_startup_health_check_timeout=1500,volume_size=256,endpoint_name=endpoint_name)# 我们的请求和响应将以json格式,因此我们指定序列化器和反序列化器predictor = sagemaker.Predictor(endpoint_name=endpoint_name,sagemaker_session=sess,serializer=serializers.JSONSerializer(),)

测试模型端点

成功部署模型后,我们可以通过向predictor发送示例请求来验证端点:

prompt="机器学习是什么?"input_data = f"<s>[INST] <<SYS>>\n作为一名数据科学家\n<</SYS>>\n{prompt} [/INST]"response = predictor.predict({"inputs": input_data, "parameters": {"max_new_tokens":300, "do_sample":"True"}})print(json.loads(response)['generated_text'])

示例输出如下所示:

在数据分析的背景下,机器学习(Machine Learning,ML)是一种统计技术,能够从具有不断增加的复杂性和准确性的数据集中提取预测能力,通过迭代缩小统计的范围。

机器学习不是一种新的统计技术,而是现有技术的组合。此外,它并没有被设计用于特定的数据集或产生特定的结果。相反,它被设计得足够灵活,可以适应任何数据集,并对任何结果进行预测。

清理

如果您决定不再保留SageMaker端点运行,可以使用AWS SDK for Python (boto3),AWS CLI或Amazon SageMaker控制台进行删除。此外,您还可以关闭不再需要的Amazon SageMaker Studio资源

结论

在本文中,我们向您展示了如何使用LoRA适配器对Llama2-7b模型进行微调,并利用单个GPU实例将模型部署到托管在Amazon SageMaker中的Inf2实例上,使用DJL serving容器。最后,我们使用SageMaker Python SDK验证了Amazon SageMaker模型端点的文本生成预测。请试一试,并期待您的反馈。敬请关注AWS Inferentia的更多功能和新创新。

有关AWS Neuron的更多示例,请参阅 aws-neuron-samples

Leave a Reply

Your email address will not be published. Required fields are marked *