大模型 Fine-tuning 实践
大模型 Fine-tuning 实践
前面两篇文章整理了学习笔记,对大模型应该有了一个初步认知。这篇文章会从代码角度,尝试一下微调。看完本篇文章之后,应该能自己训练一个简单的类 GPT demo 模型。
一、准备工作
1. 训练数据集
比如我下面的数据是我自己开发的 Capybara 翻译软件 文档的 txt 格式数据集其中之一,这里只是一个简单的例子,实际上你可以使用任何文本数据集。你可以在这里找到更多数据集 huggingface dataset hub
1 | Capybara 翻译软件的主要特性: |
2. 开源模型
- Qwen/Qwen2-0.5B
- Qwen/Qwen2-0.5B-Instruct
我们这里选用通义千问来做微调。你可以在 huggingface 去找到这两个模型,当然你也可以使用其他模型。选择 0.5B 参数量是因为模型相对较小,训练速度更快。
二、数据准备
- 数据转换
- Tokenization
数据准备分为两部分,一部分是数据转换,另一部分是 Tokenization。
1. 数据转换
1 | import torch |
上面的代码将 txt 格式的数据处理为 JSON 格式,方便后续处理。转换结果如下:
1 | [ |
2. Tokenization
Tokenization 可以在 the-tokenizer-playground 尝试。
1 | # load the pretraining dataset and do tokenization |
比如第一条数据,经过 Tokenization 之后的结果如下:
1 | Encoded token id: [34, 9667, 24095, 54851, 104794, 42140, 100133, 105395, 103951, 3837, 100143, 80577, 220, 102450, 105395, 90395, 100136, 115654, 479, 2828, 10236, 123, 119, 102610, 47874, 3837, 101066, 99787, 87026, 102235, 100757, 110498, 0] |
三、模型微调
- 加载模型
- 设置模型参数
- 运行训练过程
- 推理 & 验证
1. 加载模型
1 | # load a pretrained model with huggingface/transformers |
打印出模型信息:
1 | # we print the model parameters |
1.1 测试模型
这里先测试一下通义千问模型,看看推理结果:
1 | # test the loaded model |
模型输出结果如下:
1 | Capybara 翻译软件的主要特性: 1. 2000 多种编程语言支持; 2. 丰富的资源和工具,如: Python, C, C++, Java, JavaScript 等编程语言,提供详细的官方教程; 3. 超过 300 万条示例; 4. 丰富的工具箱,包括编译器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、调试器、 |
可以看到基本是胡言乱语了,因为数据集里面并没有 Capybara 的信息。下一步,就是微调这个模型,让他能够生成我们想要的文本。
2. 设置模型参数
设置模型,注意一下 learning_rate
参数。
学习率 是一个超参数,用于控制在每次更新模型参数时,梯度下降算法的步伐大小。简单来说,它决定了每次调整模型参数的幅度。
设置的比较小,可能得不到想要的训练结果,具体数值可以自行尝试。
1 | from transformers import DataCollatorForLanguageModeling |
3. 运行训练过程
1 | # start the training process, just 1 line of code |
训练结果:
1 | {'loss': 0.2601, 'grad_norm': 9.022148132324219, 'learning_rate': 3e-05, 'epoch': 1.0} |
可以尝试看一下这个结果,loss 数值越来越小,说明模型在训练过程中逐渐收敛。epoch 为 5,表示训练了 5 轮。learning_rate 逐渐减小,这是因为我们设置了 lr_scheduler_type='cosine'
,这个参数会让学习率逐渐减小。
4. 推理 & 验证
1 | pretrained_model = AutoModelForCausalLM.from_pretrained('saves/Qwen2-0.5B-pt') |
输出结果:
1 | Capybara 翻译软件的主要特性: |
可以看到,虽然有少许的差异,但是总体还是很精准的。最开始设置的 learning_rate
比较小,没有得到想到的结果,将其调大之后,以及 epoch
调大,明显比最开始的效果好很多。
4.1 问答
这里用一个问句来测试是否能得到我们想要的结果。
1 | input_text2 = "你帮我回答一下 Capybara 翻译软件的主要特性有什么?" |
输出结果:
1 | 你帮我回答一下 Capybara 翻译软件的主要特性有什么? 1. 多平台翻译比对:支持多种翻译平台间的翻译结果对比,帮助用户选择最佳翻译。 |
可以看到,整体答案还是符合的,但是有一点,模型把我们的问题也作为回答的一部分了。可以得出,模型学习了知识,但无法按照我们的指令进行响应,预期是能按照类似 GPT 的回答方式,一问一答。因此我们需要指令调优,即 SFT。
四、指令调优
指令调优是指在微调模型的过程中,通过指令的方式来指导模型生成更加符合预期的结果。这里我们使用的是通义千问的 Qwen2-0.5B-Instruct 模型。
- 数据格式化
- 训练
- 推理
1. 数据格式化
直接让 GPT 帮我们格式化需要的指令数据,后面用这个去训练:
1 | [ |
2. 设置参数
1 | # so we have done the pretraing process, the model just can just predict the next token based on the previous tokens |
3. 处理数据
1 | from trl import SFTConfig, SFTTrainer |
格式化样本:
1 | '<|im_start|>system\n<|im_end|>\n<|im_start|>user\nCapybara 是什么?<|im_end|>\n<|im_start|>assistant\nCapybara 是一款多平台翻译软件,支持 OCR 识别翻译,并且内置 GPT 翻译服务,努力成为您最好的办公助手!<|im_end|>\n' |
上面这条数据即为格式化后的数据,到这里,指令已经被正确的格式化了。
4. 训练
1 | train_result = sft_trainer.train() |
训练结果:
1 | {'loss': 2.796, 'grad_norm': 39.54423904418945, 'learning_rate': 1.5e-05, 'epoch': 0.25} |
5. 推理
这里问了一个问题,"你帮我回答一下 Capybara 翻译软件的主要特性有什么?"
1 | from transformers import AutoModelForCausalLM, AutoTokenizer |
5.1 微调之前的结果
1 | Input: 你帮我回答一下 Capybara 翻译软件的主要特性有什么? |
5.2 微调之后的结果
微调之前的模型,已经能做到根据我们的指令回答我们想要的结果了。但是回答的内容并不是想要的,微调之后,就能满足要求了。
1 | After fine-tuning: Capybara 翻译软件的主要特性: |
- 感谢你的欣赏!