大模型微调实战:使用INT8/FP4/NF4微调大模型

随着,ChatGPT 迅速爆火,引发了大模型的时代变革。然而对于普通大众来说,进行大模型的预训练或者全量微调遥不可及。由此,催生了各种参数高效微调技术,让科研人员或者普通开发者有机会尝试微调大模型。

因此,该技术值得我们进行深入分析其背后的机理,之前分享了大模型参数高效微调技术原理综述的文章。下面给大家分享大模型参数高效微调技术实战系列文章,相关代码均放置在GitHub:llm-action

本文为大模型参数高效微调技术实战的第八篇。本文将结合 bitsandbytes(使用 INT8 量化来加载大模型)和 LoRA 技术来微调Bloom大模型。

量化降低了浮点数据类型的精度,减少了存储模型权重所需的内存。因此,量化会降低推理性能,因为降低精度时会丢失信息。INT8量化只使用四分之一的精度,但它不会降低训练性能,因为它不仅丢弃位或数据。相反,INT8量化从一种数据类型舍入到另一种。

数据集和模型准备

本文使用english_quotes数据集,该数据集可用于多标签文本分类和文本生成。数据集下载地址:huggingface.co/datasets/Ab…

image.png

模型下载地址:huggingface.co/bigscience/…

bitsandbytes 简介

bitsandbytes 是自定义 CUDA 函数的轻量级包装器,特别是 8 比特优化器、矩阵乘法和量化函数。 主要特征如下:

  • 具有混合精度分解的 8 比特矩阵乘法
  • LLM.int8() 推理
  • 8 比特优化器:Adam、AdamW、RMSProp、LARS、LAMB、Lion(节省 75% 内存)
  • 稳定的嵌入层:通过更好的初始化和标准化提高稳定性
  • 8 比特量化:分位数、线性和动态量化
  • 快速的分位数估计:比其他算法快 100 倍

目前,transformers 库已经集成并 原生 支持了 bitsandbytes 这个量化库。而且bitsandbytes 是量化任何模型的最简单方法之一,因为它不需要量化校准数据及校准过程 (即零样本量化)。任何模型只要含有 torch.nn.Linear 模块,就可以对其进行开箱即用的量化。每当在 transformers 库中添加新架构时,只要其可以用 accelerate 库的 device_map="auto" 加载,用户就可以直接受益于开箱即用的 bitsandbytes 量化,同时该方法对性能的影响也是最小的。量化是在模型加载时执行的,无需运行任何后处理或准备步骤。

由于量化模型的唯一条件是包含 torch.nn.Linear 层,因此量化对于任何模态都可以实现开箱即用。用户可以开箱即用地加载诸如 Whisper、ViT、Blip2 之类的 8 比特或 4 比特(FP4/NF4)模型。

如果你在量化基础模型之上使用PEFT库基于Lora进行训练,则可以将训练得到的Apapter合并在基础模型之上进行部署,而不会降低推理性能。你甚至还可以在反量化模型之上合并 Apapter!

下面是使用 NF4 量化加载 4 比特模型的示例:

from transformers import BitsAndBytesConfig

nf4_config = BitsAndBytesConfig(
   load_in_4bit=True,
   bnb_4bit_quant_type="nf4",
   bnb_4bit_use_double_quant=True,
   bnb_4bit_compute_dtype=torch.bfloat16
)

model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)

下面是使用 FP4 量化加载 4 比特模型的示例:

import torch
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
   load_in_4bit=True,
   bnb_4bit_compute_dtype=torch.bfloat16
)

LoRA 简介

LoRA方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。

模型训练及推理

为了不影响阅读体验,详细的微调代码放置在GitHub:llm-action 项目中 finetune_bloom_bnb_peft.ipynb文件,这里仅列出关键步骤。

第一步,加载模型及Tokenizer。

import os

import torch
import torch.nn as nn
import bitsandbytes as bnb
from transformers import AutoTokenizer, AutoConfig, AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("/workspace/model/bloomz-3b", load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained("/workspace/model/bloomz-3b")

注意:这里演示的是INT8,如果希望使用NF4或者FP4,在模型加载时修改quantization_config参数即可,具体可以参考PEFT官方示例:inetune_fp4_opt_bnb_peft.py

NF4+QLoRA

model = AutoModelForCausalLM.from_pretrained(
    model_name_or_path='/name/or/path/to/your/model',
    load_in_4bit=True,
    device_map='auto',
    max_memory=max_memory,
    torch_dtype=torch.bfloat16,
    quantization_config=BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_compute_dtype=torch.bfloat16,
        bnb_4bit_use_double_quant=True,
        bnb_4bit_quant_type='nf4'
    ),
)

第二步,训练模型做准备。在使用 peft 训练 int8 模型之前,需要完成一些预处理,需导入一个实用函数prepare_model_for_int8_training,它将完成如下操作:

  • 将所有非 int8 模块转换为全精度 (fp32) 以确保稳定性
  • 将forward_hook添加到输入嵌入层以启用输入隐藏状态的梯度计算
  • 启用梯度检查点(gradient checkpointing)以提高训练的内存效率
from peft import prepare_model_for_int8_training
model = prepare_model_for_int8_training(model)

第三步,创建 LoRA 微调方法对应的配置;同时,通过调用 get_peft_model 方法包装基础的 Transformer 模型。

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16, lora_alpha=32, target_modules=["query_key_value"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM"
)

model = get_peft_model(model, config)
model = model.to(device)
print_trainable_parameters(model)

第四步,进行模型微调。

from transformers import Seq2SeqTrainer, TrainerCallback, TrainingArguments, TrainerState, TrainerControl
from transformers.trainer_utils import PREFIX_CHECKPOINT_DIR

# 回调保存Peft模型
class SavePeftModelCallback(TrainerCallback):
    def on_save(
        self,
        args: TrainingArguments,
        state: TrainerState,
        control: TrainerControl,
        **kwargs,
    ):
        checkpoint_folder = os.path.join(args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{state.global_step}")
        print("checkpoint folder: ",checkpoint_folder)
        peft_model_path = os.path.join(checkpoint_folder, "adapter_model")
        kwargs["model"].save_pretrained(peft_model_path)

        
        files = os.listdir(checkpoint_folder)
        print("checkpoint folder list: ", files)
        adapter_files = os.listdir(peft_model_path)
        print("checkpoint adapter folder list: ", adapter_files)
        
        pytorch_model_path = os.path.join(checkpoint_folder, "pytorch_model.bin")
        if os.path.exists(pytorch_model_path):
            os.remove(pytorch_model_path)
        return control

args = transformers.TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        max_steps=20,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=1,
        output_dir="outputs",
        save_strategy = 'steps',
        save_steps = 10
    )

trainer = transformers.Trainer(
    model=model,
    train_dataset=data["train"],
    args=args,
    data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),
    callbacks=[SavePeftModelCallback()],
)

model.config.use_cache = False  # silence the warnings. Please re-enable for inference!

trainer.train()

第五步,重新加载训练的Apapter进行推理。

import torch
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer

peft_model_id = "outputs/checkpoint-20/"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForCausalLM.from_pretrained(
    config.base_model_name_or_path, return_dict=True, load_in_8bit=True, device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)

# Load the Lora model
model = PeftModel.from_pretrained(model, peft_model_id)

batch = tokenizer("Two things are infinite: ", return_tensors="pt")

# 使用 Pytorch 的 autocast 运行推理
# 以 autocast 选择的特定op数据类型运行ops,以提高性能,同时保持准确性。
with torch.cuda.amp.autocast():
    output_tokens = model.generate(**batch, max_new_tokens=50)

print("output:\n\n", tokenizer.decode(output_tokens[0], skip_special_tokens=True))

结语

本文结合 bitsandbytes(使用 INT8 量化来加载大模型)和 LoRA 技术来微调Bloom大模型。码字不易,如果觉得我的文章能够能够给您带来帮助,期待您的点赞收藏加关注~~

如何学习AI大模型?

大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?”“谁的饭碗又将不保了?”等问题热议不断。

不如成为「掌握AI工具的技术人」,毕竟AI时代,谁先尝试,谁就能占得先机!

想正式转到一些新兴的 AI 行业,不仅需要系统的学习AI大模型。同时也要跟已有的技能结合,辅助编程提效,或上手实操应用,增加自己的职场竞争力。

但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高

那么我作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,希望可以帮助到更多学习大模型的人!至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

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

👉 福利来袭优快云大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

全套AGI大模型学习大纲+路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈
基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉 福利来袭优快云大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

img

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

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

### 大模型微调所需显存的估算 大模型微调所需的 GPU 显存主要由以下几个因素决定:模型大小、微调方法以及优化策略。对于较大的模型,全量微调通常需要较高的显存支持,而高效的微调方法可以显著降低这一需求。 #### 1. **全量微调** 当进行全量微调时,模型的所有参数都会被更新,因此需要足够的显存来存储模型权重、梯度和优化器状态。例如,一个具有数十亿参数的大模型可能需要几十 GB 的显存才能完成训练[^1]。然而,在资源有限的情况下,这种方法并不现实。 #### 2. **高效微调方法** 为了适应低资源配置环境,研究者开发了一些高效的微调方法,这些方法能够大幅减少显存消耗: - **LoRA (Low-Rank Adaptation)** LoRA 方法通过引入低秩矩阵分解的方式调整模型的关键部分,而不是直接修改原始权重。这种方式只需要额外存储少量新增加的小规模参数,从而极大地降低了显存需求。即使是在较小的显卡上(如拥有 4GB 显存的 GTX 960),也可以尝试使用此技术实现简单的微调操作[^1]。 - **QLoRA** 结合量化技术和 LoRA 的优势,QLoRA 能够进一步压缩模型尺寸并减少显存占用。尽管如此,具体表现仍依赖于目标应用领域的要求及其对精度损失容忍程度如何评估[^1]。 #### 3. **量化与精度控制** 除了改变微调方式外,还可以通过对模型进行量化处理来减小其体积进而节约更多空间。比如从 FP16 或 BF16 进一步降到 INT8 精度水平,则理论上可以使每张卡片上的可用有效工作区域扩大近两倍左右。不过需要注意的是,这样做可能会带来一定程度的质量折损[^2]。 #### 4. **分布式训练方案** 针对极端受限条件下的场景,还有多种分布式的解决方案可供选择: - **数据并行(Data Parallelism):** 将批量样本拆分成若干份分别交给不同节点独立计算后再汇总结果;但是这种做法无法缓解单机内部件间竞争激烈所带来的压力——即每个单独使用的装置依旧面临相同的高峰时期内存瓶颈问题[^3]。 - **零冗余优化(Zero Redundancy Optimizer, ZeRO Stage 3):** 它不仅实现了跨设备共享参数副本的功能而且还允许动态加载那些当前迭代过程中需要用到的部分而非一次性全部载入内存之中,最终达到既缩短整体耗时时长又能充分利用现有硬件设施的目的. - **张量切片(Tensor Sharding/Slicing):** 把原本属于同一个张量对象的内容按照一定规则分开存放至各个处理器单元里头去执行相应的运算任务,这样做的好处是可以让每一个参与协作过程中的成员只负责维护属于自己那一份额度范围内的变量集合即可[^3]. - **管道级联(Pipeline Parallelism):** 此种模式把神经网络结构纵向切割成数段之后再分配给不同的计算实体各自承担其中一段职责所在的工作流程环节,虽然说这样的安排有助于减轻局部负载过重的现象发生几率可是同时也伴随着更多的消息传递成本开支增加的风险存在[^3]. 综上所述,即便面对像只有 4GB 显存容量这么局限性的条件下也并非完全没有希望达成某些特定类型的预训练语言模型定制化改造作业的目标可能性。只是在实际操作之前务必要充分考虑到各种潜在影响因子之间的相互作用关系以便做出更加合理科学的选择决策而已。 ```python import torch from transformers import LlamaForCausalLM, BitsAndBytesConfig # 使用 Quantization 减少显存占用 bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) model = LlamaForCausalLM.from_pretrained("meta-llama/Llama-2-7b", quantization_config=bnb_config) ``` 以上代码片段展示了如何利用 `BitsAndBytes` 库来进行四比特量化以适配较低规格的 GPU 设备。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值