shuxueslpi / chatGLM-6B-QLoRA

使用peft库,对chatGLM-6B/chatGLM2-6B实现4bit的QLoRA高效微调,并做lora model和base model的merge及4bit的量化(quantize)。
356 stars 46 forks source link

qlora 微调效果 #4

Open yxk9810 opened 1 year ago

yxk9810 commented 1 year ago

hi,你好请问有没有adgen上的Qlora在验证集上的效果比如rouge-l 、blue ,效果会比p-tuning好么?

shuxueslpi commented 1 year ago

@wujindou 这块我还没有时间去做,关于哪种微调方式更好,可能不同数据集会有不同表现吧。

yxk9810 commented 1 year ago

嗯,多谢~,我试试看

2512309z commented 1 year ago

@wujindou 这块我还没有时间去做,关于哪种微调方式更好,可能不同数据集会有不同表现吧。

我微调以后效果很差,我执行了merge chatglm2和qlora,然后修改了model path ,启动web以后,发现以下问题:

  1. 有出现 ... 和缺字的情况
  2. chatglm2本身最基础的能力都丢失了,无论你问什么,比如一些简单提问,它的回答全是我的训练数据集里面的问题
  3. 语言组织能力几乎为0,基本上都是训练数据里面断断续续出来的答案

是不是我的训练数据集太少了? 或者是需要再多训练几次? 请问我该如何继续优化?

shuxueslpi commented 1 year ago

@wujindou 你的数据集或者任务时什么? 配置文件和启动命令是什么? 可不可以打印出数据和input_ids,看看数据是否有问题? 目前看应该不会出现很离谱的情况,官方issue下有个哥们做了文本纠错的任务训练,效果也还行:https://github.com/THUDM/ChatGLM2-6B/issues/141

2512309z commented 1 year ago

@wujindou 你的数据集或者任务时什么? 配置文件和启动命令是什么? 可不可以打印出数据和input_ids,看看数据是否有问题? 目前看应该不会出现很离谱的情况,官方issue下有个哥们做了文本纠错的任务训练,效果也还行:THUDM/ChatGLM2-6B#141

1.你的数据集或者任务时什么? 我的数据集大部分是这样的 {"instruction": "筛选框说明:\n默认展示“全部部门”,可筛选部门\n全部部门\n1.系统管理员可筛选所有部门数据2.部门排班管理员可筛选被设置为部门管理员的部门", "output": "\n用例标题\n【WEB端】科室管理-部门筛选检查\n前置条件 \n操作步骤:\n1. 点击科室管理菜单\n2. 点击部门下拉框筛选\n3. 点选全部部门、单个部门\n预期结果:\n1. 成功进入科室管理页面\n2. 下拉展示全部部门、单个部门\n3. 列表刷新,展示筛选结果"} \n是换行符的意思。

2.配置文件和启动命令是什么? 什么配置文件?config.jason这个文件吗? 是指qlora的配置文件还是chatglm2的配置文件? 启动命令? 我是按照说明,把chatglm2的webui.py里面的 model指向 训练出来的结果数据文件,我不是很清楚启动命令

shuxueslpi commented 1 year ago

@wujindou 配置文件就是我项目里的chatGLM_6B_QLoRA.json这个文件,启动命令就是训练的启动命令:

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

还有,你的数据集有多少数据量?都是这种医疗软件的说明吗?

另外,你是用merge_lora_and_quantize.py把lora model和base model合并了吧,这块排查问题的话,可以先不用webui,直接在ipython这种交互窗口里像下面这样试试吗?

from transformers import AutoModel, AutoTokenizer

model_path = '/tmp/merged_qlora_model_4bit'

tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModel.from_pretrained(model_path, trust_remote_code=True).half().cuda()

input_text = '类型#裙*版型#显瘦*风格#文艺*风格#简约*图案#印花*图案#撞色*裙下摆#压褶*裙长#连衣裙*裙领型#圆领'
response, history = model.chat(tokenizer=tokenizer, query=input_text)
print(response)
2512309z commented 1 year ago

配置文件就是我项目里的chatGLM_6B_QLoRA.json这个文件,启动命令就是训练的启动命令:

python3 train_qlora.py --train_args_json chatGLM_6B_QLoRA.json \ --模型名称或路径THUDM/chatglm-6 b\ --train_data_path data/train.jsonl \ --eval_data_path data/dev.jsonl \ --lora_rank 4 \ --lora_dropout 0.05 \ --compute_dtype fp32

还有,你的数据集有多少数据量?都是这种医疗软件的说明吗?

另外,你是用merge_lora_and_quantize.py把lora model和base model合并了吧,这块排查问题的话,可以先不用webui,直接在ipython这种交互窗口里像下面这样试试吗?

从转换器导入AutoModel、AutoTokenizer

model_path = '/tmp/merged_qlora_model_4bit'

tokenizer = AutoTokenizer.from_pretrained(model_path,trust_remote_code=True) model = AutoModel.from_pretrained(model_path,trust_remote_code=True).half().cuda()

input_text = '类型#裙版型#显瘦风格#文艺风格#简约图案#印花图案#撞色裙下摆#压褶裙长#连衣裙裙领型#圆领' response,history = model.chat(tokenizer=tokenizer,query=input_text) print(response)

这是我的chatGLM_6B_QLoRA.json文件 { “output_dir”:“saved_files/chatGLM_6B_QLoRA_t32”, “per_device_train_batch_size”:1, ———————————-这里如果改为2或者4的话,会出现out of memory “gradient_accumulation_steps”:8, “per_device_eval_batch_size”:1, ———————————-这里如果改为2或者4的话,会出现out of memory “learning_rate”:1e-2, ----这里我也降低了 “num_train_epochs”:1.0, “lr_scheduler_type”:“linear”, “warmup_ratio”:0.1, “logging_steps”:100, “保存_strategy”:“steps”, “保存_steps”:500, “evaluation_strategy”:“steps”, “eval_steps”:500, “optim”:“adamw_torch”, “fp16”:false, “remove_unused_columns”:false, “ddp_find_unused_parameters”:false, ‘’seed‘’:42

还有,你的数据集有多少数据量?都是这种医疗软件的说明吗?

我的数据集大概1000条的样子,都是类似这种结构的软件说明

--另外,你是用merge_lora_and_quantize.py把lora model和base model合并了吧,这块排查问题的话,可以先不用webui,直接在ipython这种交互窗口里像下面这样试试吗?

是的,我就是把lora model和base model合并了的,然后chatglm2加载的是合并后的/tmp/merged_qlora_model_4bit这个文件

shuxueslpi commented 1 year ago

不知道是不是数据量的问题,因为你的数据看上去即使是我作为一个人来根据instruction输出output似乎也不是那么容易。尤其是你的例子里,instruction并没有提到“科室”这个词……

然后1000条数据,真实的batchsize为8,只能跑100多个step吧。

你可以试试统一加一个prompt前缀,描述你的任务,就是这个参数: parser.add_argument('--prompt_text', type=str, default='', help='统一添加在所有数据前的指令文本') 启动训练时加这个参数,类似这样:

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 \
--prompt_text 请根据以下要求编写软件产品说明文档\n\n

另外你是什么显卡,为什么batchsize1就会OOM?还是说数据有很长的? --compute_dtype fp32 这个参数,我设置为fp16时会出现训练不稳定,loss不下降的情况

shuxueslpi commented 1 year ago

@2512309z 对了,还可以试下,合并lora但不量化,用fp16的模型看看效果

2512309z commented 1 year ago

@2512309z 对了,还可以试下,合并lora但不量化,用fp16的模型看看效果

什么是合并但不量化,不明白,麻烦你详细说一下步骤,谢谢你啊!

2512309z commented 1 year ago

不知道是不是数据量的问题,因为你的数据看上去即使是我作为一个人来根据instruction输出output似乎也不是那么容易。尤其是你的例子里,instruction并没有提到“科室”这个词……

然后1000条数据,真实的batchsize为8,只能跑100多个step吧。

你可以试试统一加一个prompt前缀,描述你的任务,就是这个参数: parser.add_argument('--prompt_text', type=str, default='', help='统一添加在所有数据前的指令文本') 启动训练时加这个参数,类似这样:

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 \
--prompt_text 请根据以下要求编写软件产品说明文档\n\n

另外你是什么显卡,为什么batchsize1就会OOM?还是说数据有很长的? --compute_dtype fp32 这个参数,我设置为fp16时会出现训练不稳定,loss不下降的情况

谢谢你耐心解答,我的训练数据确实是有很长的情况,我大概明白你的意思了,如果需要更准确的输出,就得把输入截断,然后将想要的对应输出相结合,组成一条训练数据,不知道我的理解对不对?

另外我的显卡是3张 16G teslaA100,可能就是因为单条训练数据太长的原因导致OOM的

shuxueslpi commented 1 year ago

@2512309z 对了,还可以试下,合并lora但不量化,用fp16的模型看看效果

什么是合并但不量化,不明白,麻烦你详细说一下步骤,谢谢你啊!

就是训练后执行

python3 merge_lora_and_quantize.py \
    --lora_path saved_files/chatGLM2_6B_QLoRA_t32 \
    --output_path /tmp/qlora-model2 \
    --remote_scripts_dir remote_scripts/chatglm2-6b \
    --qbits 0

会得到一个完整的merge后的fp16模型

shuxueslpi commented 1 year ago

不知道是不是数据量的问题,因为你的数据看上去即使是我作为一个人来根据instruction输出output似乎也不是那么容易。尤其是你的例子里,instruction并没有提到“科室”这个词…… 然后1000条数据,真实的batchsize为8,只能跑100多个step吧。 你可以试试统一加一个prompt前缀,描述你的任务,就是这个参数: parser.add_argument('--prompt_text', type=str, default='', help='统一添加在所有数据前的指令文本') 启动训练时加这个参数,类似这样:

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 \
--prompt_text 请根据以下要求编写软件产品说明文档\n\n

另外你是什么显卡,为什么batchsize1就会OOM?还是说数据有很长的? --compute_dtype fp32 这个参数,我设置为fp16时会出现训练不稳定,loss不下降的情况

谢谢你耐心解答,我的训练数据确实是有很长的情况,我大概明白你的意思了,如果需要更准确的输出,就得把输入截断,然后将想要的对应输出相结合,组成一条训练数据,不知道我的理解对不对?

另外我的显卡是3张 16G teslaA100,可能就是因为单条训练数据太长的原因导致OOM的

16G的显存应该是够的,不知道你的太长到底是多长…… 一般一条数据就是一个输入+一个输出啊,除非你是做多轮对话,那会有一些其他组织数据的方式

2512309z commented 1 year ago

不知道是不是数据量的问题,因为你的数据看上去即使是我作为一个人来根据instruction输出output似乎也不是那么容易。尤其是你的例子里,instruction并没有提到“科室”这个词…… 然后1000条数据,真实的batchsize为8,只能跑100多个step吧。 你可以试试统一加一个prompt前缀,描述你的任务,就是这个参数: parser.add_argument('--prompt_text', type=str, default='', help='统一添加在所有数据前的指令文本') 启动训练时加这个参数,类似这样:


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 \
--prompt_text 请根据以下要求编写软件产品说明文档\n\n

另外你是什么显卡,为什么batchsize1就会OOM?还是说数据有很长的? --compute_dtype fp32 这个参数,我设置为fp16时会出现训练不稳定,loss不下降的情况

谢谢你耐心解答,我的训练数据确实是有很长的情况,我大概明白你的意思了,如果需要更准确的输出,就得把输入截断,然后将想要的对应输出相结合,组成一条训练数据,不知道我的理解对不对? 另外我的显卡是3张 16G teslaA100,可能就是因为单条训练数据太长的原因导致OOM的

16G的显存应该是够的,不知道你的太长到底是多长…… 一般一条数据就是一个输入+一个输出啊,除非你是做多轮对话,那会有一些其他组织数据的方式

谢谢你啊 ,我所谓的太长意思是,我的输入和输出都很长,导致一条训练数据就很长,我暂时没有时间精力去研究多轮对话

2512309z commented 1 year ago

@2512309z 对了,还可以试下,合并lora但不量化,用fp16的模型看看效果

什么是合并但不量化,不明白,麻烦你详细说一下步骤,谢谢你啊!

就是训练后执行

python3 merge_lora_and_quantize.py \
    --lora_path saved_files/chatGLM2_6B_QLoRA_t32 \
    --output_path /tmp/qlora-model2 \
    --remote_scripts_dir remote_scripts/chatglm2-6b \
    --qbits 0

会得到一个完整的merge后的fp16模型

我就是按照你的这个步骤做的,merge以后,就直接用chatglm2去使用合并后的模型,并没有量化,难道是因为我没有量化,导致效果不好吗?

wisper181 commented 1 year ago

@2512309z 对了,还可以试下,合并lora但不量化,用fp16的模型看看效果

什么是合并但不量化,不明白,麻烦你详细说一下步骤,谢谢你啊!

就是训练后执行

python3 merge_lora_and_quantize.py \
    --lora_path saved_files/chatGLM2_6B_QLoRA_t32 \
    --output_path /tmp/qlora-model2 \
    --remote_scripts_dir remote_scripts/chatglm2-6b \
    --qbits 0

会得到一个完整的merge后的fp16模型

请问想得到不量化的模型的时候,在训练时需要修改train.py里面的参数嘛?我看默认脚本在训练时也有量化步骤:

Quantization

q_config = BitsAndBytesConfig(load_in_4bit=True,
                              bnb_4bit_quant_type='nf4',
                              bnb_4bit_use_double_quant=True,
                              bnb_4bit_compute_dtype=_compute_dtype_map[global_args.compute_dtype])

model = AutoModel.from_pretrained(global_args.model_name_or_path,
                                  quantization_config=q_config,
                                  device_map='auto',
                                  trust_remote_code=True)