diff --git a/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md b/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md index a81a400231dce4cd63fbc0360990a4958be37885..450baab7b714e25cb5e9c1a2b20c5558dc1e4553 100644 --- a/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md +++ b/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md @@ -1,3 +1,193 @@ # 开发迁移 -[![查看源文件](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source.svg)](https://gitee.com/mindspore/docs/blob/master/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md) \ No newline at end of file +[![查看源文件](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source.svg)](https://gitee.com/mindspore/docs/blob/master/docs/mindformers/docs/source_zh_cn/usage/dev_migration.md) + +本文档将指导用户如何基于MindFormers开发构建一个大模型,并完成最基本的适配,以拉起训练和推理流程。 + + +## 基于MindFormers构建大模型 + +MindFormers中大模型的基本组成包含配置、模型、分词器(适用于大语言模型)。此外,为了使用run_mindformer统一脚本拉起训练或推理流程,还需要准备用于训练或推理的`YAML`配置文件。 + +### 编写配置 + +模型配置是一个实例,它包含模型的所有信息。MindFormers中所有模型的`__init__`方法都接收一个模型配置的实例作为入参,模型的所有子模块都通过这个配置实例中所包含的信息来初始化。 + +MindFormers提供了[PretrainedConfig]()类,它提供了一些配置的通用方法。所有模型的配置类都应该继承于PretrainedConfig类,开发者只需关心定义所有帮助构建大模型的配置参数:Transformer类大模型通常都拥有`seq_length`、`hidden_size`、`num_layers`、`num_heads`等配置参数,文本类的大模型通常还有`vocab_size`等。 + +可以参考MindFormers中Llama模型的配置类[LlamaConfig]()。 + +> 如果您的模型与库内的模型非常相似,您可以复用与该模型相同的配置。 + +### 编写模型 + +MindFormers的大模型基于MindSpore框架进行开发,如果您的模型已基于PyTorch实现,可以参考[MindSpore网络搭建](https://www.mindspore.cn/docs/zh-CN/master/migration_guide/model_development/model_and_cell.html)。其中开发者只需要关心模型网络本身的实现,MindFormers提供了通用的训练和推理流程,模型开发者只需遵循下述规则,即可使自己的模型适配MindFormers已有的训推流程,并通过与MindFormers仓内模型类似的方式拉起训练和推理任务。 + +MindFormers提供了[PretrainedModel]()类,它负责存储模型配置并处理加载、保存模型的方法。所有模型的类都应该继承于PretrainedModel类,并且模型的输入应该是统一的,即模型的`construct`方法的入参应该一致,具体入参和含义可以参考MindFormers中的Llama模型类[LlamaForCausalLM]()。同时,模型类必须实现基类的一些抽象方法,包括: + +- `prepare_inputs_for_generation`:为模型推理构建输入的方法。 +- `prepare_inputs_for_predict_layout`:为分布式加载模型权重构建虚拟输入的方法。 + +关于它们的具体含义,可以参考[LlamaForCausalLM]()中的描述。 + +> 如果您的模型结构与库内的模型非常相似,您可以复用该模型的实现。 + +### 编写分词器(适用于大语言模型) + +分词器(Tokenizer)的作用是处理大语言模型的输入与输出。它在大语言模型的工作流程中是必需的。 + +MindFormers提供了[PretrainedTokenizer]()类和[PretrainedTokenizerFast]()类,分别是一个纯Python的实现和一个使用Rust库的实现。后者实现的区别是: + +- 在进行批量处理时速度显著提高; +- 额外包含一些在文本字符串和词元空间映射的方法(例如,获取包含给定字符的词元的索引或与给定词元相对应的字符跨度) + +所有分词器的类应该继承于PretrainedTokenizer类或PretrainedTokenizerFast类,具体实现可以参考[LlamaTokenizer]()和[LlamaTokenizerFast]()。 + +> 如果您的分词器与库内的分词器非常相似,您可以复用该分词器的实现。 + +### 把配置、模型、分词器注册到MindFormers + +MindFormers中配置、模型、分词器等API接口都需要通过装饰器注册机制自动注册到Registry字典中,从而实现对API接口的灵活配置和灵活调用。用户自定义的API需要在类的声明上添加[MindFormerRegister]()装饰器,即可在编译时自动进行注册,从而适配MindFormers原有的训推流程。 + +以下是注册的示例: + +#### 注册配置 + +```python +from mindformers.tools.register import MindFormerRegister, MindFormerModuleType + +@MindFormerRegister.register(MindFormerModuleType.CONFIG) +class MyConfig(PretrainedConfig): + ... +``` + +其中`MyConfig`为自定义配置类,本例将`MyConfig`注册进了`CONFIG`类型的字典中。 + +#### 注册模型 + +```python +from mindformers.tools.register import MindFormerRegister, MindFormerModuleType + +@MindFormerRegister.register(MindFormerModuleType.MODELS) +class MyModel(PretrainedConfig): + ... +``` + +其中`MyModel`为自定义模型类,本例将`MyModel`注册进了`MODELS`类型的字典中。 + +#### 注册分词器 + +```python +from mindformers.tools.register import MindFormerRegister, MindFormerModuleType + +@MindFormerRegister.register(MindFormerModuleType.TOKENIZER) +class MyTokenizer(PretrainedConfig): + ... +``` + +其中`MyTokenizer`为自定义分词器类,本例将`MyTokenizer`注册进了`TOKENIZER`类型的字典中。 + +### 准备权重和数据集 + +如已有基于PyTorch的模型权重,可以参考[权重转换文档]()将权重转换为MindSpore格式的权重。 + +数据集的准备可以参考[数据集文档](https://www.mindspore.cn/mindformers/docs/zh-CN/dev/function/dataset.html)。或参考模型文档,如[Llama2说明文档——数据集准备](https://gitee.com/mindspore/mindformers/blob/dev/docs/model_cards/llama2.md#%E6%95%B0%E6%8D%AE%E5%8F%8A%E6%9D%83%E9%87%8D%E5%87%86%E5%A4%87)。 + +### 准备`YAML`配置文件 + +MindFormers使用`YAML`配置文件配置一个任务所需的所有参数,包括模型的配置参数、训练所需的配置参数(优化器、学习率、数据集等)、推理所需的配置参数(分词器等)、分布式并行的配置参数、上下文环境的配置参数等。 + +上文提到了将API接口注册到MindFormers的Registry字典中。由于外挂代码(即不在MindFormers库内的代码,如`research`目录下代码)在使用run_mindformer统一脚本启动时无法被编译,从而需要在`YAML`配置文件中额外添加自动注册的配置项`auto_register`,设置为要注册的API接口的相对导入路径。然后在执行run_mindformer脚本拉起任务时额外添加注册路径的入参`--register_path`,设置为外挂代码所在目录的相对路径。 + +例如,运行`research`目录下的Llama3.1-8B模型的推理任务时,需要额外修改`YAML`文件,以注册[`research/llama3_1/llama3_1_tokenizer.py`](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3_1/llama3_1_tokenizer.py)中自定义的`Llama3Tokenizer`: + +#### 修改[`research/llama3_1/predict_llama3_1_8b.yaml`](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3_1/predict_llama3_1_8b.yaml) + +```yaml +... +processor: + return_tensors: ms + tokenizer: + model_max_length: 8192 + vocab_file: "/path/tokenizer.json" + pad_token: "<|reserved_special_token_0|>" + type: Llama3Tokenizer + auto_register: llama3_1_tokenizer.Llama3Tokenizer + type: LlamaProcessor +... +``` + +其中在`tokenizer`下配置了`Llama3Tokenizer`的相对导入路径`auto_register: llama3_1_tokenizer.Llama3Tokenizer`。 + +#### 使用run_mindformer脚本拉起推理任务 + +运行如下命令拉起推理任务: + +```bash +python run_mindformer.py --config research/llama3_1/predict_llama3_1_8b.yaml --load_checkpoint path/to/llama3_1_8b.ckpt --register_path research/llama3_1 --predict_data "hello" +``` + +**参数说明** + +| 参数 | 说明 | +|:---------------:|:--------------| +| config | `YAML`配置文件的路径 | +| load_checkpoint | 加载的权重路径 | +| register_path | 外挂代码所在目录的路径 | +| predict_data | 推理的输入数据 | + +其中设置了`register_path`为外挂代码所在目录的路径`research/llama3_1`,模型权重的准备参考[Llama3.1说明文档——模型权重下载](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3_1/llama3_1.md#%E6%A8%A1%E5%9E%8B%E6%9D%83%E9%87%8D%E4%B8%8B%E8%BD%BD)。 + +配置文件的详细内容及可配置项可以参考[配置文件说明]()。在实际编写配置文件时,也可以参考库内已有的配置文件,例如[Llama2-7B微调的配置文件](https://gitee.com/mindspore/mindformers/blob/dev/configs/llama2/finetune_llama2_7b.yaml)。 + +在准备完上述所有基本要素之后,可以参考MindFormers使用教程中的其余文档进行模型训练、微调、推理等流程的实践。后续模型调试调优可以参考[大模型精度调优指南](https://www.mindspore.cn/mindformers/docs/zh-CN/dev/acc_optimize/acc_optimize.html)和[大模型性能调优指南](https://www.mindspore.cn/mindformers/docs/zh-CN/dev/perf_optimize/perf_optimize.html)。 + +### 将模型贡献给MindFormers开源仓库 + +可以参考[MindFormers贡献指南](),将模型贡献到MindFormers的开源仓库,供广大开发者研究和使用。 + +## MindFormers大模型迁移实践 + +MindFormers的大模型迁移实践,分为3个层次: + +- 简单:模型结构与库内基础模型一致,只有模型参数、分词器和权重不同。只需修改`YAML`配置文件,迁移分词器代码,和重新转换权重。 +- 中等:模型结构与库内基础模型略微差异,分词器和权重不同。基于简单基础上,需要继承基础模型代码并实现差异点。 +- 高级:模型结构与库内已有基础模型均不同。需从头开发。 + +下面提供了一个简单层次的迁移示例。 + +### 基于Llama2-7B迁移Llama3-8B + +Llama3-8B与Llama2-7B拥有相同的模型结构,只有部分模型参数、分词器和权重不同。 + +#### 模型配置 + +以下对比了Llama2-7B和Llama3-8B的模型配置: + +![model_config_comparison](image/model_config_comparison.png) + +其中的区别有: + +- Llama3-8B的序列长度为8192,将`seq_length`修改为`8192`。 +- Llama3-8B使用GQA,每个key-value组的head数量为8,设置`n_kv_head`为`8`。 +- Llama3-8B的词表大小为128256,将`vocab_size`修改为`128256`。 +- Llama3-8B扩充了Feed-Forward Network的隐藏层大小至14336,设置`intermediate_size`为`14336`。 +- Llama3-8B修改了特殊词元索引,修改`bos_token_id`为`128000`、`eos_token_id`为`128001`、`pad_token_id`为`128002`。 +- Llama3-8B修改了部分结构的数据类型,修改`softmax_compute_type`为`float32`、`rotary_dtype`为`float32`、`param_init_type`为`float16`、`embedding_init_type`为`bfloat16`。 +- Llama3-8B修改了旋转位置编码中的theta值为500000,修改`theta`为`500000`。 + +修改Llama2-7B的`YAML`配置文件中的对应内容即可得到[Llama3-8B的配置文件](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3/finetune_llama3_8b_8k_800T_A2_64G.yaml)。 + +#### 分词器 + +Llama3-8B重新实现了分词器。对照官方的实现,继承MindFormers中的PretrainedTokenizer实现Llama3Tokenizer,编写在[llama3_tokenizer.py](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3/llama3_tokenizer.py)中。 + +#### 权重转换 + +Llama3-8B的参数命名和Llama2-7B一致,因此可以复用Llama2-7B的权重转换流程,参考[Llama3文档的权重转换章节](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3/llama3.md#%E6%A8%A1%E5%9E%8B%E6%9D%83%E9%87%8D%E8%BD%AC%E6%8D%A2)。 + +#### 数据集处理 + +由于Llama3-8B的分词器与Llama2-7B不同,因此Llama3-8B需要在Llama2-7B的数据集处理脚本的基础上,替换Llama3-8B的分词器对数据进行预处理,参考[conversation.py](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3/conversation.py)和[llama_preprocess.py](https://gitee.com/mindspore/mindformers/blob/dev/research/llama3/llama_preprocess.py)。 + +关于MindFormers中Llama3的具体实现,可以参考MindFormers仓库中[Llama3的文件夹](https://gitee.com/mindspore/mindformers/tree/dev/research/llama3)。关于MindFormers中Llama3的使用,可以参考[LLama3的说明文档](https://gitee.com/mindspore/mindformers/tree/dev/research/llama3)。 \ No newline at end of file diff --git a/docs/mindformers/docs/source_zh_cn/usage/image/model_config_comparison.png b/docs/mindformers/docs/source_zh_cn/usage/image/model_config_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7b68be2aa98bde82c9ffba8edfea7df06f89be Binary files /dev/null and b/docs/mindformers/docs/source_zh_cn/usage/image/model_config_comparison.png differ