Skip to content

[llm] Add llm pretrain tutorial #10611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/zh/llm/devices/intel_hpu/tests/README.md
1 change: 1 addition & 0 deletions docs/zh/llm/docs/pretrain_tutorial.md
176 changes: 176 additions & 0 deletions llm/docs/pretrain_tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# PaddleNLP 大模型新手指南-预训练
本教程将从新手视角出发,讲解如何使用 PaddleNLP 进行大语言模型(LLM)预训练。我们以 Qwen2.5-0.5B 模型为例,运行在百度星河平台(AI Studio)上,完整展示数据准备、模型构建、训练启动及调优建议。

我们在 Ai Studio 上同步公开了项目,也可以点击[链接](https://aistudio.baidu.com/projectdetail/9038113)在线体验大模型预训练。

目标:
- 了解预训练任务基本流程
- 能运行 PaddleNLP 提供的训练脚本
- 会在自己的数据上复现训练过程

## 1. 依赖安装
首先安装 PaddlePaddle 和 PaddleNLP 的[最新版本](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/linux-pip.html):


```python
# 安装PaddlePaddle最新版本
python -m pip install --pre paddlepaddle-gpu -i https://www.paddlepaddle.org.cn/packages/nightly/cu118/
```


```python
# Clone PaddleNLP仓库,训练/微调/对齐/量化的脚本都在仓库的llm/目录下
git clone https://github.com/PaddlePaddle/PaddleNLP.git
```

## 2. 数据准备
大模型的预训练任务目标是让模型学习语言的结构和语义,因此数据通常是大规模的自然语言文本,如:
* 新闻、小说、百科

* 网络论坛、问答内容

这里的训练数据与我们常见的<数据,标签>的监督学习所用的数据并不相同。我们使用[OpenWebTextCorpus](https://skylion007.github.io/OpenWebTextCorpus/)作为本次预训练的数据。

以[PaddleNLP 预训练数据流程](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/tools/preprocess)中的样例分析:

```
飞桨是功能完备、开源开放的产业级深度学习平台。
飞桨拥有核心训练和推理框架、基础模型库。
PaddleNLP是自然语言处理领域的优秀工具。
```
大模型的预训练数据就是这样的自然语言文本。大模型的预训练是一种无监督训练,基本的思想是根据之前的词语来预测下一个词,以第一句举例:
```
(输入)飞桨是功能完备、开源开放的产业级深度学习 -> (输出)平台
```
不需要额外的标注数据。

我们通过下面的命令下载已经预处理过的数据。


```python
# llama 模型数据下载
wget https://bj.bcebos.com/paddlenlp/models/transformers/llama/data/llama_openwebtext_100k.bin
wget https://bj.bcebos.com/paddlenlp/models/transformers/llama/data/llama_openwebtext_100k.idx
```


```python
mkdir data
mv llama_openwebtext_100k.bin ./data
mv llama_openwebtext_100k.idx ./data
```

### 数据处理
我们下载的数据是经过处理的数据,虽然我们本次不需要自己处理,但是可以简单了解一下数据的格式。
* 原始数据:用换行符隔开的句子。
* json/jsonl:两者区别是 jsonl 是每行一个句子,json 完整格式相对复杂一些。```{"text": "PaddleNLP是自然语言..."}```
* 分词(可选):```PaddleNLP 是 自然语言处理领域 的 优秀工具。```
* 转换为 ID:每个词会转换为一个数字 ID,最终形成一个 mmap(memory-mapped file)文件。bin 的二进制文件里面是所有文本的数字 ID,idx 文件里面是每句话的起始位置。

详细数据处理可以参考[PaddleNLP 预训练数据流程](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/tools/preprocess)。

## 3. 模型训练
PaddleNLP 实现了一个对常用开源大模型便捷的预训练方式,本次我们使用 Qwen2.5-0.5B 进行实验。从 PaddleNLP 支持的[模型列表](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/pretrain.html#model-weight)将制定模型配置文件作为参数输入训练脚本即可开展训练。


```python
# 16G 显存可训练
python -u ~/PaddleNLP/llm/run_pretrain.py ~/PaddleNLP/llm/config/qwen/pretrain_argument_0p5b.json
```

看到下面的提示说明已经开始进行训练了:
```
[2025-05-18 10:13:15,353] [ INFO] - loss: 12.0635252, learning_rate: 2e-06, global_step: 1, current_memory_allocated: 7.549170255661011, current_memory_reserved: 7.753237724304199, max_memory_allocated: 7.549170255661011, max_memory_reserved: 7.753237724304199, interval_runtime: 1.1518, interval_samples_per_second: 0.8682, interval_tokens_per_second_per_device: 889.0448, interval_hardware_tflops_per_device: 2.77, interval_steps_per_second: 0.8682, progress_or_epoch: 0.0
[2025-05-18 10:13:15,607] [ INFO] - loss: 12.05887604, learning_rate: 3e-06, global_step: 2, current_memory_allocated: 7.549170255661011, current_memory_reserved: 12.4834623336792, max_memory_allocated: 12.307440280914307, max_memory_reserved: 12.4834623336792, interval_runtime: 0.2556, interval_samples_per_second: 3.913, interval_tokens_per_second_per_device: 4006.9441, interval_hardware_tflops_per_device: 12.49, interval_steps_per_second: 3.913, progress_or_epoch: 0.0
```

### FAQ1:显存不足
如果在训练时候看到类似的错误信息:
```
RuntimeError: CUDA out of memory. ......
```

说明训练所需的显存超过了当前显卡提供的最大显存,说明此时我们无法按照默认设置进行单卡训练,解决方式有如下几种:
* 更换拥有更大显存的显卡
* 使用模型量化或一些机制来节省显存
* 多卡并行训练

我们重点介绍一下除了更换显卡之外的另外两种解决方案。

### 3.1 节省显存
#### 模型量化
模型量化(Quantization)是指将模型中的权重和激活值从高精度(如 FP32)压缩为低精度(如 INT8 或 FP16),以减小模型大小、加快推理速度、降低内存/显存占用。这部分将在模型量化的指南当中进行介绍。

#### 其他机制
在模型的 config 文件中,修改以下参数:
```
"use_flash_attention": false,
"use_fused_rms_norm": false,
......
"recompute": false,
```

**注意:**
1. Flash attention 对于显卡的硬件架构有要求,需要在 V100、H100等显卡上面才能开启,建议使用 cuda11.8及以上环境;
2. use_fused_rms_norm 需要安装自定义算子。如果安装后仍然找不到算子,需要额外设置 PYTHONPATH。

### 3.2 高性能/多卡/多机训练
单张显卡的显存/性能不足可以通过多卡的并行来进行解决,我们常见的大模型也是在很多张显卡上面进行并行训练的。飞桨大模型套件支持4D 并行,在实际使用上也很便捷。相比于单卡训练,主要的区别在于输入了多张显卡的编号。


```python
# 编译自定义算子,可选
cd ../slm/model_zoo/gpt-3/external_ops/ && python3 setup.py install && cd -
# 多卡模型预训练参考:
python -u -m paddle.distributed.launch --devices "0,1,2,3,4,5,6,7" run_pretrain.py ./config/llama/pretrain_argument.json
# 多机训练参考: 占用45G显存左右
python -u -m paddle.distributed.launch --devices "0,1,2,3,4,5,6,7" --master=192.168.1.1:8090 --nnodes=2 run_pretrain.py ./config/llama/pretrain_argument.json

```

### 3.3 训练结果
当训练结束时,可以看到下面的输出:
```
[2025-05-18 10:49:13,774] [ INFO] - Saving model checkpoint to ./checkpoints/pretrain_ckpts
[2025-05-18 10:49:13,775] [ INFO] - tokenizer config file saved in ./checkpoints/pretrain_ckpts/tokenizer_config.json
[2025-05-18 10:49:13,776] [ INFO] - Special tokens file saved in ./checkpoints/pretrain_ckpts/special_tokens_map.json
[2025-05-18 10:49:13,776] [ INFO] - added tokens file saved in ./checkpoints/pretrain_ckpts/added_tokens.json
[2025-05-18 10:49:13,803] [ WARNING] - Asynchronous saving is not supported for single card environment currently.
[2025-05-18 10:49:15,691] [ INFO] - Configuration saved in ./checkpoints/pretrain_ckpts/config.json
[2025-05-18 10:49:15,694] [ INFO] - Configuration saved in ./checkpoints/pretrain_ckpts/generation_config.json
[2025-05-18 10:49:15,695] [ INFO] - ***** train metrics *****
[2025-05-18 10:49:15,695] [ INFO] - progress_or_epoch = 0.0868
[2025-05-18 10:49:15,695] [ INFO] - train_loss = 5.4334
[2025-05-18 10:49:15,695] [ INFO] - train_runtime = 0:35:59.57
[2025-05-18 10:49:15,696] [ INFO] - train_samples_per_second = 4.6305
[2025-05-18 10:49:15,696] [ INFO] - train_steps_per_second = 4.6305
[2025-05-18 10:49:15,697] [ INFO] - ***** Running Prediction *****
[2025-05-18 10:49:15,697] [ INFO] - Num examples = 258
[2025-05-18 10:49:15,697] [ INFO] - Total prediction steps = 129
[2025-05-18 10:49:15,697] [ INFO] - Pre device batch size = 2
[2025-05-18 10:49:15,697] [ INFO] - Total Batch size = 2
[2025-05-18 10:49:28,420] [ INFO] - ***** test metrics *****
[2025-05-18 10:49:28,420] [ INFO] - test_loss = 4.8691
[2025-05-18 10:49:28,420] [ INFO] - test_runtime = 0:00:12.72
[2025-05-18 10:49:28,420] [ INFO] - test_samples_per_second = 20.2781
[2025-05-18 10:49:28,420] [ INFO] - test_steps_per_second = 10.1391
Effective Tokens per second: 4741.68
ips: 4741.68 tokens/s
```
说明我们已经成功训练并且将训练后的模型参数进行了保存,在 ```checkpoints/pretrain_ckpts```目录下。我们可以简单浏览一下目录,看看预训练后的模型文件是什么样子。


```python
ls -l checkpoints/pretrain_ckpts/
```

| 分类 | 代表文件 | 作用 |
| ----------- | --------------------------------------------------- | -------------------- |
| 模型结构 | `config.json` | 定义模型维度、层数等超参数 |
| 模型权重 | `model-*.safetensors` + index 文件 | 保存 Transformer 模型的参数 |
| 分词器 | `vocab.json`, `merges.txt`, `tokenizer_config.json` | 定义 tokenizer 行为和词表 |
| 特殊 token 信息 | `added_tokens.json`, `special_tokens_map.json` | 管理新增或特殊 token |
| 训练状态 | `trainer_state.json`, `training_args.bin` | 记录训练进度和参数 |
| 评估结果 | `all_results.json`, `train_results.json` | 保存训练评估指标结果 |
| TensorBoard | `runs/` | 可视化训练曲线 |
| 检查点 | `checkpoint-*/` | 每 N 步保存的快照 |