欺诈文本分类检测(十):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 bitsandbytes

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量化微调策略与实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1524256.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

使用Python的Elasticsearch客户端 elasticsearch-py 来完成删除现有索引、重新创建索引并测试分词的示例代码

以下是一个使用Python的Elasticsearch客户端 elasticsearch-py 来完成删除现有索引、重新创建索引并测试分词的示例代码 一、安装依赖 pip install elasticsearch二、运行效果 三、程序代码 from elasticsearch import Elasticsearch, NotFoundError# 连接到Elasticsearch es…

PS系统教程32

调色之单通道调色 上次分享内容调色可通过 色阶调色曲线调色 案例-复古 CtrlM调出曲线图选择单色通道-蓝色降到1/2绿色降1/4红色定点上拉 冷风 Alt复位降到1/2绿色降1/4红色定点下拉 调色-色相饱和度&#xff08;ctrlu&#xff09; 原图 只改变背景不改变蜥蜴的颜色 对比…

SpringBoot中@SchedulerLock注解实现定时任务中分布式锁的使用

背景 在SpringBoot项目中经常会去写一些定时任务&#xff0c;但是当我们的服务的实例部署多个的情况下&#xff0c;那么每个实例中的定时任务都会执行一遍&#xff0c;这显然不是我们想要的&#xff0c;我们只想让它执行一次。在没有引入像xxl-job之类的分布式任务调度框架的前…

CRIO与Windows下LabVIEW开发对比

LabVIEW在CRIO和Windows平台上开发时&#xff0c;尽管同属于一个编程环境&#xff0c;但在硬件架构、实时性能、模块化设计等方面存在显著差异。CRIO系统通常应用于工业自动化和嵌入式控制&#xff0c;具有实时操作系统支持和强大的I/O扩展能力&#xff1b;而Windows系统则更适…

突破教材,简单聊聊《文件系统》

文章目录 前言&#xff1a;文件系统的引入&#xff1a;认识物理磁盘&#xff1a; 对磁盘的存储进行逻辑抽象&#xff1a;LBA逻辑区块地址&#xff1a; &#x1f680;文件系统的理解&#xff1a;理解各个区段&#xff1a;&#x1f6f9;深入理解 inode&#xff1a;inode和文件名&…

动态化-鸿蒙跨端方案介绍

一、背景 &#x1f449; 华为在2023.9.25官方发布会上宣布&#xff0c;新的鸿蒙系统将不再兼容安卓应用&#xff0c;这意味着&#xff0c;包括京东金融APP在内的所有安卓应用&#xff0c;在新的鸿蒙系统上将无法运行&#xff0c;需要重新开发专门适用于新鸿蒙系统的专版APP。 …

Windows安装使用Docker

配置Dorker环境 启用或关闭windows功能 安装wsl 以管理员身份打开windows PowerShell&#xff0c;安装相关配置 下载docker应用程序 Releases tech-shrimp/docker_installer (github.com) 安装Docker 指定安装位置 默认双击程序就开始安装了&#xff0c;要安装在指定位置…

iOS P8证书推送测试

最近在配合服务端人员调试相关的 APNS auth key 推送的问题&#xff0c;相比于苹果的P12证书的推送&#xff0c;P8证书的推送显得方便很多&#xff0c;P8的优势在于简单&#xff0c;安全 容易生成 最重要的是不会过期。 现在我们来看下测试具体流程&#xff1a; 方法一 地址…

ESP-DL部署魔改MobilenetV1—3. 模型部署

在完成模型训练和模型量化后&#xff0c;就可以开始我们的模型部署了。这部分的关键在于Model类中层的初始化以及build和call的实现。 环境依赖 esp-idf > 5.0esp-dl 模型定义 在模型定义时&#xff0c;我们需要用到量化时输出的层信息、cat_vs_dog_coefficient.hpp&…

分析源码学习c++(srs中http客户端)

文章目录 背景基础知识c标准库虚函数虚函数使用方法 虚析构函数 HTTP客户端使用方法TCP传输层分析使用方法结构分析连接函数读写函数 协议层分析初始化函数发送请求响应数据解析 背景 通过阅读源码&#xff0c;编写分析笔记来学习C是一种非常有效且深入的方法&#xff0c;能帮助…

论文解读 | ACL2024 Outstanding Paper:因果指导的主动学习方法:助力大语言模型自动识别并去除偏见...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击阅读原文观看作者直播讲解回放&#xff01; 作者简介 孙洲浩&#xff0c;哈尔滨工业大学SCIR实验室博士生 概述 尽管大语言模型&#xff08;LLMs&#xff09;展现出了非常强大的能力&#xff0c;但它们仍然…

数据源10min自动断开连接导致查询抛异常(未获取可用连接)

由于个人能力有限&#xff0c;本文章仅仅代表本人想法&#xff0c;若有不对请即时指出&#xff0c;若有侵权&#xff0c;请联系本人。 1 背景 工作中引入druid来管理数据源连接&#xff0c;由于数据源每隔10分钟强制管理空闲超过10分钟的连接&#xff0c;导致每隔10分钟出现1…

Web攻防之应急响应(二)

目录 前提 &#x1f354;学习Java内存马前置知识 内存马 内存马的介绍 内存马的类型众多 内存马的存在形式 Java web的基础知识&#xff1a; Java内存马的排查思路&#xff1a; &#x1f354;开始查杀之前的需要准备 1.登录主机启动服务器 2.生成jsp马并连接成功 …

【Linux】多线程:线程概念,线程与进程的区别与联系,多线程相较于多进程的优势

目录 一、进程基本属性回顾 二、线程概念 三、操作系统为什么要引入线程—多进程和多线程的区别 为什么多线程比多线程调度效率更快&#xff1f; 四、线程的优点 五、线程的缺点 六、线程异常 一、进程基本属性回顾 在学习线程之前&#xff0c;我们先来回顾一下进程的基…

注册安全分析报告:熊猫频道

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【Rust】007-包管理与模块管理

【Rust】007-包管理与模块管理 文章目录 【Rust】007-包管理与模块管理一、包管理器&#xff1a;Cargo1、简介Cargo 官方文档仓库 2、项目初始化3、写一个小程序任务目标寻找合适的库添加库到我们的项目中代码实现cargo run运行 二、模块管理1、概述2、文件作为模块第一步&…

前端模拟面试:如何检查JavaScript对象属性是否存在?

你正在参加一场关键的前端开发面试&#xff0c;面试官提出了一个经典的JavaScript问题&#xff1a;“在JavaScript中&#xff0c;如何检查对象是否包含某个属性&#xff1f;请你详细介绍几种不同的方法&#xff0c;并解释它们的区别。” 这个问题不仅考验你对JavaScript的基础掌…

怎样在公司将手机屏幕(远程)投屏到家里的大电视上?

我不住家里&#xff0c;前几次回去都会替老爸老妈清理手机。这两个星期没空回去&#xff0c;老爸吐槽手机用几天就又卡了&#xff0c;其实就是清理一些手机缓存的问题。 我说我远程控制他的手机&#xff0c;给他清理一下。他一听“控制”就不喜欢&#xff0c;说我大了&#xf…

sM4040B科学级显微制冷相机特性

sM4040B科学级显微制冷相机特性 sM4040B搭载了 GSENSE4040BSI 3.2 英寸图像传感器&#xff0c;针对传感器固有的热噪声&#xff0c;专门设计了高效制冷模块&#xff0c;使得相机传感器的工作温度比环境温度低达 35-40 度。针对制冷相机常见的低温结雾现象设计了防结雾机制&…

【Python百日进阶-Web开发-音频】Day707 - 时域处理 librosa.autocorrelate

文章目录 一、时域处理1.1 librosa.autocorrelate1.1.1 语法与参数1.1.2 例子1.1.2.1 计算完全自相关y1.1.2.2 计算长达 4 秒的起始强度自相关 一、时域处理 1.1 librosa.autocorrelate https://librosa.org/doc/latest/generated/librosa.autocorrelate.html 1.1.1 语法与参…