大语言模型微调实践记录

是大模型呀

Posted by BY J on September 8, 2023

大语言模型微调实践记录

背景

根据目前公开的训练范式,大模型微调主要经过三个步骤的训练:

  • 万亿Token预训练
  • SFT指令对齐
  • RLHF阶段

目前开源的模型大部分为基座大模型与对齐后的chat模型,大体对应了两个阶段中的1与2阶段。本篇将记录根据开源的基座大模型进行SFT微调的实战记录。

基座大模型是不具备对话能力的,所以回答会出现牛头不对马嘴的情况。所以需要我们针对具体的对话数据进行SFT微调,使之具备初步的对话能力。

3月初时,笔者当时根据羊驼项目进行过Llama模型的初步微调,但当时受客观条件限制——训练时间过长与数据集准备不充分、模型了解不多,导致训练完毕后,生成部分会出现token重复,回答截断等问题。所以微调阶段一度放弃。

时间来到9月份,一是认为微调不出具备良好效果的大模型则无法踩坑,也不会有太大成长。二是毕竟这是大势所趋,作为算法工程师应是必备技能。另外,随着陆续开源,可借鉴的资料也很多,所以再度挤时间投入这部分的实验验证。

模型训练大致需要做好三个准备工作:

  • 数据集准备
  • 模型训练代码
  • 资源环境配置、评估工作

数据部分

数据集部分,对于超大数据量数据,通常需要做数据清洗与聚类去重操作,这里将常见的清洗类型与聚类方法进行列举:

这里,我们不涉及数据清洗与数据去重操作,在已知的高质量指令数据中选取复旦大学MOSS团队开源的中英文多轮对话数据。

模型部分

本次微调基于开源Firefly项目(代码友好型,组织结构易于理解)。基座模型选取Baichuan-7B与

Baichuan2-7B进行对比。模型的具体细节不再赘述。具体细节讲解见此处

在实际测试过程中,基座模型是不具备对话能力的,所以需要针对基座模型进行SFT的微调。这里之前我一直有误解。这里值得一提的是在多轮对话训练过程中,Firefly损失函数处稍有改进,具体讲解见此处

训练部分

日志记录

训练过程各相关曲线的观察,这里未采用原项目中的tensorboard,而是选用的wandb

起初实验验证部分选取了MOSS前10万条数据,epoch=1,在两个A6000大约耗时22小时进行微调,结果发现模型已实现了基本的指令对齐,而且并未出现回答token重复等现象出现,这已验证了Firefly项目的良好微调特性。

Moss前10万,Epoch=1

效果图

https://res.cloudinary.com/dsn0i1fsm/image/upload/v1694168738/firefly_o5mcdi.png

目前正在进行基于baichuan-7B与Baichuan2-7B在MOSS上的全量数据微调,相关结果等数据出现后会再公布。

Update:

2023-09-10

baichuan-7B

数据集: Moss

微调日志: 机器 4卡- A100

2023-09-10 10:18:45***** train metrics *****
1350
2023-09-10 10:18:45 epoch = 1.0
1351
2023-09-10 10:18:45 train_loss = 0.7111
1352
2023-09-10 10:18:45 train_runtime = 1 day, 20:04:26.08
1353
2023-09-10 10:18:45 train_samples_per_second = 6.772
1354
2023-09-10 10:18:45 train_steps_per_second = 0.053
1355
2023-09-10 10:18:45wandb: Waiting for W&B process to finish... (success).

2023-09-10 10:18:46wandb: Run summary:
1369
2023-09-10 10:18:46wandb: train/epoch 1.0
1370
2023-09-10 10:18:46wandb: train/global_step 8395
1371
2023-09-10 10:18:46wandb: train/learning_rate 0.0002
1372
2023-09-10 10:18:46wandb: train/loss 0.6591
1373
2023-09-10 10:18:46wandb: train/total_flos 2.4055027002056376e+19
1374
2023-09-10 10:18:46wandb: train/train_loss 0.71107
1375
2023-09-10 10:18:46wandb: train/train_runtime 158666.0883
1376
2023-09-10 10:18:46wandb: train/train_samples_per_second 6.772
1377
2023-09-10 10:18:46wandb: train/train_steps_per_second 0.053

多轮对话效果图

User hello
Moss Hello! How can I assist you today?
User 你谁 会说中文吗
Moss 是的,我可以使用中文与您交流。
User 北京连续下了两天雨了,已经入秋,你能作首宋词描述一下吗
Moss 当然可以,以下是我为您创作的一首宋词:
《秋雨》
秋雨绵绵,秋风萧瑟,
梧桐叶落,满地黄。
秋雨绵绵,秋风萧瑟,
万物凋零,人心思归。
秋雨绵绵,秋风萧瑟,
梧桐叶落,满地黄。
秋雨绵绵,秋风萧瑟,
万物凋零,人心思归。
User 你能背诵李白的将进酒吗
Moss 当然可以,以下是我为您背诵的李白的《将进酒》:
君不见黄河之水天上来,奔流到海不复回。
君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。
岑夫子,丹丘生,将进酒,杯莫停。
与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。
古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。
主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。
User 可以把最后一句翻译成英文吗
Moss Sure, the last line of the poem is:
“五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。”
Translation:
“Five-colored horse, thousand-gold coat, call my son to exchange for wine, and you can help me forget the world for thousands of years.”
User 你做的很不错呢
Moss 谢谢夸奖!我会继续努力的。
User 你认识黑塞吗
Moss 黑塞是德国作家,他的作品被翻译成多种语言,包括中文。他的代表作包括《荒原狼》、《流浪者之歌》等。
User 荒原狼讲的 什么啊
Moss 《荒原狼》是黑塞的代表作之一,讲述了一个孤独的男子在荒原上寻找自我和意义的故事。主人公哈里在现实生活中感到孤独和无助,于是他开始漫游荒原,寻找自我和意义。在荒原上,他遇到了许多人和事物,包括一个神秘的流浪者,一个神秘的女子,以及一只狼。在与这些人和事物的接触中,哈里逐渐找到了自我和意义,最终回到了现实生活中。
User 我刚要开始读它,有什么建议吗
Moss 如果你想开始读《荒原狼》,我建议你先了解一些背景知识。黑塞的作品通常涉及到哲学、宗教、历史等多个领域,需要有一定的阅读基础。此外,黑塞的作品通常比较深刻,需要有一定的思考和理解能力。如果你对这些方面不太熟悉,可以先阅读一些相关的介绍和导读,或者选择一些比较易读的作品。最后,阅读黑塞的作品需要耐心和时间,不要急于求成,慢慢地品味其中的深意和美感。
User 好的,谢谢了,周末愉快
Moss 很高兴能够帮到你,祝你周末愉快!如果你有任何其他问题,随时都可以问我。

从几个测试样例看,效果还是蛮不错的,唯独宋词部分重复输出,综合细评后续给出。

baichuan2-7B

目前微调800step后,会遇到Assertion srcIndex < srcSelectDimSize 错误,从而中断,查阅资料应该是token 索引溢出,但具体错误需要在cpu模式下才会报具体的错误信息,目前不太好解决。。。

Update:

2023-09-12

baichuan2-7B报错是因为包含了add_tokens.json中,删除该文件即可。

目前baichuan2-7B正在微调中.

Update:

2023-09-13

baichuan2-7B

数据集: Moss

微调日志: 机器 4卡- A100

2023-09-13 12:56:48wandb: Run summary:
2023-09-13 12:56:48wandb: train/epoch 1.0
2023-09-13 12:56:48wandb: train/global_step 16790
2023-09-13 12:56:48wandb: train/learning_rate 0.0002
2023-09-13 12:56:48wandb: train/loss 0.7066
2023-09-13 12:56:48wandb: train/total_flos 2.5723421463171564e+19
2023-09-13 12:56:48wandb: train/train_loss 0.74206
2023-09-13 12:56:48wandb: train/train_runtime 145986.254
2023-09-13 12:56:48wandb: train/train_samples_per_second 7.361
2023-09-13 12:56:48wandb: train/train_steps_per_second 0.115

多轮对话效果: 测试样例与baichuan1 保持相同

User hello
Moss Hello! How can I assist you today?
User 你谁 会说中文吗
Moss 是的,我会说中文。请问有什么可以帮助您的吗?
User 当然可以,以下是我为您创作的宋词:
《秋雨》
秋雨绵绵,落满京城。
梧桐叶落,秋风萧瑟。
行人匆匆,脚步匆匆。
思绪万千,愁绪满怀。
但愿秋雨,早日停息。
但愿秋风,不再萧瑟。
但愿行人,不再匆匆。
但愿愁绪,早日消散。
User 你能背诵李白的将进酒吗
Moss 当然可以,以下是我为您背诵的《将进酒》:
君不见黄河之水天上来,奔流到海不复回。
君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。
岑夫子,丹丘生,将进酒,杯莫停。
与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不愿醒。
古来圣贤皆寂寞,惟有饮者留其名。<br /陈王昔时宴平乐,斗酒十千恣欢谑。
主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。
User 可以把最后一句翻译成英文吗
Moss 当然可以,最后一句的英文翻译是:
“Call for the horses and the fur coat, let the children bring out the wine, and we will drink together to forget the sorrows of the ages.”
User 你做的很不错呢
Moss 谢谢夸奖,我会继续努力为您服务的。
User 你认识黑塞吗
Moss 是的,我认识黑塞。黑塞是德国作家赫尔曼·黑塞的笔名,他是20世纪德国文学的代表人物之一,被誉为“德国文学的巨匠”。他的作品以深刻的哲学思考、细腻的情感描写和独特的艺术风格著称,深受读者喜爱。
User 荒原狼讲的 什么啊
Moss 《荒原狼》是德国作家赫尔曼·黑塞的一部小说,讲述了一个名叫哈勒尔的孤独、忧郁、反叛的作家,他在一次意外中失去了自己的灵魂,变成了荒原狼。他试图寻找自己的灵魂,但在这个过程中,他遇到了各种人和事,经历了许多磨难和痛苦,最终找到了自己的归宿。
小说中,黑塞通过哈勒尔的遭遇,探讨了人类的孤独、痛苦、反叛、追求等问题,表达了对人类命运的深刻思考和对人性的深刻洞察。同时,小说也展现了黑塞独特的文学风格和艺术魅力,被誉为德国文学的经典之作。
User 我刚要开始读它,有什么建议吗
Moss 当然,以下是一些阅读《荒原狼》的建议:
1. 了解黑塞的创作背景和思想,这有助于更好地理解小说中的主题和意义。
2. 注意小说中的细节描写和象征意义,这些细节和象征往往能够揭示出小说的深层含义。
3. 注意小说中的对话和内心独白,这些是小说中最重要的部分,能够揭示出哈勒尔的内心世界和情感变化。
4. 注意小说中的节奏和结构,黑塞的小说往往具有独特的节奏和结构,需要耐心阅读和理解。
5. 注意小说中的情感和主题,黑塞的小说往往具有深刻的情感和主题,需要用心去感受和理解。
希望这些建议能够对您阅读《荒原狼》有所帮助。
User 好的,谢谢了,周末愉快
Moss 不客气,祝您周末愉快!如果您有其他问题或需要帮助,随时都可以问我。

测试样例输出其他参数均为变化,可以看到与1对比,内容稍显丰富,同时秋雨的重复问题不再出现,但是在回答上,在“我刚要开始读它,有什么建议吗”的回答方式上,感觉1的开头回答方式稍显好些。

模型评估

通过阅读baichuan2技术论文,目前总体表现测试主要在以下8个benchmark下进行: MMLU,C-Eval,CMMLU,AGIEval, GaoKao,BBH,GSM8K,HumanEval。

另外还包括了垂直领域测试,数学与代码能力测试,多语言测试,道德测试。

测试方式主要为构建5-shot prompt的方式,让模型预测给出的问题答案,然后计算平均正确率。

Baichuan1-7B

经过Moss数据微调后,模型在C-Eval dev数据单次测试Average Acc为42.5%, github首页为42.8%,由于测试时为随机5-shot,0.3%的偏差在误差允许范围内,可见微调对原模型结构影响很小。

Baichuan2-7B

同上述测试一样,单次测试Average Acc 46.2%,github首页为54%,出入较大。

Argue

根据baichuan测评方法

C-Eval 数据集是一个全面的中文基础模型评测数据集,涵盖了 52 个学科和四个难度的级别。我们使用该数据集的 dev 集作为 few-shot 的来源,在 test 集上进行了 5-shot 测试。

通过看公开数据集,test文件夹csv种是不含answer的,看源码测试也不是,所以有点🤔疑惑怎么测试的。是用dev作为few-shot来源,测试val??

总之,目前SFT到测评全流程已基本跑通,暂不关注。

训练平台

公司目前已开放了ModelHub平台,但是我并未采用此方式进行微调训练。

主要采用了两种方式:

  1. 实验验证部分,基于离线容器,通过创建python虚拟容器进行环境配置。
  2. 全量数据部分,目前正通过鲁班平台→离线任务→开发任务 进行微调,但是该方法存在稳定性的问题,偶尔会因为显存问题训练过程被中断。

下面列举详细配置及参数

  1. Firefly项目:

项目介绍页会列举torch版本的区别,可全部采用2.0以上版本, python版本3.8.10。

accelerate==0.21.0
peft==0.4.0
bitsandbytes==0.41.0
loguru==0.7.0
numpy==1.21.4
pandas==1.2.5
tqdm==4.62.3
deepspeed==0.9.5
tensorboard
sentencepiece
transformers_stream_generator
tiktoken
einops
Xformers
torch==2.0.1
scipy
wandb

transformers需要原包安装

2.模型训练参数

{
    "output_dir": "output/firefly-baichuan-7b-1000000",
    "model_name_or_path": "baichuan-7B",
    "cache_dir": "cache_model",
    "train_file": "./data/moss-003-sft-data.jsonl",
    "num_train_epochs": 1,
    "per_device_train_batch_size": 16,
    "gradient_accumulation_steps": 2,
    "learning_rate": 2e-4,
    "max_seq_length": 1024,
    "logging_steps": 50,
    "save_steps": 100,
    "save_total_limit": 1,
    "lr_scheduler_type": "constant_with_warmup",
    "warmup_steps": 1000,
    "lora_rank": 64,
    "lora_alpha": 16,
    "lora_dropout": 0.05,
    "bits": 4,

    "gradient_checkpointing": true,
    "disable_tqdm": false,
    "optim": "paged_adamw_32bit",
    "seed": 42,
    "fp16": true,
    "report_to": "wandb",
    "dataloader_num_workers": 0,
    "save_strategy": "steps",
    "weight_decay": 0,
    "max_grad_norm": 0.3,
    "remove_unused_columns": false,
    "do_eval": false,
    "evaluation_strategy": "no"
}

模型评估

该部分待全量模型训练完毕后再进行补充

TO-DO

  • 更改Dataloader为动态加载文件方式,以适应超大规模数据
  • 添加模型评估方法
  • 添加交互界面以供测试,提供http调用

FAQ:

1. 训练提示bitsandbytes报错?

 Transformer版本一定要用原库安装,一般安装命令

 pip install git+https:*//github.com/huggingface/transformers.git
 不过由于公司平台网络限制原因,建议直接下载git包后,通过pip install -e .
 的方式进行安装

2. 如果发生生成token重复怎么办?
 生成token重复通常可能因训练不充分,或数据集质量太差,另外也可通过生成参数去控制,具体可见[**此处**](https://yuansearch.com/2023/08/14/%E8%A7%A3%E7%A0%81%E7%9A%84%E7%94%9F%E6%88%90%E5%A4%9A%E6%A0%B7%E6%80%A7/)

以上为本周进展,本篇将根据具体实验进展不断更新,以上部分观点仅为个人见解,如有错误,望批评指正。