# ChatGLM-6B-QLoRA
介绍
本项目使用peft库,实现了ChatGLM-6B/chatGLM2-6B模型4bit的QLoRA高效微调,可以在一张RTX3060上完成全部微调过程。
内容包括:
- 环境配置
- 数据集介绍
- ChatGLM-6B/chatGLM2-6B的QLoRA训练完整流程
- ChatGLM-6B/chatGLM2-6B的推理流程
- 使用adapter做推理
- 合并adapter和basemodel做推理
- 量化合并后的模型做推理
- 推理性能测试
- QLoRA微调前后的效果比对
特别说明:
无特别理由,强烈推荐使用chatGLM2-6B,理由如下:
- chatGLM2-6B的推理效率比chatGLM-6B快30%~50%,见本文档
5. 推理性能测试章节 - chatGLM2-6B在微调前的输出质量就远高于chatGLM-6B,微调后的loss值更低
- chatGLM2-6B几乎没有灾难性疑问的情况,微调后对数据集外的问题仍然能输出高质量的答案,不过也有人反馈会陷入重复回答的问题
- chatGLM2-6B和1代模型比,目前微调或推理时的显存占用应该差别不大,如果出现微调时显存占用明显大于1代模型,请拉取最新的2代模型,尤其是里面的脚本文件
关于模型训练后使用int4的方式进行推理:
- 目前官方的量化方法在
merge_lora_and_quantize.py中已经集成,但有反馈表示量化后存在一定性能损失 - 还有一种方式是使用
merge_lora_and_quantize.py脚本合成base model和lora model,但是不做量化处理,将保存fp16的模型,使用此模型时,以int4的方式加载,进行推理(加载方法同训练脚本中的代码) - 2中的方法目前应该比1的方法在准确性的损失上要小一些,但两种方式都是降低显存的同时增加响应延时,并没有加快推理速度,见
5. 推理性能测试章节
环境配置
环境依赖
- CUDA >= 11.7
- python依赖项
peft==0.4.0 transformers==4.30.2 datasets==2.12.0 tqdm==4.65.0 loguru==0.7.0 fire==0.5.0 bitsandbytes==0.39.0 wandb==0.15.3 cpm_kernels==1.0.11 accelerate==0.20.3 sentencepiece==0.1.99
推荐环境
推荐使用docker镜像,如下:
GPT plus 代充 只需 145docker pull huggingface/transformers-pytorch-gpu:4.29.1 docker run -tid -v /your/data/path:/home -p 58323:58323 --gpus all huggingface/transformers-pytorch-gpu:4.29.1 # 上面命令中的 -p 58323:58323 如果你想用tensorboard查看训练过程,需要映射一个端口出来 # 进入容器 docker exec -ti container_name /bin/bash
进入容器后,执行:
python3 -m pip install --upgrade pip pip install -q -U bitsandbytes pip install peft==0.4.0 pip install transformers==4.30.2 pip install accelerate==0.20.3
注:理论上更高版本的transformers库应该可以正常运行本项目。
数据集介绍
数据集使用ADGEN广告数据集,任务为根据instruction生成一段广告词,见本项目data文件夹,每条样本为一行,形式为:
GPT plus 代充 只需 145{ "instruction": "类型#裤*版型#宽松*风格#性感*图案#线条*裤型#阔腿裤", "output": "宽松的阔腿裤这两年真的吸粉不少,明星时尚达人的心头爱。毕竟好穿时尚,谁都能穿出腿长2米的效果宽松的裤腿,当然是遮肉小能手啊。上身随性自然不拘束,面料亲肤舒适贴身体验感棒棒哒。系带部分增加设计看点,还让单品的设计感更强。腿部线条若隐若现的,性感撩人。颜色敲温柔的,与裤子本身所呈现的风格有点反差萌。" }
其中训练数据train.jsonl共计条,验证数据dev.jsonl共计1070条。
训练流程
进入本项目目录,训练启动命令如下:
python3 train_qlora.py --train_args_json chatGLM_6B_QLoRA.json --model_name_or_path THUDM/chatglm-6b --train_data_path data/train.jsonl --eval_data_path data/dev.jsonl --lora_rank 4 --lora_dropout 0.05 --compute_dtype fp32
训练chatGLM2-6B只要修改model_name_or_path参数为THUDM/chatglm2-6b.
其中chatGLM_6B_QLoRA.json文件为所有transformers框架支持的TrainingArguments,参考:https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments
默认如下,可根据实际情况自行修改:
GPT plus 代充 只需 145{ "output_dir": "saved_files/chatGLM_6B_QLoRA_t32", "per_device_train_batch_size": 4, "gradient_accumulation_steps": 8, "per_device_eval_batch_size": 4, "learning_rate": 1e-3, "num_train_epochs": 1.0, "lr_scheduler_type": "linear", "warmup_ratio": 0.1, "logging_steps": 100, "save_strategy": "steps", "save_steps": 500, "evaluation_strategy": "steps", "eval_steps": 500, "optim": "adamw_torch", "fp16": false, "remove_unused_columns": false, "ddp_find_unused_parameters": false, "seed": 42 }
对参数compute_type,可选fp16, bf16和fp32,实测使用fp16, bf16这两种计算速度有明显提升,相同的epoch只需要大约一半的时间,但出现loss收敛较慢的情况,默认选择fp32.
关于这个参数的选择,可能需要根据数据集做不同的尝试。
训练截图(chatGLM-6B)
- 显存占用,batch_size = 4

- chatGLM-6B的loss曲线,训练一个epoch,可以看到loss还在下降

经过实测在训练一个epoch的情况下,chatGLM-6B的loss在3.4左右,chatGLM2-6B的loss可以到2.9
默认会在saved_files/chatGLM_6B_QLoRA_t32文件夹中生成一个runs的文件夹,可进入saved_files/chatGLM_6B_QLoRA_t32文件夹,用以下命令启动tensorboard,查看训练曲线:
tensorboard --logdir runs --port 'your port' --bind_all
模型推理
训练过程会保存adapter的checkpoint及最终的adapter文件,默认配置下chatGLM-6B每个文件的情况如下:
GPT plus 代充 只需 145-rw-r--r-- 1 root root 417 Jun 2 21:14 adapter_config.json -rw-r--r-- 1 root root 7.1M Jun 2 21:14 adapter_model.bin -rw-r--r-- 1 root root 15M Jun 2 21:14 optimizer.pt -rw-r--r-- 1 root root 15K Jun 2 21:14 rng_state.pth -rw-r--r-- 1 root root 627 Jun 2 21:14 scheduler.pt -rw-r--r-- 1 root root 2.0K Jun 2 21:14 trainer_state.json -rw-r--r-- 1 root root 3.9K Jun 2 21:14 training_args.bin
保存的adapter只有约7M的大小。
使用adapter推理
推理代码如下:
import torch from transformers import AutoModel, AutoTokenizer, BitsAndBytesConfig from peft import PeftModel, PeftConfig peft_model_path = 'saved_files/chatGLM_6B_QLoRA_t32' config = PeftConfig.from_pretrained(peft_model_path) q_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type='nf4', bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=torch.float32) base_model = AutoModel.from_pretrained(config.base_model_name_or_path, quantization_config=q_config, trust_remote_code=True, device_map='auto') input_text = '类型#裙*版型#显瘦*风格#文艺*风格#简约*图案#印花*图案#撞色*裙下摆#压褶*裙长#连衣裙*裙领型#圆领' print(f'输入: {input_text}') tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path, trust_remote_code=True) response, history = base_model.chat(tokenizer=tokenizer, query=input_text) print(f'微调前: {response}') model = PeftModel.from_pretrained(base_model, peft_model_path) response, history = model.chat(tokenizer=tokenizer, query=input_text) print(f'微调后: {response}')
合并Lora model和base model、量化模型推理
首先需要说明,本项目目前使用的peft为dev的版本,在合并lora model和base model时,会报错,见https://github.com/huggingface/peft/pull/535
因此要�
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/243723.html