- 最近在参加:2023AIWIN——中文网页自动导航挑战赛
- DataWhale的大佬们提供了baseline的讲解:如何手把手打一场世界人工智能大赛
- 下面就来记录一下使用Kaggle上提供的30小时15G免费GPU算力的运行情况。
数据集预处理
数据下载及配置
- 首先从比赛官网上下载A榜的数据集:获取数据
- 在本地解压缩后,进入到路径:
\2023S-T1-A-Data[供选手] 0513\指令数据&标签
,找到我们的训练集测试集数据和标签,共有3个.json
文件。 - 将这3个文件打包上传至Kaggle上。
- 进入到
jupyter notebook
环境中,配置好数据集,效果如下:
数据处理
- 生成训练集和验证集
import json
import pandas as pd
import re
from collections import defaultdict, Counter
from bs4 import BeautifulSoup
# 配置文件路径,读取数据集
LABEL_PATH = '/kaggle/input/web-auto-navigation-dataset/'
label_trainset = json.load(open(LABEL_PATH + 'label_trainset.json', encoding="utf-8"))
instruction_trainset = json.load(open(LABEL_PATH + 'instruction_trainset.json', encoding="utf-8"))
instruction_testA = json.load(open(LABEL_PATH + 'instruction_testA.json', encoding="utf-8"))
import random
chat_data = []
for idx in range(20):
for instructions in instruction_trainset[idx]['instruction_detail']:
chat_data.append({
'prompt': instructions['instruction'],
'response': ';'.join([f'{key}' for key, value in instructions['key-value'].items()]),
"history": []
})
random.shuffle(chat_data)
with open('train.json', 'w') as up:
for line in chat_data[:-400]:
up.write(json.dumps(line)+'\n')
with open('dev.json', 'w') as up:
for line in chat_data[-400:]:
up.write(json.dumps(line)+'\n')
- 生成的文件可以在
/kaggle/working/
目录下找到:
配置环境
-
git clone
github仓库。
!git clone https://github.com/THUDM/ChatGLM-6B.git
- 配置
requirements.txt
中的必要工具包。
!pip install -r /kaggle/working/ChatGLM-6B/requirements.txt
配置 train_chat.sh
文件
- 进入到对应目录
cd /kaggle/working/ChatGLM-6B/ptuning
- 写入相关配置
- 其中
--model_name_or_path
我们训练4-bit量化版本THUDM/chatglm-6b-int4
。 - 普通的
THUDM/chatglm-6b
版本会爆显存,因为会先将模型下载下来再进行量化。 - 通过修改以下超参数来调整模型训练。
- 下述参数中
PRE_SEQ_LEN
、max_source_length
、max_target_length
过大导致模型训练较慢,可以适当修改。
with open("/kaggle/working/ChatGLM-6B/ptuning/train_chat.sh", mode='w') as f:
f.write('CHAT_TRAIN_DATA=/kaggle/working/train.json'+'\n')
f.write('CHAT_VAL_DATA=/kaggle/working/dev.json'+'\n')
f.write('CHECKPOINT_NAME=/kaggle/working'+'\n')
f.write('PRE_SEQ_LEN=128'+'\n')
f.write('LR=1e-3'+'\n')
f.write('CUDA_VISIBLE_DEVICES=0 python3 main.py \\'+'\n')
f.write(' --do_train \\'+'\n')
f.write(' --train_file $CHAT_TRAIN_DATA \\'+'\n')
f.write(' --validation_file $CHAT_VAL_DATA \\'+'\n')
f.write(' --prompt_column prompt \\'+'\n')
f.write(' --response_column response \\'+'\n')
f.write(' --history_column history \\'+'\n')
f.write(' --overwrite_cache \\'+'\n')
f.write(' --model_name_or_path THUDM/chatglm-6b-int4 \\'+'\n')
f.write(' --output_dir $CHECKPOINT_NAME \\'+'\n')
f.write(' --overwrite_output_dir \\'+'\n')
f.write(' --max_source_length 256 \\'+'\n')
f.write(' --max_target_length 256 \\'+'\n')
f.write(' --per_device_train_batch_size 1 \\'+'\n')
f.write(' --per_device_eval_batch_size 1 \\'+'\n')
f.write(' --gradient_accumulation_steps 16 \\'+'\n')
f.write(' --predict_with_generate \\'+'\n')
f.write(' --max_steps 3000 \\'+'\n')
f.write(' --logging_steps 100 \\'+'\n')
f.write(' --save_steps 1000 \\'+'\n')
f.write(' --learning_rate $LR \\'+'\n')
f.write(' --pre_seq_len $PRE_SEQ_LEN \\'+'\n')
f.write(' --quantization_bit 4'+'\n')
- 注:由于Kaggle上目前不支持
Linux
的vim
命令修改文件,尝试了如下两种写入方法都会报错:
- 1、这种方式只能在文件末尾补充内容,报错原因大概是在调用后声明导致。
!echo CHAT_TRAIN_DATA=/kaggle/working/train.json >> train_chat.sh
!echo CHAT_VAL_DATA=/kaggle/working/dev.json >> train_chat.sh
!echo CHECKPOINT_NAME=/kaggle/working >> train_chat.sh
- 2、这种方式修改的文件不是
Linux
支持的格式。
%%writefile /kaggle/working/ChatGLM-6B/ptuning/train_chat.sh
微调 ChatGLM
- 还有一个包需要安装
!pip install rouge_chinese -i https://pypi.tuna.tsinghua.edu.cn/simple
- 微调模型,由于Kaggle上无法支持代码运行过程中的输入,因此要关闭
wandb
,执行默认操作,等待模型运行完毕即可。
!wandb off
!bash train_chat.sh
使用微调权重部署ChatGLM
# 首先载入Tokenizer
import torch
from transformers import AutoTokenizer, AutoModel, AutoConfig
# 加载 Checkpoint
config = AutoConfig.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
# pre_seq_len要设置成微调时候的大小
config.pre_seq_len = 128
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True, config=config).half()
# 本次微调得到的glm权重
prefix_state_dict = torch.load('./ChatGLM-6B/ptuning/checkpoint-100/pytorch_model.bin')
new_prefix_state_dict = {}
for k, v in prefix_state_dict.items():
if k.startswith("transformer.prefix_encoder."):
new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
# 据需求可以进行量化
model = model.quantize(4)
model = model.half().cuda()
model.transformer.prefix_encoder.float()
model = model.eval()
# 测试是否部署完成
response, history = model.chat(tokenizer, '''请搜索:吉林批发和零售业的主板B股的首创环保的信息。''', history=[])
print(response)
结果提交
- 对模型的输出格式进行调整,符合提交要求,保存为
.json
文件。 - 将得到的
.json
文件压缩提交 参赛提交
结果分析
- ChatGLM-6B-int4模型的精度稍低,需要更多的训练步数。
- 由于GPU显存有限,每个batch只能处理1个样本,训练过程波动较大,因此需要调整
gradient_accumulation_steps
参数,在多个样本后更新参数。 - 缺点是速度较慢,设置为16的话总时长要10小时以上。
- 模型调优过程经验见下一篇文章。