欺诈文本分类微调(十):QLora量化微调

2024-09-04 16:44

本文主要是介绍欺诈文本分类微调(十):QLora量化微调,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 引言

前文微调方法概览总结了微调的各种方法,并且在更前面两篇文章Lora单卡训练
和 lora单卡二次调优中已经尝试过用Lora进行微调,本文出于好奇准备尝试下用QLora进行微调的效果。

QLoRA是一种新的微调大型语言模型(LLM)的方法,它的特点是能在节省内存的同时保持推理性能。它的出现是为了应对大型模型微调时内存需求大,成本昂贵的问题。

工作原理:首先将LLM进行4位量化,从而显著减少模型的内存占用,接着使用低阶适配器(LoRA)方法对量化的LLM进行微调,因此,QLora可以看成是量化+Lora的结合体。

采用以下核心技术:

  • 4位量化,它创新性的引入了特殊的4位浮点数表示方法NF4(Normal Float 4-bit),使用非均匀量化来平衡数据范围与精度。
  • 双量化,一种对量化后常数再次进行量化的方法,每个参数可平均节省约 0.37 位。
  • 分页优化,使用具有 NVIDIA 统一内存的分页优化器,以避免具有长序列长度的小批量时出现内存峰值。

依赖库安装:

pip install -q -U bitsandbygit

bitsandbytes主要是针对llm和transformers模型提供了优化和量化模型的功能,专门为8位优化器、矩阵乘法和量化而设计,提供了像8位Adam/AdamW之类的函数。目标是通过8位操作实现高效的计算和内存使用从而使llm更易于访问。```

本文将用欺诈文本分类这个业务场景来测试下QLora进行量化微调的实际效果。

2. 训练过程

2.1 初始化

引入之前封装好的trainer.py脚本,定义模型路径和数据集路径,以及要使用的GPU设备。

%run trainer.py
traindata_path = '/data2/anti_fraud/dataset/train0819.jsonl'
evaldata_path = '/data2/anti_fraud/dataset/eval0819.jsonl'
model_path = '/data2/anti_fraud/models/modelscope/hub/Qwen/Qwen2-1___5B-Instruct'
output_path = '/data2/anti_fraud/models/Qwen2-1___5B-Instruct_ft_0830_2'
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
device = 'cuda'
2.2 加载模型和数据集

由于QLora需要以量化的方式来加载模型,所以加载模型的方法需要作调整,这里的改动是引入BitsAndBytesConfig类构建一个量化配置quantization_config, 具体配置项释义:

  • load_in_4bit:决定了模型参数以4位量化格式加载,加载后的模型参数占用空间会比较小;
  • bnb_4bit_compute_dtype=bfloat16:决定了矩阵乘法的计算精度使用bfloat16,输入数据也会被转换成bfloat16位进行计算;
  • bnb_4bit_quant_type:指定量化数据类型nf4;
  • bnb_4bit_use_double_quant:是否启用双重量化;
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfigdef load_model(model_path, device='cuda'):tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=False, trust_remote_code=True)model = AutoModelForCausalLM.from_pretrained(model_path,torch_dtype=torch.bfloat16,quantization_config=BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_compute_dtype=torch.bfloat16,bnb_4bit_use_double_quant=False, bnb_4bit_quant_type='nf4'),)return model, tokenizer

注1:普通的量化通常是将数值分成均匀的区间,比如,将0到1之间的数值分成16个区间,每个区间的宽度相同。而NF4则根据数据的分布情况,使用不均匀的区间来表示数值,这样可以更有效地表示模型中的重要数值,特别是那些频繁出现的数值。

注2:双重量化是指在已经量化的基础上再进行量化,第二次量化并不会改变位数本身(即仍然是4位),它的目的是通过更紧凑地表示数值,使得存储和计算更加高效。由于每一次量化都会引入一些量化误差,双重量化可能会带来更大的数值误差,所以一般只用于极端内存受限的情况下。

注3:之所以模型参数加载使用4位而计算时使用16位,是因为量化本身已经带来了误差,计算时需要采用更高的精度是为了减少量化误差带来的影响。

加载模型参数和token序列化器。

%%time
model, tokenizer = load_model(model_path, device)
model.device
    CPU times: user 1min 55s, sys: 3.96 s, total: 1min 59sWall time: 1min 52sdevice(type='cuda', index=0)

在这里插入图片描述

占用内存方面,量化加载的1.9GB相比于bfloat16加载的3.9GB减少了将近一半,模型加载时的显存优化比较明显。

加载耗时方面,使用量化方式加载模型的过程是比较慢的,耗时了1分52秒,中间涉及到将模型参数从高精度的浮点数(如 FP32)转换为低精度的 NF4 格式。与之对比,不带量化时基本是秒加载。

加载数据集,复用前文的方法。

train_dataset, eval_dataset = load_dataset(traindata_path, evaldata_path, tokenizer)
2.3 构建训练参数

训练参数:引入分页内存优化器来优化训练过程中的内存分配。

train_args = build_train_arguments(output_path)
train_args.optim="paged_adamw_32bit"   

paged_adamw_32bit 是一种优化器配置,它使用了分页内存管理和32位浮点数来优化训练过程,可以帮助你在训练大规模模型时更有效地管理内存和计算资源。

lora配置:同前文Lora训练一样使用大小为16的秩。

lora_config = build_loraconfig()
lora_config.lora_dropout = 0.2   
lora_config.r = 16
lora_config.lora_alpha = 32
2.4 开始训练

构造训练器开始训练。

trainer = build_trainer(model, tokenizer, train_args, lora_config, train_dataset, eval_dataset)
trainer.train()
StepTraining LossValidation Loss
1000.0433000.028851
2000.0413000.045375
3000.0156000.025569
4000.0287000.023149
5000.0244000.022869
6000.0309000.021145
7000.0196000.019462
8000.0189000.023610
9000.0188000.019515
10000.0174000.018651
11000.0187000.018088
12000.0120000.019770
13000.0124000.023283
14000.0166000.017231
15000.0118000.020865
16000.0120000.018183
17000.0080000.017868
18000.0114000.017251
19000.0172000.017052
20000.0158000.016834
21000.0074000.019656
22000.0101000.016112
23000.0063000.016171
24000.0072000.019825
25000.0046000.022892
26000.0064000.023701
27000.0031000.025771
    TrainOutput(global_step=2700, training_loss=0.028382157780299032, metrics={'train_runtime': 5695.8171, 'train_samples_per_second': 9.895, 'train_steps_per_second': 0.618, 'total_flos': 1.1883908308313702e+17, 'train_loss': 0.028382157780299032, 'epoch': 2.2998296422487225})

训练过程中观察内存变化:
在这里插入图片描述

训练时的显存占用相比非量化时并没有明显变化,基本上占满了24G显卡的显存。

推测原因可能是:QLoRA只是通过量化技术减少了模型参数加载时的显存占用,但训练时仍然会反量化为16位进行矩阵计算,尤其是前向和反向传播阶段,显存的主要消耗来自于激活值、梯度和优化器状态,模型参数仅仅是一小部分,这就导致真正训练过程中占用的显存相比非量化时并没有减少。

QLoRA 主要通过量化模型参数来减小显存占用,但在需要更大的 batch size 的场景下,其显存优化效果可能并不显著。

3. 评估测试

用验证损失最低的checkpoint-2200进行测评。

%run evaluate.py
checkpoint_path='/data2/anti_fraud/models/Qwen2-1___5B-Instruct_ft_0830_2/checkpoint-2200'
evaluate(model_path, checkpoint_path, evaldata_path, device, batch=True, debug=True)
run in batch mode, batch_size=8progress: 100%|██████████| 2348/2348 [03:19<00:00, 11.80it/s]tn:1145, fp:20, fn:167, tp:1016
precision: 0.9806949806949807, recall: 0.8588334742180896

这个训练结果和前文的召回率0.86区别不大,说明使用量化后的模型参数进行训练确实能保持和16位精度的参数训练几乎一样的效果。

小结:本文通过实际训练来测试QLora对于显存占用和推理性能方面的效果,在我们这个验证结果里,推理性能方面几乎可以保持同先前一样的效果,但显存占用只在加载时降低了不到1/2, 而在训练过程中相比于非量化时没有明显减少。原因可能是由于我们的模型太小,而训练时的批量相对较大,模型参数加载时所优化的这部分内存,与整个训练过程所需要的内存相比较小,所以内存优化的整体效果就不太明显。

基于QLora主要是通过减少模型参数所占用的显存这个原理出发,个人理解可能在参数更大的模型并且batch_size更小的训练时效果可能会比较显著。

相关阅读

  • 微调方法概览
  • 欺诈文本分类微调(六):Lora单卡训练
  • 欺诈文本分类微调(七):lora单卡二次调优
  • QLoRA量化微调策略与实践

这篇关于欺诈文本分类微调(十):QLora量化微调的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136470

相关文章

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

Python中图片与PDF识别文本(OCR)的全面指南

《Python中图片与PDF识别文本(OCR)的全面指南》在数据爆炸时代,80%的企业数据以非结构化形式存在,其中PDF和图像是最主要的载体,本文将深入探索Python中OCR技术如何将这些数字纸张转... 目录一、OCR技术核心原理二、python图像识别四大工具库1. Pytesseract - 经典O

苹果macOS 26 Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色

《苹果macOS26Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色》在整体系统设计方面,macOS26采用了全新的玻璃质感视觉风格,应用于Dock栏、应用图标以及桌面小部件等多个界面... 科技媒体 MACRumors 昨日(6 月 13 日)发布博文,报道称在 macOS 26 Tahoe 中

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

Pandas使用AdaBoost进行分类的实现

《Pandas使用AdaBoost进行分类的实现》Pandas和AdaBoost分类算法,可以高效地进行数据预处理和分类任务,本文主要介绍了Pandas使用AdaBoost进行分类的实现,具有一定的参... 目录什么是 AdaBoost?使用 AdaBoost 的步骤安装必要的库步骤一:数据准备步骤二:模型

C#TextBox设置提示文本方式(SetHintText)

《C#TextBox设置提示文本方式(SetHintText)》:本文主要介绍C#TextBox设置提示文本方式(SetHintText),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录C#TextBox设置提示文本效果展示核心代码总结C#TextBox设置提示文本效果展示核心代

使用Python实现文本转语音(TTS)并播放音频

《使用Python实现文本转语音(TTS)并播放音频》在开发涉及语音交互或需要语音提示的应用时,文本转语音(TTS)技术是一个非常实用的工具,下面我们来看看如何使用gTTS和playsound库将文本... 目录什么是 gTTS 和 playsound安装依赖库实现步骤 1. 导入库2. 定义文本和语言 3

Python实现常用文本内容提取

《Python实现常用文本内容提取》在日常工作和学习中,我们经常需要从PDF、Word文档中提取文本,本文将介绍如何使用Python编写一个文本内容提取工具,有需要的小伙伴可以参考下... 目录一、引言二、文本内容提取的原理三、文本内容提取的设计四、文本内容提取的实现五、完整代码示例一、引言在日常工作和学

Pytorch微调BERT实现命名实体识别

《Pytorch微调BERT实现命名实体识别》命名实体识别(NER)是自然语言处理(NLP)中的一项关键任务,它涉及识别和分类文本中的关键实体,BERT是一种强大的语言表示模型,在各种NLP任务中显著... 目录环境准备加载预训练BERT模型准备数据集标记与对齐微调 BERT最后总结环境准备在继续之前,确