当前位置: 首页 > news >正文

使用bert-base-chinese中文预训练模型,使用 lansinuote/ChnSentiCorp 中文网购评价数据集进行情感分类微调和训练。

from datasets import load_dataset
from transformers import (BitsAndBytesConfig,  # 用于配置量化参数AutoModel, AutoTokenizer,TrainingArguments,DataCollatorForLanguageModeling,Trainer
)
import torch
from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model# 1.配置4bit量化参数,减少内存占用同时保持模型性能
bnb_config = BitsAndBytesConfig(# 启用4bit精度加载模型,大幅度减少内存使用load_in_4bit=True,# 使用NF4量化类型,一种优化的4bit量化方法bnb_4bit_quant_type="nf4",# 计算时使用bfloat16精度,平衡精度和性能bnb_4bit_compute_dtype=torch.bfloat16,#启用双量化,对量化参数再次量化,进一步压缩模型bnb_4bit_use_double_quant=True,
)# 2.加载模型和分词器 并应用量化配置
model_name = "openchat/openchat-3.5-1210"
model = AutoModel.from_pretranined(model_name,quantization_config=bnb_config, # 应用上面配置的量化参数device_map="auto",trust_remote_code=True, # 信任远程代码,加载自定义模型cache_dir='model/',
)# 加载对应的分词器
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token # 设置填充token为结束token,用于批次处理# 3.为Qlora训练准备模型,应用必要的修改以支持量化训练
model = prepare_model_for_kbit_training(model)# 4.配置lora参数
peft_config = LoraConfig(r=16,                 # LoRA的秩(rank),决定适配器的大小lora_alpha=32,        # 缩放参数,控制适配器输出的缩放程度target_modules=["q_proj", "v_proj"],  # 要应用LoRA的目标模块(注意力机制中的查询和值投影)lora_dropout=0.05,    # LoRA层的dropout率,防止过拟合bias="none",          # 不训练偏置参数task_type="CAUSAL_LM" # 任务类型为因果语言建模
)# 将lora适配器应用到模型上
model = get_peft_model(model, peft_config)
# 打印可训练参数
model.print_trainable_parameters()# 5.配置训练参数
training_arguments = TrainingArguments(output_dir="./results/openchat",  # 训练结果保存目录num_train_epochs=1,  # 训练轮数per_device_train_batch_size=4,  # 每个设备的训练批次大小gradient_accumulation_steps=2,  # 梯度累积步数,模拟更大的批次大小optim="paged_adamw_32bit",  # 使用分页AdamW优化器,防止内存碎片save_steps=50,  # 每50步保存一次检查点learning_rate=2e-4,  # 学习率fp16=False,  # 禁用float16精度bf16=True,  # 启用bfloat16精度,更好的数值稳定性max_grad_norm=0.3,  # 梯度裁剪阈值,防止梯度爆炸warmup_ratio=0.03,  # 预热比例,学习率从0线性增加到初始值group_by_length=True,  # 按长度分组样本,提高训练效率lr_scheduler_type="constant",  # 学习率调度器类型(恒定学习率)
)# 6. 加载和预处理数据集
dataset = load_dataset("timdettmers/openassistant-guanaco", split="train", cache_dir='./dataset')def tokenizer_function(examples):return tokenizer(examples["text"],truncation=True,  # 超过最大长度时截断padding=False,  # 不填充,使用数据整理器进行动态填充max_length=512  # 最大序列长度)# 应用分词函数到整个数据集
tokenized_dataset = dataset.map(tokenizer_function, batched=True)
print(tokenized_dataset)# 创建数据整理器,用于动态填充和准备训练批次
data_collector = DataCollatorForLanguageModeling(tokenizer,mlm=False,              # 禁用掩码语言建模(使用因果语言建模)pad_to_multiple_of=8,   # 填充到8的倍数,优化硬件性能return_tensors="pt"     # 返回PyTorch张量
)# 7. 初始化Trainer类,封装整个训练流程
trainer = Trainer(model=model,                    # 要训练的模型train_dataset=tokenized_dataset, # 训练数据集processing_class=tokenizer,     # 分词器类args=training_arguments,        # 训练参数data_collator=data_collector    # 数据整理器
)# 8. 开始训练!
trainer.train()# 9. 保存适配器权重(只需保存LoRA权重,文件非常小)
trainer.model.save_pretrained("./results/openchat-qlora-adapter")

1. 使用4bit量化加载模型了,为什么还要 prepare_model_for_kbit_training

简短回答:
“4bit加载”只是推理/初始化阶段的内存压缩;而 prepare_model_for_kbit_training 是为在量化权重上进行反向传播训练所做的必要准备。

✅ 详细解释:
  • 当你用 BitsAndBytesConfig(load_in_4bit=True) 加载模型时:

    • 模型权重以 4bit 量化形式存储在显存中,大幅减少显存占用。
    • 但 前向传播时会动态反量化成 bfloat16(或 float16)进行计算
    • 这是 推理友好型量化(inference-time quantization)
  • 然而,在 训练阶段,我们需要对模型做梯度更新。如果直接在量化权重上训练,梯度计算不稳定,甚至无法收敛。

  • 所以 prepare_model_for_kbit_training(model) 做了以下几件事:

    1. 启用梯度检查点(Gradient Checkpointing):节省显存。
    2. 设置模块的 requires_grad = True:确保 LoRA 层可以训练。
    3. 添加可学习的残差连接(如适配器层)到量化层
    4. 冻结原始量化权重(不更新主权重),只训练 LoRA 适配器。
    5. 确保输入嵌入层(input embedding)可训练(有些模型默认冻结)。

📌 总结:

load_in_4bit=True 是为了 节省显存加载模型
prepare_model_for_kbit_training 是为了让模型 支持在量化权重基础上进行 LoRA 微调,属于训练流程的一部分。


🔹 2. 计算时使用 bfloat16 是意味着每次都要反量化吗?

✅ 是的,每次前向/反向传播都会动态反量化

📌 原理说明:
  • BitsAndBytes 的 4bit 量化(如 NF4)是一种 离线量化存储 + 在线反量化计算 的策略。
  • 权重以 4bit 存储,但在前向传播(forward pass)时:
    • 系统会将 4bit 权重 实时反量化为 bfloat16(或 float16)
    • 然后与输入张量进行矩阵乘法运算(使用 GPU 的 Tensor Core 加速)。
  • 反向传播时,只更新 LoRA 参数,原始 4bit 权重 保持不变(冻结)。

🎯 优点:

  • 显存占用低(仅 4bit 存储)。
  • 计算精度高(bfloat16 支持训练稳定性)。
  • 训练效率高(只训练小部分 LoRA 参数)。

📌 所以:

bnb_4bit_compute_dtype=torch.bfloat16 就是告诉系统:“虽然我用 4bit 存权重,但算的时候请用 bfloat16 精度”


🔹 3. tokenizer.pad_token = tokenizer.eos_token 有什么用?

✅ 用于 批次处理(batching)时的填充(padding)

🧩 背景知识:
  • 在训练时,一个 batch 中的样本长度不同,必须统一长度才能堆叠成 tensor。
  • 方法是:短的句子用 pad_token 填充到最大长度
  • 但很多语言模型(如 GPT 系列)没有定义 pad_token,只有 eos_token(结束符)。
❗问题:
  • 如果强行 padding,模型会把 pad token 当作有效 token 处理,影响训练。
✅ 解决方案:
 

Python

编辑

tokenizer.pad_token = tokenizer.eos_token
  • 把 pad_token 设为 eos_token,意味着:
    • 填充部分等价于 “句子结束”。
    • 模型知道这些位置不需要预测或关注(注意力 mask 也会屏蔽)。

📌 为什么重要?

  • 避免模型误认为 padding 是语义内容。
  • 兼容因果语言建模(Causal LM)任务,防止在 padding 上计算 loss。

🔹 4. prepare_model_for_kbit_training 到底干了什么?

✅ 它是一个预处理函数,为 在量化模型上进行微调 做准备。

🛠️ 主要功能包括:
功能说明
1. 梯度检查点(Gradient Checkpointing)减少显存占用,牺牲少量计算时间
2. 启用 input embeddings 的梯度有些模型默认冻结词嵌入层,需手动开启
3. 设置 requires_grad_(True)确保后续插入的 LoRA 层可以训练
4. 保持量化权重冻结主权重不参与更新,只训练 LoRA
5. 兼容性修复处理某些层在量化下的异常行为

📌 举例:

model = prepare_model_for_kbit_training(model)

等价于:

model.gradient_checkpointing_enable()  # 开启梯度检查点
model.enable_input_require_grads()     # 确保嵌入层可训练

⚠️ 如果跳过这一步,可能会导致:

  • 显存不足
  • 梯度无法回传
  • LoRA 不生效

🔹 5. LoRA 的 r 和 lora_alpha 的关系公式是什么?

✅ LoRA 的输出是:

ℎ=��+��⋅���h=Wx+rα​⋅BAx

其中:

  • �W:原始权重(冻结)
  • ��BA:低秩分解矩阵(�∈��×�,�∈��×�A∈Rr×d,B∈Rd×r)
  • �r:LoRA 秩(rank),控制适配器大小
  • �α:缩放系数(lora_alpha
📌 关键点:
  • 缩放因子是 ��rα​,所以:

    • 当 r 增大 → 适配器表达能力增强,但缩放变小 → 实际影响减弱
    • 当 alpha 增大 → 适配器影响增强
  • 通常设置 lora_alpha = 2 * rlora_alpha = 32 是经验值。

✅ 举例:
r=16, lora_alpha=32 → 缩放因子 = 32 / 16 = 2.0

表示 LoRA 分支的输出会被放大 2 倍后再加到原始输出上。

📌 经验建议:

  • r 小 → 参数少、轻量,但表达能力弱
  • alpha 大 → 更强调 LoRA 调整,但可能过拟合
  • 通常 alpha/r ≈ 2 是常见配置(如 r=8, alpha=16)

🔹 6. 除了 get_peft_model(model, peft_config),还有其他方法应用 LoRA 吗?

✅ 有!但 get_peft_model 是最推荐的方式。

✅ 方法一:get_peft_model(推荐)
model = get_peft_model(model, peft_config)
  • 自动根据 peft_config 插入 LoRA 层。
  • 支持多种 PEFT 方法(LoRA、AdaLoRA、IA³ 等)。
  • 易于保存/加载适配器。
✅ 方法二:手动定义 LoRA 层(不推荐)

你可以自己写一个包装类,替换 nn.LinearLoraLinear,但这非常繁琐且容易出错。

✅ 方法三:使用 peft.LoraModel 类(底层 API)
from peft import LoraModel, LoraConfig
lora_model = LoraModel(peft_config, model)

功能类似,但 get_peft_model 更高层、更易用。

✅ 方法四:使用 transformers 集成方式(Hugging Face 新版本)

某些版本支持直接在 from_pretrained(..., peft_config=...) 中传入,但仍在发展中。

📌 结论:

get_peft_model 是目前最标准、最安全、最通用的方法,无需替换。


🔹 7. 分页 AdamW(paged_adamw_32bit)是什么?

✅ 是一种 防止 GPU 内存碎片化 的优化版 AdamW 优化器。

🧩 问题背景:
  • AdamW 为每个可训练参数维护两个状态(momentum 和 variance),占用 2× 显存。
  • 训练中频繁分配/释放显存会导致 内存碎片,最终 OOM(即使总显存足够)。
✅ 解决方案:NVIDIA 的 Page Allocator
  • paged_adamw_32bit 使用 分页内存管理(类似操作系统虚拟内存)。
  • 把优化器状态分配在连续的“页面”上,避免碎片。
  • 即使显存不连续,也能拼接使用。
✅ 优势:
优点说明
防止 OOM即使有碎片也能分配内存
提高稳定性尤其适合长时间训练
支持大 batch更高效利用显存

📌 使用前提:

  • 需要安装 accelerate>=0.12.0 和 bitsandbytes
  • 推荐搭配 optim="paged_adamw_32bit"

🔹 8. tokenizer_function 是不是相当于在进行位置编码?为什么要用 map 包裹?

❌ 不是位置编码。它只是 分词 + 编码成 ID 序列

✅ tokenizer_function 做了什么?
def tokenizer_function(examples):return tokenizer(examples["text"], truncation=True, padding=False, max_length=512)
  • 输入:一批文本(examples["text"]
  • 输出:每个文本对应的 input_idsattention_mask 等
  • 不包含位置编码:位置编码是在模型内部(如 Transformer 的 pos_emb)自动添加的。
✅ 为什么用 .map()

tokenized_dataset = dataset.map(tokenizer_function, batched=True)
  • .map() 是 datasets.Dataset 的方法,用于 对整个数据集批量预处理
  • batched=True 表示一次处理多个样本,效率更高。
  • 结果是:每个样本变成 {"input_ids": [...], "attention_mask": [...], "labels": [...]}

📌 为什么这样做?

  • 避免训练时实时 tokenize(太慢)
  • 提前把文本转为模型可读的 token ID
  • 支持快速随机访问(dataset[i] 直接返回 tokenized 结果)
✅ 与位置编码的关系?
  • 位置信息由模型内部处理。
  • 你只需要提供 input_ids 和 attention_mask
  • 模型会根据 input_ids 的长度自动添加位置编码。

✅ 总结:关键点回顾

问题核心答案
4bit加载后为何还要处理?为训练做准备(梯度、检查点、嵌入层等)
计算用 bfloat16 是否反量化?是,每次前向/反向都动态反量化
pad_token = eos_token 作用?批次填充时不干扰语义,兼容 CLM
prepare_model_for_kbit_training启用梯度检查点、确保可训练性
r 和 lora_alpha 关系?缩放因子为 alpha / r,控制 LoRA 影响力
其他应用 LoRA 方法?有但不推荐,get_peft_model 最佳
分页 AdamW?防止显存碎片,提升训练稳定性
tokenizer_function 是位置编码?否,只是分词;map 用于预处理加速
http://www.dtcms.com/a/490467.html

相关文章:

  • 国内做设计的网站做视频素材哪个网站好
  • WebGIS包括哪些技术栈?
  • Python全栈(基础篇)——Day13:后端内容(模块详解)
  • 科创企业品牌营销:突破与发展之路
  • Spring Boot 3零基础教程,Spring Boot 指定日志文件位置,笔记21
  • 腾讯云如何建设网站首页北京网站建设联系电话
  • 【JWT漏洞】
  • 2025年10月版集成RagFlow和Dify的医疗知识库自动化查询(安装篇)
  • 苏州手机网站建设多少钱上海小程序定制公司
  • YOLO-V1 与 YOLO-V2 核心技术解析:目标检测的迭代突破
  • HarmonyOS Next 实战技巧集锦
  • 【鸿蒙进阶-7】鸿蒙与web混合开发
  • HarmonyOS Next 快速参考手册
  • 8.list的模拟实现
  • 鸿蒙NEXT按键拦截与监听开发指南
  • 网站建设等级定级企查查官网查企业网页版
  • 【数据结构】基于Floyd算法的最短路径求解
  • 【传感器技术】入门红外传感器技术
  • 成都哪里做网站便宜郴州新网招聘官网
  • 天地一体:卫星互联网与5G/6G的融合之路
  • BCH码编译码仿真与误码率性能分析
  • 5G+AIoT智赋,AI电力加密边缘网关智慧电网数字化运维解决方案
  • 深度学习:PyTorch Lightning,训练流程标准化?
  • 100G 单纤光模块:高带宽传输新选择,选型与应用全解析
  • 网站开发的技术有gis网站开发实战教程
  • 汕头网站建设技术外包模板网站怎么用
  • 2025-10-16-TH 开源框架JeecgBoot Pro搭建流程
  • 二叉树搜索树插入,查找,删除,Key/Value二叉搜索树场景应用+源码实现
  • 2025年10月版集成RagFlow和Dify的医疗知识库自动化查询(数据篇)
  • UVa 12803 Arithmetic Expressions