ChatGLM-6B微调实践与问题汇总(fine-tune+p-tuning+知识遗忘解决尝试)

在这里插入图片描述

ChatGLM-6B微调实践与问题汇总(fine-tune+p-tuning+知识遗忘解决尝试)

1.介绍

ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。在模型量化技术的加持下,INT4 量化级别下显存占用不到6G,满足一些消费级显卡部署的需要。

https://github.com/THUDM/ChatGLM-6B.git

本文只涉及对官方仓库中模型参数全量fine-tune和p-tuning方案的复现,以及对p-tuning训练后,模型对旧知识遗忘现象的优化。

训练后,丧失了原有的对话功能的优化可直接调到第5节

2.软硬件环境

硬件平台

cpu:Inter Xeon Gold 6130 x2

GPU:Tesla V100 16G x8

预训练模型

chatglm-6B

数据集

adgen

软件环境

deepspeed==0.9.2	
protobuf	
transformers==4.28.1(不建议用requirements中的4.27.1版本,不要问我怎么知道的)	
cpm_kernels	
torch>=1.10	
gradio	
mdtex2html	
sentencepiece	
accelerate	
rouge_chinese 	
nltk 	
jieba 	
datasets
3.模型与数据集下载

模型

https://huggingface.co/THUDM/chatglm-6b

数据集

下载处理好的 ADGEN 数据集 https://cloud.tsinghua.edu.cn/f/b3f119a008264b1cabd1/?dl=1,将解压后备用。

4.训练

训练操作过程参考https://github.com/THUDM/ChatGLM-6B/blob/main/ptuning/README.md

4.1 fine-tune

脚本:

ds_train_finetune.sh

LR=1e-4

MASTER_PORT=$(shuf -n 1 -i 10000-65535)

deepspeed --num_gpus=4 --master_port $MASTER_PORT main.py \
    --deepspeed deepspeed.json \
    --do_train \
    --train_file AdvertiseGen/train.json \
    --test_file AdvertiseGen/dev.json \
    --prompt_column content \
    --response_column summary \
    --overwrite_cache \
    --model_name_or_path THUDM/chatglm-6b \
    --output_dir ./output/adgen-chatglm-6b-ft-$LR \
    --overwrite_output_dir \
    --max_source_length 64 \
    --max_target_length 64 \
    --per_device_train_batch_size 4 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 1 \
    --predict_with_generate \
    --max_steps 5000 \
    --logging_steps 10 \
    --save_steps 1000 \
    --learning_rate $LR \
    --fp16

官方给出的deepspeed配置文件为zero stage2,由于本服务器单卡显存较低,需要使用ZeRO stage3 + offload cpu。

新建deepspeed配置文件:deepspeed_zero3_config.json

{
	"gradient_accumulation_steps":"auto",
    "train_micro_batch_size_per_gpu": "auto",
    "zero_allow_untested_optimizer": true,
    "fp16": {
      "enabled": "auto",
      "loss_scale": 0,
      "initial_scale_power": 16,
      "loss_scale_window": 1000,
      "hysteresis": 2,
      "min_loss_scale": 1
    },
    "bf16": {
      "enabled": "auto"
  },
  "optimizer": {
    "type": "AdamW",
    "params": {
        "lr": "auto",
        "betas": "auto",
        "eps": "auto",
        "weight_decay": "auto"
    }
  },
    "zero_optimization": {
      "stage": 3,
      "offload_optimizer": {
        "device": "cpu",
        "pin_memory": true
    },
    "offload_param": {
        "device": "cpu",
        "pin_memory": true
    },
      "allgather_partitions": true,
      "allgather_bucket_size": 5e8,
      "reduce_scatter": true,
      "contiguous_gradients" : true,
      "overlap_comm": true,
      "sub_group_size": 1e9,
      "reduce_bucket_size": "auto",
      "stage3_prefetch_bucket_size": "auto",
      "stage3_param_persistence_threshold": "auto",
      "stage3_max_live_parameters": 1e9,
      "stage3_max_reuse_distance": 1e9,
      "stage3_gather_16bit_weights_on_model_save": true
    }
  }

实际训练时需对如下两个参数进行调整

--num-gpus 8 
--deepspeed deepspeed_zero3_config.json 

训练过程资源利用情况

cpumenGPU显存
8*550%8*4.4%50%-100%8*(14.8-16G)

GPU利用率波动较大

训练时长

31h11min

针对ADGEN数据集的评价指标

脚本 ptuning/evaluate_finetune.sh

Bleu-4: 8.6162

rouge-1: 30.7453

rouge-2: 7.6246

rouge-1: 24.832

4.2 p-tuning

训练脚本 train.sh

PRE_SEQ_LEN=128
LR=2e-2

CUDA_VISIBLE_DEVICES=0 python3 main.py \
    --do_train \
    --train_file AdvertiseGen/train.json \
    --validation_file AdvertiseGen/dev.json \
    --prompt_column content \
    --response_column summary \
    --overwrite_cache \
    --model_name_or_path THUDM/chatglm-6b \
    --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \
    --overwrite_output_dir \
    --max_source_length 64 \
    --max_target_length 64 \
    --per_device_train_batch_size 1 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --predict_with_generate \
    --max_steps 3000 \
    --logging_steps 10 \
    --save_steps 1000 \
    --learning_rate $LR \
    --pre_seq_len $PRE_SEQ_LEN \
    --quantization_bit 4

训练过程资源占用

model Quantized to 8 bit

cpu内存GPU显存
1core100%0.5%80%-100%8500MB

训练总时间:

3h48min

针对ADGEN数据集的评价指标

脚本 :ptuning/evaluate.sh

指标:

Bleu-4: 7.951

rouge-1: 31.520

rouge-2: 7.219

rouge-1: 24.932

5.效果优化,针对”训练后丧失了原有的对话功能“

根据4中的步骤完成训练后,模型在广告生成效果上表现较好(输入:类型#上衣版型#宽松版型#显瘦图案#线条衣样式#衬衫衣袖型#泡泡袖衣款式#抽绳),切两种训练方式得到的模型效果类似。但是在常规的问答或其他任务中,丧失了原有的对话功能,出现了对旧知识遗忘的现象。

https://github.com/THUDM/ChatGLM-6B/issues/1148

所以后续尝试对两种训练方式的训练超参数进行调整:

fine-tune

学习率调整为1e-6 (原始为1e-4),其他参数不变

模型在训练step=2000时,训练收敛,提前结束训练

模型在广告生成和原始对话功能的表现都正常

实际效果如下:

command :( input something or press Ctrl + c to exit ...)
马掉进海里会变成海马么
马掉进海里不会变成海马。马是一种哺乳动物,属于鸮形目,而海马是海龙的别称,属于腔肠动物门。它们是不同的生物,所以马掉进海里不会变成海马。
time consume :2135.13ms, and speed :31.398970588235297 ms / word 
command :( input something or press Ctrl + c to exit ...)
类型#上衣*材质#丹宁*颜色#白色*风格#简约*图案#刺绣*衣样式#外套*衣款式#破洞
这件简约而不简单的丹宁外套,采用白色作为基调,将丹宁外套的硬朗气质与白色调的柔和气息相结合,演绎出时尚与干练兼具的都市摩登感。领口、袖口、下摆以及门襟处的破洞设计,在带来个性时尚的同时,也赋予了外套
time consume :2942.03ms, and speed :29.71747474747475 ms / word 
command :( input something or press Ctrl + c to exit ...)
老鼠病了可用吃老鼠药么
不建议使用老鼠药来治疗老鼠病。老鼠药通常是用于杀死老鼠或其他害虫,而不是治疗它们的疾病。使用老鼠药可能会导致其他动物的伤害或死亡,并可能违反当地的动物保护法律。
如果老鼠生病了,建议寻求兽医的帮助。兽医可以通过检查和诊断来找出老鼠病的根本原因,并采取适当的治疗措施来治愈它。
time consume :3605.08ms, and speed :26.123768115942028 ms / word 
command :( input something or press Ctrl + c to exit ...)
下岗和下海有啥区别
下岗指的是在原公司、单位或者行业失业后选择再就业的情况;下海指的是离开原来的工作,自己创业当老板的情况。两者的主要区别在于就业方向和创业方式的不同。
time consume :1790.36ms, and speed :24.194054054054053 ms / word
p-tuning

学习率调整为1e-4(原始为2e-2),其他参数不变

训练完成后

模型在广告生成和原始对话功能的表现都正常。

针对ADGEN数据集的评价指标:

Bleu-4: 5.6319

rouge-1: 27.1907

rouge-2: 5.0235

rouge-1: 22.4369

实际效果如下:

command :( input something or press Ctrl + c to exit ...)
马掉进海里会变成海马么
马掉进海里不会变成海马,因为马是陆地上的生物,不会变成海洋中的生物。
time consume :1171.6ms, and speed :34.45882352941176 ms / word 
command :( input something or press Ctrl + c to exit ...)
类型#上衣*材质#丹宁*颜色#白色*风格#简约*图案#刺绣*衣样式#外套*衣款式#破洞
这件丹宁外套,采用了简约的直筒款式,搭配白色的刺绣图案,看起来兴起兴起。衣袖处破洞的设计,给这件丹宁外套增加了一点幽默感。
time consume :2121.93ms, and speed :34.78573770491803 ms / word 
command :( input something or press Ctrl + c to exit ...)
老鼠病了可用吃老鼠药么
不建议使用老鼠药来治疗老鼠的疾病。老鼠药通常用于捕捉老鼠,而不是治疗它们。使用老鼠药可能会对老鼠造成伤害,并且可能会导致它们死亡。此外,使用老鼠药来治疗其他动物可能会导致道德和伦理问题。因此,建议不要试图使用老鼠药来治疗老鼠的疾病。
command :( input something or press Ctrl + c to exit ...)
下岗和下海有啥区别
下岗和下海下海是两个不同的概念。下岗指的是失业后重新就业的过程,下海则指的是离开工作岗位,从事其他行业或职业的过程。
从字面上看,下岗指的是离开原工作岗位,下海指的是从事其他行业或职业。但是,下海与下岗的本质区别在于,下海是对原有的工作岗位的放弃,而下岗则是因为原工作岗位的失业


6.资源占用

推理对比

训练方式量化运行显存内存VIRT加载时间推理速度
p-Tuningfp1613197MB0.4%26G13s25-30ms/word
全量fine-Tuningfp1612255MB0.3%24.6G11s25-30ms/word
7.问题与解决

6.1 全量fine-tune时,模型初始化报错“NotImplementedError: Cannot copy out of meta tensor; no data!”

修改main.py:124

model = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True)
改为
model = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True, empty_init=False)
“NotImplementedError: Cannot copy out of meta tensor; no data! 
这个错误通常是由于Deepspeed在使用自定义权重初始化时出现问题,而这些初始化可能需要从先前的训练中加载权重。如果在使用Deepspeed进行分布式训练时出现此错误,则需要在初始化模型时指定`empty_init=False`,以便在加载权重之前,权重矩阵不会被初始化为空。
AutoModel.from_pretrained是Hugging Face Transformers库中的一个方法,用于从预训练模型中加载权重。在Deepspeed分布式训练中,模型的初始化和权重加载可能需要特殊处理,因此需要使用`empty_init=False`参数来指定在加载权重之前不要将权重矩阵初始化为空。
在其他模型中,可能不需要这个参数是因为它们的初始化和权重加载不需要特殊处理,或者因为它们的代码已经进行了相应的修改以适应Deepspeed的分布式训练流程。”

--https://github.com/THUDM/ChatGLM-6B/issues/530
<think>嗯,用户遇到了一个NotImplementedError: cannot remove artist的错误,需要帮助解决。首先,我得弄清楚这个错误通常出现在什么情况下。根据经验,这个错误可能Matplotlib库有关,尤其是在处理图形元素时,比如试图删除一个不支持删除操作的Artist对象。 用户提供的引用中有提到CUDA tensor转换的问题和.pyi文件的信息,但这些似乎当前的错误无关。不过,可能需要确认用户是否在混合使用不同的库,例如在绘图时误操作了张量。但首先,我应该专注于常见的Matplotlib场景。 在Matplotlib中,Artist对象是图形元素的基础类,比如线条、文本、轴等。当用户尝试调用某个移除方法(如remove()或clear())时,如果该Artist类型不支持这些操作,就会抛出NotImplementedError。例如,Figure对象本身不支持直接remove(),而Axes对象可以。 接下来,我需要考虑用户可能的代码情况。可能用户错误地调用了remove()在一个不支持的对象上,比如Figure而不是Axes或具体的绘图元素。或者,用户可能在使用某些高级绘图库时,如seaborn,间接操作了Artist对象。 可能的解决方案包括: 1. 检查调用remove()的对象类型,确保其支持该操作。例如,使用ax.remove()而不是fig.remove()。 2. 使用更安全的方法清除图形,如plt.clf()清除整个图形,或ax.cla()清除轴。 3. 在动态更新图表时,避免重复创建新Artist,而是更新现有对象的属性。 4. 使用面向对象的方法,明确操作特定的Axes或Artist实例。 另外,可能需要查看用户的具体代码片段,但用户没有提供。因此,我需要给出通用的解决步骤,并建议用户检查代码中是否有错误的remove调用,或者尝试替换为其他清除方法。同时,提供一个示例代码来演示正确的做法,比如先获取Axes对象再进行操作,或者使用cla()代替remove()。 最后,确保回答结构清晰,分步骤说明可能的原因和解决方法,并附上示例代码,帮助用户理解和应用解决方案。</think>针对`NotImplementedError: cannot remove artist`错误的修复方法及分析: ### 错误原因 该错误通常在使用Matplotlib绘图时发生,表示尝试删除一个不支持删除操作的`Artist`对象(图形元素)。常见场景包括: 1. 对`Figure`对象直接调用`remove()`方法(如`fig.remove()`) 2. 使用某些第三方绘图库时对底层对象进行非法操作 3. 动态更新图表时错误调用移除方法 ### 解决方案 #### 方法一:使用正确的清除方法 ```python # 清除当前轴 plt.cla() # 清除所有轴内容但保留轴框架 # 或清除整个图形 plt.clf() # 清除所有轴和图形内容 ``` #### 方法二:面向对象操作 ```python fig, ax = plt.subplots() line, = ax.plot([0,1,2], [3,1,4]) # 正确移除特定元素 line.remove() # 移除线条对象 ax.figure.canvas.draw() # 重绘画布 ``` #### 方法三:使用容器管理 ```python class PlotManager: def __init__(self): self.fig, self.ax = plt.subplots() self.lines = [] def update_plot(self, new_data): # 先清除旧的线条 for line in self.lines: line.remove() self.lines.clear() # 添加新线条 new_line, = self.ax.plot(new_data) self.lines.append(new_line) self.fig.canvas.draw_idle() ``` ### 错误预防建议 1. **类型检查**:操作前验证对象类型 ```python if hasattr(artist, 'remove'): artist.remove() else: print(f"{type(artist)} does not support remove()") ``` 2. **使用上下文管理器**: ```python with plt.ion(): # 交互模式 while updating: ax.lines[0].set_ydata(new_data) fig.canvas.draw_idle() plt.pause(0.1) ``` 3. **优先使用更新方法**而非删除重建: ```python line.set_data(new_x, new_y) # 更新现有线条数据 ax.relim() # 重新计算坐标范围 ax.autoscale_view() # 自动缩放视图 ``` ### 典型应用场景示例 ```python import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots() x = np.linspace(0, 2*np.pi, 100) line, = ax.plot(x, np.sin(x)) # 正确更新方式 for phase in np.linspace(0, 2*np.pi, 50): line.set_ydata(np.sin(x + phase)) # 更新数据而非删除 plt.pause(0.1) ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值