大模型实战:使用 LoRA(低阶适应)微调 LLM

为什么需要LLM

LLM 是一种基础模型,与传统模型不同,在早期模型中基础模型是在大量数据上进行预训练的,然后我们可以直接将它们用于某些任务用例,也可以对其进行微调以适应某些用例。在传统的机器学习模型中,我们必须从头开始为每种情况训练不同的模型,这是昂贵且耗时的。

在这里插入图片描述

预训练的大型语言模型通常被称为基础模型,它们在各种任务上表现良好,我们可以将它们用作目标任务微调的基础。大型语言模型 (LLM) 在客户服务、营销、法律、金融、医疗保健、教育等领域有着广泛的应用,而微调使我们能够使模型适应目标领域和目标任务,这就是 LLM 的微调之处。

低阶自适应参数高效微调 (LoRA) 简介

一些微调的最佳实践包括使用强正则化、使用较小的学习率和少量的epochs。一般来说,像卷积神经网络用于图像分类的神经网络并不完全微调,这样做很昂贵,可能导致灾难性遗忘。我们只微调最后一层或最后几层。

对于LLM,我们使用一种类似的方法,称为参数高效微调(PEFT)。其中一种流行的PEFT方法是低秩适应(LoRA),LoRA 是低秩适应 (Low-Rank Adaptation) 的缩写,其是一种用于微调深度学习模型的新技术,它在模型中添加了少量可训练参数模型,而原始模型参数保持冻结。LoRA 是用于训练定制 LLM 的最广泛使用、参数高效的微调技术之一。

LoRA 可以将可训练参数数量减少 10,000 倍,GPU 内存需求减少 3 倍。尽管可训练参数更少、训练吞吐量更高且无需额外推理,LoRA 在 RoBERTa、DeBERTa、GPT-2 和 GPT-3 上的模型质量表现与微调相当或更好延迟。

LoRA 将权重矩阵分解为两个较小的权重矩阵,如下所示,以更参数有效的方式近似完全监督微调。

在这里插入图片描述

LoRA是怎么去微调适配下游任务的

流程很简单,LoRA利用对应下游任务的数据,只通过训练新加部分参数来适配下游任务。而当训练好新的参数后,利用重参的方式,将新参数和老的模型参数合并,这样既能在新任务上到达fine-tune整个模型的效果,又不会在推断的时候增加推断的耗时。

在这里插入图片描述

在这里插入图片描述

具体思路是,与微调预训练的大型语言模型的权重矩阵(W)中的所有权重相比,微调两个较小的矩阵(A和B),这两个矩阵近似于对原始矩阵的更新。

W0 + ΔW = W0 + BA,其中W0(dk)、A(dr)和B(r*k),r << d、k

这些矩阵构成LoRA适配器。这里的“r”是一个超参数(该论文建议使用1、2、4、8或64,其中4或8在大多数情况下效果最好)。在训练期间,W0被冻结,不接收梯度更新,而A和B包含可训练参数。W0和ΔW = BA与相同的输入进行乘法运算,它们的输出向量在坐标上进行求和。A使用随机高斯初始化,B使用零初始化,因此在训练开始时ΔW = BA为零。

在这里插入图片描述

在这里插入图片描述

在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x,所以,只要将训练完成的矩阵乘积BA跟原本的权重矩阵W加到一起作为新权重参数替换原始预训练语言模型的W即可,不会增加额外的计算资源。

LoRA 伪代码

LoRA 的实现相对简单。我们可以将其视为 LLM 中全连接层的修改前向传递。在伪代码中,如下所示:

代码语言:javascript

input_dim = 768  # e.g., the hidden size of the pre-trained model
output_dim = 768  # e.g., the output size of the layer
rank = 8  # The rank 'r' for the low-rank adaptation

W = ... # from pretrained network with shape input_dim x output_dim

W_A = nn.Parameter(torch.empty(input_dim, rank)) # LoRA weight A
W_B = nn.Parameter(torch.empty(rank, output_dim)) # LoRA weight B

# Initialization of LoRA weights
nn.init.kaiming_uniform_(W_A, a=math.sqrt(5))
nn.init.zeros_(W_B)

def regular_forward_matmul(x, W):
    h = x @ W
return h

def lora_forward_matmul(x, W, W_A, W_B):
    h = x @ W  # regular matrix multiplication
    h += x @ (W_A @ W_B)*alpha # use scaled LoRA weights
return h

在上面的伪代码中,alpha 是一个缩放因子,用于调整组合结果(原始模型输出加上低秩自适应)的大小。这可以平衡预训练模型的知识和新的特定于任务的适应 - 默认情况下,alpha 通常设置为 1。另请注意,虽然 W A 初始化为小的随机权重,WB 初始化为 0,因此

ΔW = WA WB = 0 < /span> 在训练开始时,意味着我们用原始权重开始训练。

代码部分

在本博客中,我们将使用LaMini-instruction 数据集 作为示例数据集。如果我们有一些自定义企业 QnA 数据集,我们可以使用相同的数据集来微调模型。我们会一步一步地去做——

第 1 步 — 加载 LaMini 指令数据集 使用 Huggingface 中的 load_dataset 第 2 步 — 加载 Dolly Tokenizer并使用 Huggingface 进行建模(再次!) 第 3 步 — 数据准备 — Tokenize, 分割数据集并准备批处理 第 4 步 — 配置 LoRA 并获取 PEFT 模型 第 5 步 — 训练模型并保存 第 6 步 - 使用微调模型进行预测

在此之前,让我们导入必要的包

代码语言:javascript

# mentioning datatypes for better documentation
from typing import Dict, List
from datasets import Dataset, load_dataset, disable_caching
disable_caching() ## disable huggingface cache
from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
import torch
from torch.utils.data import Dataset
from IPython.display import Markdown
  1. 数据加载

代码语言:javascript

# Dataset Preparation
dataset = load_dataset("MBZUAI/LaMini-instruction" , split = 'train') 
small_dataset = dataset.select([i for i in range(200)])
print(small_dataset)
print(small_dataset[0])

# creating templates
prompt_template = """Below is an instruction that describes a task. Write a response that appropriately completes the request. Instruction: {instruction}\n Response:"""
answer_template = """{response}"""

# creating function to add keys in the dictionary for prompt, answer and whole text
def _add_text(rec):
    instruction = rec["instruction"]
    response = rec["response"] 
    # check if both exists, else raise error   
    if not instruction:
        raise ValueError(f"Expected an instruction in: {rec}")
    if not response:
        raise ValueError(f"Expected a response in: {rec}")
    rec["prompt"] = prompt_template.format(instruction=instruction)
    rec["answer"] = answer_template.format(response=response)
    rec["text"] = rec["prompt"] + rec["answer"]
    return rec

# running through all samples
small_dataset = small_dataset.map(_add_text)
print(small_dataset[0])

为了微调我们的 LLM,我们需要用提示来装饰我们的指令数据集 — 指令:{指令} 响应:{响应}

  1. 分词器和模型加载

代码语言:javascript

# loading the tokenizer for dolly model. The tokenizer converts raw text into tokens
model_id = "databricks/dolly-v2-3b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token

#loading the model using AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    # use_cache=False,
    device_map="auto", #"balanced",
    load_in_8bit=True,
    torch_dtype=torch.float16
)

# resizes input token embeddings matrix of the model if new_num_tokens != config.vocab_size.
model.resize_token_embeddings(len(tokenizer))
> Embedding(50280, 2560)
  1. 数据准备

代码语言:javascript

from functools import partial
import copy
from transformers import DataCollatorForSeq2Seq

MAX_LENGTH = 256

# Function to generate token embeddings from text part of batch
def _preprocess_batch(batch: Dict[str, List]):  
    model_inputs = tokenizer(batch["text"], max_length=MAX_LENGTH, truncation=True, padding='max_length')    
    model_inputs["labels"] = copy.deepcopy(model_inputs['input_ids'])
    return model_inputs

_preprocessing_function = partial(_preprocess_batch)

# apply the preprocessing function to each batch in the dataset
encoded_small_dataset = small_dataset.map(
        _preprocessing_function,
        batched=True,
        remove_columns=["instruction", "response", "prompt", "answer"],
)
processed_dataset = encoded_small_dataset.filter(lambda rec: len(rec["input_ids"]) <= MAX_LENGTH)

# splitting dataset
split_dataset = processed_dataset.train_test_split(test_size=14, seed=0)
print(split_dataset)

# takes a list of samples from a Dataset and collate them into a batch, as a dictionary of PyTorch tensors.
data_collator = DataCollatorForSeq2Seq(
        model = model, tokenizer=tokenizer, max_length=MAX_LENGTH, pad_to_multiple_of=8, padding='max_length')
  1. 配置LoRA

代码语言:javascript

from peft import LoraConfig, get_peft_model, prepare_model_for_int8_training

LORA_R = 256 # 512
LORA_ALPHA = 512 # 1024
LORA_DROPOUT = 0.05
# Define LoRA Config
lora_config = LoraConfig(
                 r = LORA_R, # the dimension of the low-rank matrices
                 lora_alpha = LORA_ALPHA, # scaling factor for the weight matrices
                 lora_dropout = LORA_DROPOUT, # dropout probability of the LoRA layers
                 bias="none",
                 task_type="CAUSAL_LM",
                 target_modules=["query_key_value"],
)

# Prepare int-8 model for training - utility function that prepares a PyTorch model for int8 quantization training. <https://huggingface.co/docs/peft/task_guides/int8-asr>
model = prepare_model_for_int8_training(model)
# initialize the model with the LoRA framework
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()

> trainable params: 83886080 || all params: 2858972160 || trainable%: 2.9341342029717423
  1. 模型训练与保存

代码语言:javascript

from transformers import TrainingArguments, Trainer
import bitsandbytes
# define the training arguments first.
EPOCHS = 3
LEARNING_RATE = 1e-4  
MODEL_SAVE_FOLDER_NAME = "dolly-3b-lora"
training_args = TrainingArguments(
                    output_dir=MODEL_SAVE_FOLDER_NAME,
                    overwrite_output_dir=True,
                    fp16=True, #converts to float precision 16 using bitsandbytes
                    per_device_train_batch_size=1,
                    per_device_eval_batch_size=1,
                    learning_rate=LEARNING_RATE,
                    num_train_epochs=EPOCHS,
                    logging_strategy="epoch",
                    evaluation_strategy="epoch",
                    save_strategy="epoch",
)
# training the model 
trainer = Trainer(
        model=model,
        tokenizer=tokenizer,
        args=training_args,
        train_dataset=split_dataset['train'],
        eval_dataset=split_dataset["test"],
        data_collator=data_collator,
)
model.config.use_cache = False  # silence the warnings. Please re-enable for inference!
trainer.train()
# only saves the incremental 🤗 PEFT weights (adapter_model.bin) that were trained, meaning it is super efficient to store, transfer, and load.
trainer.model.save_pretrained(MODEL_SAVE_FOLDER_NAME)
# save the full model and the training arguments
trainer.save_model(MODEL_SAVE_FOLDER_NAME)
trainer.model.config.save_pretrained(MODEL_SAVE_FOLDER_NAME)

该模型似乎对训练数据过度拟合,这可能是因为训练测试数据集、训练参数的差异,但我们找到了微调 LLM 的关键。

  1. 使用微调模型进行预测

代码语言:javascript

# Function to format the response and filter out the instruction from the response.
def postprocess(response):
    messages = response.split("Response:")
    if not messages:
        raise ValueError("Invalid template for prompt. The template should include the term 'Response:'")
    return "".join(messages[1:])
# Prompt for prediction
inference_prompt = "List 5 reasons why someone should learn to cook"
# Inference pipeline with the fine-tuned model
inf_pipeline =  pipeline('text-generation', model=trainer.model, tokenizer=tokenizer, max_length=256, trust_remote_code=True)
# Format the prompt using the `prompt_template` and generate response 
response = inf_pipeline(prompt_template.format(instruction=inference_prompt))[0]['generated_text']
# postprocess the response
formatted_response = postprocess(response)
formatted_response

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取==🆓

在这里插入图片描述

<think>嗯,用户想了解如何使用LoRA对多模态大模型进行微调的实际操作方法。首先,我需要回忆一下LoRA的基本原理。LoRA通过低秩分解来模拟参数变化,这样可以减少训练参数量,适合大模型微调。用户提到的多模态大模型,比如DeepSeek Janus-Pro 7B,可能需要同时处理文本、图像等多种数据,所以微调时要考虑不同模态的参数调整。 接下来,我得结合用户提供的引用内容。引用[1]提到LoRA的核心思想,引用[2]介绍了ms-swift框架支持多模态模型的训练和微调,而引用[3]则提供了一些学习资料。所以,我需要整合这些信息,给出一个实战教程的步骤。 首先,可能需要准备环境,安装ms-swift框架,因为引用[2]提到它支持多模态模型的训练和部署。然后,数据准备部分,要处理多模态数据,比如文本-图像对。接着,配置LoRA参数,确定rank和模块选择。在微调过程中,可能需要加载预训练的多模态模型,并应用LoRA到特定的模块,比如视觉编码器和文本解码器。 然后,用户可能关心具体的代码示例,所以需要提供一个使用ms-swift的代码片段,展示如何配置和启动训练。此外,还要考虑模型融合,将LoRA适配器合并回原模型,以便推理时使用。最后,性能优化和注意事项也是关键点,比如混合精度训练和参数调整。 用户可能还希望了解如何验证微调效果,比如在多模态任务上的评估指标,以及常见问题的解决方法。需要确保回答结构清晰,步骤详细,并且引用相关的资料,比如引用[1]和[2]来支持技术点。同时,生成的相关问题需要围绕LoRA微调的优化、多模态数据处理和框架使用等方面,帮助用户进一步深入学习。</think>### LoRA微调多模态大模型实战教程 ### 一、环境准备 1. 安装ms-swift框架(魔搭大模型训练框架) ```bash pip install ms-swift[multi-modal]>=1.6.0 ``` 2. 准备预训练模型(以DeepSeek Janus-Pro 7B为例)[^2] ```python from modelscope import snapshot_download model_dir = snapshot_download('deepseek-ai/DeepSeek_Janus-Pro-7B') ``` ### 二、数据准备(以图文对数据为例) ```python # 示例数据集格式 dataset = [ { "image": "path/to/image.jpg", "text": "一只橘色猫咪在窗台上晒太阳" }, # 更多多模态样本... ] ``` ### 三、LoRA配置 ```yaml # config/lora.yaml train_args: learning_rate: 1e-4 max_epochs: 5 per_device_train_batch_size: 2 lora: rank: 8 # 低秩矩阵维度[^1] target_modules: ['q_proj', 'v_proj', 'vision_encoder'] # 多模态特殊模块[^2] ``` ### 四、微调执行 ```python from swift import LoRAConfig, Swift from swift.llm import DatasetName, ModelType, get_model_tokenizer # 加载多模态模型 model, tokenizer = get_model_tokenizer( ModelType.deepseek_janus_pro_7b_chat, model_kwargs={'device_map': 'auto'} ) # 创建LoRA适配器 lora_config = LoRAConfig( rank=8, target_modules=['q_proj', 'v_proj', 'vision_proj'] ) model = Swift.prepare_model(model, lora_config) ``` ### 五、训练过程 ```bash # 启动训练命令 swift sft \ --model_type deepseek-janus-pro-7b-chat \ --dataset coco-en-2k \ --lora_rank 8 \ --gradient_checkpointing true \ --use_flash_attn true ``` ### 六、模型融合(部署准备) ```python # 合并LoRA权重到原模型 Swift.merge_and_unload(model) model.save_pretrained('merged_model') ``` ### 关键参数解析 1. **Rank选择**:通常取8-64之间,数值越大训练能力越强但参数量增加 2. **目标模块**: - `vision_proj`: 视觉编码器投影层 - `text_decoder`: 文本解码器层 3. **混合精度训练**:推荐使用`bfloat16`减少显存占用 ### 性能优化技巧 1. 使用梯度检查点技术节省显存 2. 开启Flash Attention加速计算 3. 冻结非关键模块参数(如部分视觉编码器层) ### 效果验证 ```python # 推理测试样例 response = model.generate( images=[Image.open("cat.jpg")], text="描述这张图片的内容" ) print(response) # 输出:"一只橘色猫咪在窗台上晒太阳" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值