mirror of
https://github.com/hiyouga/LLaMA-Factory.git
synced 2026-09-26 17:35:43 +08:00
[v1] update docs (#10684)
This commit is contained in:
52
.claude/skills/llamafactory-v1-docs/SKILL.md
Normal file
52
.claude/skills/llamafactory-v1-docs/SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: llamafactory-v1-docs
|
||||
description: Write, review, update, build, or preview LlamaFactory v1 documentation. Use for docs work grounded in src/llamafactory/v1; not for running model training.
|
||||
---
|
||||
|
||||
# LlamaFactory v1 Documentation
|
||||
|
||||
## Scope
|
||||
|
||||
- Work in the repository containing both `docs/` and `src/llamafactory/v1/`. Check the branch and existing changes first.
|
||||
- Treat this branch's v1 implementation as the source of truth; do not infer behavior from v0 or upstream code.
|
||||
- Maintain Chinese and English counterparts for pages touched by the task unless the user limits the language. Align relative page paths, structure, technical meaning, examples, and navigation; translate prose naturally while preserving code identifiers and commands. Report any remaining language gaps.
|
||||
- Preserve unrelated edits and explicitly deferred issues. Review-only requests stay read-only; build-only requests do not rewrite content.
|
||||
|
||||
## Writing
|
||||
|
||||
- Explain features directly: behavior, configuration, execution, and constraints. Avoid assumed user goals, selection advice, rhetorical questions, and “use case” columns unless requested.
|
||||
- Keep content ownership clear: feature guides explain usage; configuration pages define fields and semantics; developer guides explain internals. Link between them instead of repeating full sections.
|
||||
- Use tables for factual comparisons. Keep examples short and distinguish complete configurations from partial snippets without repetitive setup reminders.
|
||||
- Explain defaults, omitted versus explicit values, precedence, units, and conditional behavior—not just parameter names.
|
||||
- In developer guides, show responsibilities, inputs, outputs, state ownership, and call order. Use a small example or tensor shapes when abstractions need clarification.
|
||||
- Use one H1 per page, meaningful headings, language-tagged code blocks, relative links, and the appropriate `toctree` entry for new pages.
|
||||
|
||||
## Source and Examples
|
||||
|
||||
- Trace relevant configuration parsing, plugin registration, and call sites. A declared field or interface alone does not establish support.
|
||||
- Distinguish related concepts, such as quantization plugins, backends, bit widths, and formats. Verify current support rather than hardcoding assumptions into this skill.
|
||||
- Keep model IDs, adapter paths, model directories, and filenames consistent across training, inference, and export examples. Match each downstream input to the preceding output.
|
||||
- Parse changed YAML examples and check their placement and composition. Examples described as runnable need the required imports, interfaces, and registration.
|
||||
- Document confirmed behavior and limitations. Report unresolved implementation questions separately; do not insert speculation or conversation history into public documentation.
|
||||
|
||||
## Build and Preview
|
||||
|
||||
Use an existing Python environment with `docs/requirements.txt` installed. Build both languages from the repository root, or just the language explicitly requested:
|
||||
|
||||
```bash
|
||||
for doc_language in zh en; do
|
||||
env LC_ALL=C LANG=C python3 -m sphinx -b html -n -W --keep-going "docs/$doc_language" "docs/_build/html/$doc_language" || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
Review the diff and build diagnostics; check changed pages, links, anchors, and table/code rendering. Fix issues introduced by authorized edits and rebuild. For review-only or build-only requests, report existing failures without expanding the scope. Do not disable strict checks or run model training merely to validate documentation.
|
||||
|
||||
When a preview is requested, reuse a server serving this output or start one on an available local port:
|
||||
|
||||
```bash
|
||||
python3 -m http.server 8765 --bind 127.0.0.1 --directory docs/_build/html
|
||||
```
|
||||
|
||||
Open the relevant pages under `/zh/` and `/en/` on the preview server and verify the served content and language-switch links. Do not stop unrelated servers or publish the site automatically.
|
||||
|
||||
Report the changed files and completed checks briefly; include a preview link if available. Distinguish a successful documentation build from validated model execution.
|
||||
5
docs/_static/css/tables.css
vendored
Normal file
5
docs/_static/css/tables.css
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.rst-content table.docutils td code {
|
||||
white-space: nowrap;
|
||||
overflow-wrap: normal;
|
||||
word-break: normal;
|
||||
}
|
||||
@@ -26,6 +26,7 @@ html_js_files = [
|
||||
|
||||
html_css_files = [
|
||||
"css/lang-switcher.css",
|
||||
"css/tables.css",
|
||||
]
|
||||
|
||||
myst_enable_extensions = [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# FSDPTurbo EP/EFSDP and LlamaFactory FSDP2/CP Design
|
||||
|
||||
Chinese version: [FSDPTurbo EP/EFSDP 与 LlamaFactory FSDP2/CP 设计说明](../../../zh/advanced/distributed/fsdpturbo-ep-efsdp.md)
|
||||
Chinese v1 guide: [Distributed training with FSDPTurbo](https://llamafactory.readthedocs.io/zh-cn/latest/feature-guide/distributed_training.html#fsdpturbo)
|
||||
|
||||
This document describes the current implementation of the `fsdpturbo` distributed plugin. Its core principle is a clear separation of responsibilities:
|
||||
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
# LLaMA-Factory Kernels 系统
|
||||
|
||||
## 概述
|
||||
|
||||
LLaMA-Factory Kernels 系统用于管理不同硬件设备提供的高性能计算内核(kernel)实现,该系统通过替换模型中的关键模块(如 RMSNorm、SwiGLU、RoPE、MoE 等)为硬件优化的版本,从而显著提升模型训练和推理的性能。
|
||||
|
||||
Kernels 系统采用基于注册表的自动发现机制,能够根据当前运行环境自动检测可用的硬件设备(NPU、CUDA 等),并使能相应的高性能 kernels。这种设计使得用户无需关心底层实现细节,只需简单调用接口即可获得性能提升。
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **自动注册机制**:基于 `@register_kernel` 装饰器实现自动注册系统。系统启动时会自动扫描 `ops` 目录下的 kernel 实现,并将其注册到全局注册表中。
|
||||
|
||||
- **设备适配感知**:自动检测当前硬件设备(NPU、CUDA 等)并应用相应的优化。系统会跳过不支持的设备,确保在不同环境下都能正常工作。
|
||||
|
||||
- **模块化设计**:每个 kernel 独立实现,互不干扰。可以单独应用某个 kernel,也可以批量应用所有默认的 kernels。
|
||||
|
||||
- **后向兼容**:kernel 替换不修改模型权重,保持数值一致性。优化后的实现与原始实现保持精度一致(在浮点误差范围内)。
|
||||
|
||||
- **灵活扩展**:通过继承 `BaseKernel` 基类并使用装饰器,可以轻松添加新的 kernel 实现,支持新的硬件设备或优化算法。
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 1. 通过训练 YAML 配置文件使用
|
||||
|
||||
要在训练过程中使能 kernels,只需在配置文件中增加如下配置,即可自动使能所有默认可用的 kernels:
|
||||
|
||||
```yaml
|
||||
...
|
||||
kernel_config:
|
||||
name: auto
|
||||
include_kernels: auto # choice: null/true/false/auto/kernel_id1,kernel_id2,kernel_id3, default is null
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### 2. 调用 API 使能
|
||||
|
||||
#### 2.1 apply_default_kernels 使能所有默认 kernels
|
||||
|
||||
`apply_default_kernels` API 能够自动应用当前设备上所有默认注册的 kernels:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM
|
||||
from llamafactory.v1.plugins.model_plugins.kernels import apply_default_kernels
|
||||
|
||||
# 加载模型
|
||||
model = AutoModelForCausalLM.from_pretrained("qwen/qwen2.5-0.5B")
|
||||
|
||||
# 自动应用所有默认 kernels
|
||||
model = apply_default_kernels(model, include_kernels="auto")
|
||||
```
|
||||
|
||||
#### 2.2 apply_kernel 使能特定 kernel
|
||||
|
||||
如果需要更精细的控制,例如在某些场合单独应用某个 kernel,可以手动调用 `apply_kernel` 函数并传入 kernel ID:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM
|
||||
from llamafactory.v1.plugins.model_plugins.kernels import apply_kernel
|
||||
|
||||
# 加载模型
|
||||
model = AutoModelForCausalLM.from_pretrained("qwen/qwen2.5-0.5B")
|
||||
|
||||
# 手动应用各个 kernels
|
||||
# 注意:kernel ID 必须与定义时的 _kernel_id 一致
|
||||
model = apply_kernel("npu_fused_rope", model=model)
|
||||
model = apply_kernel("npu_fused_rmsnorm", model=model)
|
||||
model = apply_kernel("npu_fused_swiglu", model=model)
|
||||
model = apply_kernel("npu_fused_moe", model=model)
|
||||
|
||||
### 3. 查询已注册的可用 kernels
|
||||
|
||||
可以通过 `get_default_kernels` 获取当前环境中所有已注册且可用的默认 kernel ID:
|
||||
|
||||
```python
|
||||
from llamafactory.v1.plugins.model_plugins.kernels import get_default_kernels
|
||||
|
||||
# 获取默认 kernel 列表
|
||||
available_kernels = get_default_kernels()
|
||||
print(f"Available kernels: {available_kernels}")
|
||||
# 输出示例: ['npu_fused_rmsnorm', 'npu_fused_swiglu', 'npu_fused_rope', 'npu_fused_moe']
|
||||
```
|
||||
|
||||
### 当前已实现的 kernels
|
||||
|
||||
| Kernel ID | 功能 | 支持的设备 | 备注 |
|
||||
|-----------|------|-----------|------|
|
||||
| [npu_fused_rmsnorm](./fused-operators.md/#npufusedrmsnorm) | RMSNorm 融合算子 | NPU | NPU 设备的高性能 RMSNorm 实现 |
|
||||
| [npu_fused_swiglu](./fused-operators.md/#npufusedswiglu) | SwiGLU 融合算子 | NPU | NPU 设备的高性能 SwiGLU 实现 |
|
||||
| [npu_fused_rope](./fused-operators.md/#npufusedrope) | RoPE 融合算子 | NPU | NPU 设备的高性能 RoPE 实现 |
|
||||
| [npu_fused_moe](./fused-operators.md/#npufusedmoe) | MoE 融合算子 | NPU | MoE 融合算子,适配 Qwen3-MoE 等模型 |
|
||||
|
||||
我们会持续适配更多的 kernels,如果您需要自己开发新的 kernels,请参考我们的 [Kernel 开发文档](../../dev-guide/plugins/model-plugins/kernels.md),欢迎您向 LLaMA-Factory 贡献代码。
|
||||
@@ -1,104 +0,0 @@
|
||||
# Fused Operators
|
||||
|
||||
LLaMA-Factory 提供了一系列针对特定硬件优化的融合算子。这些算子位于 `src/llamafactory/v1/plugins/model_plugins/kernels/ops` 目录下。
|
||||
|
||||
系统启动时,`scan_all_kernels` 函数会自动扫描该目录,注册所有可用的算子。您可以通过 `apply_default_kernels(model, include_kernels="auto")` 一键启用它们,或者使用 `apply_kernel` 单独启用。
|
||||
|
||||
以下是当前支持的融合算子详情:
|
||||
|
||||
## NpuFusedRMSNorm
|
||||
RMSNorm(Root Mean Square Layer Normalization)是一种常用于大模型的归一化方法。在推理或训练中,RMSNorm 融合算子 将bias、residual等操作进行融合,可以减少显存访问次数,加速计算。
|
||||
|
||||
Ascend npu 通过 `torch_npu.npu_rms_norm` 接口提供 RMSNorm 融合算子调用接口,支持 float16, bfloat16, float 等数据格式。RMSNorm 算子常见于Qwen等LLM模型中,由于torch侧没有提供 RMSNorm 算子的接口,因此在模型中通常是以自定义类的形式出现,通过替换 RMSNorm 类的 `forward` 方法即可使能。
|
||||
|
||||
```python
|
||||
def _npu_rms_forward(self, hidden_states):
|
||||
"""NPU forward implementation for RMSNorm.
|
||||
|
||||
Args:
|
||||
self: RMSNorm module instance with `weight` and `variance_epsilon`.
|
||||
hidden_states: Input hidden states tensor, same shape as the baseline.
|
||||
|
||||
Returns:
|
||||
Normalized tensor consistent with the baseline RMSNorm behavior.
|
||||
"""
|
||||
|
||||
return torch_npu.npu_rms_norm(hidden_states, self.weight, epsilon=self.variance_epsilon)[0]
|
||||
```
|
||||
|
||||
在 LlamaFactory 中,通过 `NpuRMSNormKernel` 提供使能该融合算子的入口,只需要调用 `apply_kernel("npu_fused_rmsnorm", model=model)` 即可针对已适配的模型使能 npu RMSNorm 融合算子。
|
||||
|
||||
## NpuFusedSwiGlu
|
||||
SwiGLU(Swish-Gated Linear Unit)是一种结合了Swish激活函数和门控线性单元(GLU)的混合激活函数,其主要功能是对输入张量进行门控线性变换,近年来被广泛应用于 LLM 模型中的 MLP 层。SwiGLU 融合算子将分割、激活、矩阵乘等多个操作融合为单一硬件指令,避免多次内核启动开销。
|
||||
|
||||
Ascend npu 通过 `torch_npu.npu_swiglu` 接口提供 SwiGLU 融合算子调用接口,支持 float16,bfloat16,float SwiGLU 算子常见于Qwen等LLM模型中,由于torch侧没有提供 SwiGLU 算子的接口,因此在模型中通常是以自定义类的形式出现,通过替换 SwiGLU 类的 `forward` 方法即可使能。替换过程可参考如下示例:
|
||||
|
||||
```python
|
||||
# 原始 MLP forward 方法:
|
||||
def forward(self, x):
|
||||
down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
||||
return down_proj
|
||||
|
||||
# 替换后的 forward 方法:
|
||||
def _npu_swiglu_forward(self, hidden_state):
|
||||
return self.down_proj(
|
||||
torch_npu.npu_swiglu(torch.cat((self.gate_proj(hidden_state), self.up_proj(hidden_state)), dim=-1), dim=-1)
|
||||
)
|
||||
```
|
||||
|
||||
在 LLaMA-Factory 中,通过 `NpuSwiGluKernel` 提供使能该融合算子的入口,只需要调用 `apply_kernel("npu_fused_swiglu", model=model)` 即可针对已适配的模型使能 npu SwiGLU 融合算子。对于未适配的模型,如有需要,您可根据示例以及[开发者文档](../../dev-guide/plugins/model-plugins/kernels.md)自行适配。
|
||||
|
||||
|
||||
## NpuFusedRoPE
|
||||
RoPE(Rotary Positional Embedding,旋转式位置嵌入) 是一种位置编码技术,广泛应用于 Qwen 等 LLM 模型中,用于有效编码文本序列的位置信息。它结合了绝对位置编码的稳定性与相对位置编码的灵活性,同时具备优秀的长度泛化能力。传统 RoPE 算子通常在 LLM 等模型结构中通过自定义函数的形式实现。RoPE 融合算子将原计算流程合并为单个硬件优化算子,从而提升性能。
|
||||
|
||||
Ascend npu 通过 `torch_npu.npu_rotary_mul` 提供 RoPE 融合算子调用接口,支持 float16,bfloat16,float32 等数据格式。以 Qwen3 系列模型为例,通过替换其 `apply_rotary_pos_emb` 函数即可实现 RoPE融合算子使能:
|
||||
|
||||
```python
|
||||
# 原始 apply_rotary_pos_emb:
|
||||
def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
|
||||
cos = cos.unsqueeze(unsqueeze_dim)
|
||||
sin = sin.unsqueeze(unsqueeze_dim)
|
||||
q_embed = (q * cos) + (rotate_half(q) * sin)
|
||||
k_embed = (k * cos) + (rotate_half(k) * sin)
|
||||
return q_embed, k_embed
|
||||
|
||||
# 替换 RoPE 融合算子后:
|
||||
def _apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
|
||||
cos = cos.unsqueeze(unsqueeze_dim)
|
||||
sin = sin.unsqueeze(unsqueeze_dim)
|
||||
q_embed = torch_npu.npu_rotary_mul(q, cos, sin)
|
||||
k_embed = torch_npu.npu_rotary_mul(k, cos, sin)
|
||||
return q_embed, k_embed
|
||||
```
|
||||
|
||||
在 LLaMA-Factory 中,通过 `NpuRoPEKernel` 提供使能该融合算子的入口,只需要调用 `apply_kernel("npu_fused_rope", model=model)` 即可针对已适配的模型使能 npu RoPE 融合算子。对于未适配的模型,如有需要,您可根据示例以及[开发者文档](../../dev-guide/plugins/model-plugins/kernels.md)自行适配。
|
||||
|
||||
|
||||
## NpuFusedMoE
|
||||
MoE(Mixture of Experts)模型通过稀疏激活扩展容量。在原生 Transformers 实现中,使用串行循环遍历专家,导致内核启动开销大、硬件利用率低。
|
||||
|
||||
**MoE 融合算子** 利用 **GMM(Grouped Matrix Multiplication,分组矩阵乘)** 技术,支持在单个硬件指令内并行处理多组不同形状(行数不一)的矩阵乘法,消减循环开销,同时无需额外的显存复制,显著提升训练性能。
|
||||
|
||||
Ascend npu 通过 `torch_npu.npu_grouped_matmul` 等接口提供底层支持,通过替换模型中的 MoE Block forward 方法,即可利用 NPU 的分组矩阵乘能力。
|
||||
|
||||
核心逻辑替换如下(简化示意):
|
||||
|
||||
```python
|
||||
def _npu_moe_forward(self, hidden_states, routing_weights, router_indices):
|
||||
# 1. 排序:将乱序的 Token 按指派的专家归类,并生成索引映射
|
||||
permuted_states, row_map = torch_npu.npu_moe_token_permute(hidden_states, router_indices)
|
||||
|
||||
# 2. 统计:计算每个专家需要处理的 Token 数量
|
||||
tokens_per_expert = torch.histc(router_indices, bins=self.num_experts, min=0, max=self.num_experts)
|
||||
|
||||
# 3. 计算 (GMM):一次性并行计算所有专家的权重,自动适配不同专家的输入长度
|
||||
inter_states = torch_npu.npu_grouped_matmul(permuted_states, self.gate_up_proj_weights, split_sizes=tokens_per_expert, ...)
|
||||
inter_states = torch_npu.npu_swiglu(inter_states)
|
||||
output = torch_npu.npu_grouped_matmul(inter_states, self.down_proj_weights, split_sizes=tokens_per_expert, ...)
|
||||
|
||||
# 4. 还原:将结果恢复成原始 Token 顺序并应用路由权重
|
||||
return torch_npu.npu_moe_token_unpermute(output, row_map, routing_weights)
|
||||
```
|
||||
|
||||
在 LLaMA-Factory 中,通过 `NpuFusedMoEKernel` 提供使能该融合算子的入口。只需要调用 `apply_kernel("npu_fused_moe", model=model)` 即可针对已适配的模型使能 NPU MoE 融合算子。对于未适配的模型,您也可以参考上述示例代码以及[开发者文档](../../dev-guide/plugins/model-plugins/kernels.md)自行适配。
|
||||
@@ -1 +0,0 @@
|
||||
# Triton
|
||||
@@ -1 +0,0 @@
|
||||
# DeepSpeed
|
||||
@@ -1 +0,0 @@
|
||||
# FSDP
|
||||
@@ -1,215 +0,0 @@
|
||||
# FSDPTurbo EP/EFSDP 与 LlamaFactory FSDP2/CP 设计说明
|
||||
|
||||
English version: [FSDPTurbo EP/EFSDP and LlamaFactory FSDP2/CP Design](../../../en/advanced/distributed/fsdpturbo-ep-efsdp.md)
|
||||
|
||||
本文描述 `fsdpturbo` distributed plugin 的当前实现。核心原则是保持两侧职责清晰:
|
||||
|
||||
- FSDPTurbo 负责专家并行(EP)、专家参数分片(EFSDP)和设备算子注册。
|
||||
- LlamaFactory 负责进程初始化、基础 DeviceMesh、外层 FSDP2、CP、模型初始化与权重加载。
|
||||
- LlamaFactory 的集成层负责把两套参数布局组合起来,并处理跨 Mesh 的梯度范数。
|
||||
|
||||
## 1. 配置边界
|
||||
|
||||
公共并行拓扑放在 `TrainingArguments` 顶层,FSDPTurbo 私有参数保留在 `dist_config`:
|
||||
|
||||
```yaml
|
||||
cp_size: 1
|
||||
|
||||
dist_config:
|
||||
name: fsdpturbo
|
||||
ep_size: 16
|
||||
ep_dispatcher: eager
|
||||
```
|
||||
|
||||
最小示例中的字段职责如下:
|
||||
|
||||
- `ep_size`:专家并行组大小。
|
||||
- `ep_dispatcher`:FSDPTurbo EP dispatcher,默认为 `eager`。
|
||||
|
||||
`dp_size`、`cp_size`、`cp_mode`、`mp_replicate_size`、`mp_shard_size` 和 `dist_timeout`
|
||||
属于公共拓扑字段,继续放在顶层。`dist_config` 会被严格解析为 `FSDPTurboParams`;如果把公共拓扑
|
||||
字段误放进去,会直接报错,而不是静默忽略。
|
||||
|
||||
顶层训练参数 `bf16` 同时控制 FSDPTurbo 的参数存储和计算 dtype。backend 会在 FSDP materialization
|
||||
前完成模型 dtype 转换,因此 `ModelEngine` 不需要读取 distributed backend 配置。
|
||||
|
||||
以下高级字段为可选项,因此没有写入上面的最小 YAML 示例:
|
||||
|
||||
- `fsdp_ignored_modules`:额外排除在 LlamaFactory 外层 FSDP2 之外的模块。模型规格选中的专家参数
|
||||
会被集成层自动加入忽略集合,普通配置无需重复填写。
|
||||
- `hook_modules`:FSDPTurbo EFSDP hook 的可选模块模式,默认为空列表。
|
||||
- `fsdp_implementation`:FSDPTurbo EFSDP 实现,可选 `native` 或 `custom`,默认为 `native`。
|
||||
|
||||
EFSDP 的目标由模型规格决定。Attention、Embedding、LM Head 等非专家参数不进入 FSDPTurbo
|
||||
EFSDP plan,而是继续由 LlamaFactory 外层 FSDP2 管理。
|
||||
|
||||
模型相关的模块路径和准备逻辑统一由 `FSDPTurboEPModelSpec` 注册表管理。当前内置 `qwen3_moe`
|
||||
和 `qwen3_5_moe`;未注册的模型会明确报错。`ep_modules` 和 `ep_fsdp_modules` 不属于 YAML
|
||||
接口,严格参数解析会拒绝这两个字段,避免用户配置与模型实际结构失配。
|
||||
|
||||
## 2. Mesh 初始化
|
||||
|
||||
LlamaFactory 的 `DistributedInterface` 只初始化自身原有的 model/data mesh。它不感知 EP、EFSDP,
|
||||
也不为 distributed plugin 提供额外 mesh 注册接口。FSDPTurbo 的专家拓扑由插件文件内的
|
||||
`FSDPTurboParallelState` 独立创建和持有:
|
||||
|
||||
```text
|
||||
run_sft / run_dpo / run_rm
|
||||
-> DistributedInterface(training_args)
|
||||
-> 初始化 LlamaFactory model/data mesh
|
||||
-> DistributedPlugin("fsdpturbo").shard_model(...)
|
||||
-> FSDPTurboFSDP2Engine.__init__()
|
||||
-> FSDPTurboParallelState.initialize()
|
||||
-> 初始化并保存 expert parent mesh 及其子 mesh
|
||||
```
|
||||
|
||||
`FSDPTurboParallelState` 创建专家侧四维父 Mesh:
|
||||
|
||||
```text
|
||||
(edp, efsdp, ep, expert_cp)
|
||||
```
|
||||
|
||||
当前尺寸计算为:
|
||||
|
||||
```text
|
||||
dp_size = world_size / cp_size
|
||||
ep_fsdp_size = dp_size / ep_size
|
||||
edp_size = dp_size / (ep_size * ep_fsdp_size)
|
||||
mesh_shape = (edp_size, ep_fsdp_size, ep_size, cp_size)
|
||||
```
|
||||
|
||||
状态对象保存 `edp_mesh`、`efsdp_mesh`、`ep_mesh` 和 `expert_cp_mesh`。插件内部模型切分和梯度范数
|
||||
都从这个状态对象读取专家通信域;LlamaFactory 其他 backend 不需要实现或感知这些接口。状态初始化
|
||||
会校验 `ep_size` 为正数且能够整除 `dp_size`,重复初始化时也会拒绝拓扑发生变化。
|
||||
|
||||
## 3. 模型切分顺序
|
||||
|
||||
模型包装顺序必须保持为“专家侧优先,外层 FSDP2 随后”:
|
||||
|
||||
```text
|
||||
DistributedPlugin("fsdpturbo")
|
||||
-> FSDPTurboFSDP2Engine.shard_model(model)
|
||||
-> prepare_model_ep(model)
|
||||
-> expert_parallelize_modules(model, ep_mesh, ep_plan)
|
||||
-> expert_fully_shard_modules(model, efsdp_mesh, ep_plan, fsdp_plan)
|
||||
-> 收集专家参数作为 ignored_params
|
||||
-> FSDP2Engine.prepare_model(model, ignored_params=...)
|
||||
-> 对剩余 Transformer Layer 和根模块执行 outer fully_shard
|
||||
```
|
||||
|
||||
这样可以避免同一专家参数同时被 EFSDP 和外层 FSDP2 管理。外层 FSDP2 仍复用 LlamaFactory
|
||||
原有的初始化、checkpoint 和保存流程。
|
||||
|
||||
LlamaFactory 集成层接受 `eager`、`fused`、`mc2` 和 `domino`,并将选项原样传给
|
||||
FSDPTurbo。这四种模式的实现边界和当前验证状态不同:
|
||||
|
||||
| Dispatcher | 主要路径 | 额外要求 | 本 PR 验证状态 |
|
||||
| --- | --- | --- | --- |
|
||||
| `eager` | 使用 PyTorch 实现 permute、unpermute 和 grouped matmul,张量仍在当前加速设备上,通过标准 AllToAll 完成 token dispatch/combine | 依赖最少,用作参考实现 | 已在 A3 上完成精度和性能验证 |
|
||||
| `fused` | 保持相同的 AllToAll 拓扑,将 permute、unpermute 和 grouped matmul 切换为设备融合算子 | 需要对应的设备算子、dtype 和 layout 支持;存在空专家时可回退到 eager 局部算子 | 已在 A3 上完成精度和性能验证 |
|
||||
| `mc2` | 使用专用算子融合 AllToAllV 和 grouped matmul,减少通信与计算之间的中间开销 | 依赖 MC2 NPU 算子、HCCL communicator 以及对应的 shape/dtype 约束 | FSDPTurbo 提供实现,本 PR 未做端到端验证 |
|
||||
| `domino` | 将专家模块输入的第一维分成两片,使用独立通信流和 event 重叠 AllToAll 与专家计算 | 需要异步 stream/event 支持,且两个分片都要有足够的 token 工作量才能覆盖调度开销 | FSDPTurbo 提供实现,本 PR 未做端到端验证 |
|
||||
|
||||
当前只验证 `eager` 和 `fused`,是因为它们分别覆盖参考实现和 A3 常用设备融合路径,可用于隔离并验证
|
||||
LlamaFactory 与 FSDPTurbo 之间的 EP/EFSDP 集成正确性。本次实验矩阵没有继续扩展到 `mc2` 和
|
||||
`domino`:它们还引入了额外的算子、通信调度和输入形状约束,需要独立比较数值、长步稳定性和 profiler 结果。
|
||||
因此,它们在配置接口上可选,但不应从本 PR 的实验结果推断为已达到相同的稳定性、精度或性能水平。
|
||||
|
||||
## 4. FSDPTurbo 依赖入口
|
||||
|
||||
LlamaFactory 从各功能的定义模块直接导入所需对象:
|
||||
|
||||
```python
|
||||
from fsdp_turbo.distributed.expert_parallel.expert_fully_shard_parallel import (
|
||||
expert_fully_shard_modules,
|
||||
)
|
||||
from fsdp_turbo.distributed.expert_parallel.expert_parallel import expert_parallelize_modules
|
||||
from fsdp_turbo.fsdp_turbo_config import EPPlanConfig, FSDPPlanConfig
|
||||
from fsdp_turbo.utils.str_match import module_name_match
|
||||
```
|
||||
|
||||
导入发生在 `prepare_model_ep()` 内,因此没有安装 FSDPTurbo 时,其他 distributed backend 仍可正常导入。
|
||||
这里不通过 `fsdp_turbo.distributed.__init__` 聚合导出,避免 package 初始化期间的额外依赖和潜在循环导入。
|
||||
|
||||
## 5. 梯度范数
|
||||
|
||||
外层参数和专家参数可能属于不同 DTensor Mesh,不能直接放入一次标准 `clip_grad_norm_()`。
|
||||
`fsdpturbo` plugin 按参数所属 Mesh 分组计算局部 p 次方和:
|
||||
|
||||
- 非专家参数沿 DP 和 CP group 汇总。
|
||||
- 专家参数沿 `FSDPTurboParallelState` 保存的 EFSDP、EP 和 expert-CP group 汇总。
|
||||
- 汇总得到全局范数后,对所有本地梯度应用同一个 clipping coefficient。
|
||||
|
||||
启动阶段会执行一次零梯度 warmup,使相关 collective 在正式训练前完成初始化。
|
||||
当前这是 `fsdpturbo` backend 的专用实现;其他 backend 继续保留原有梯度范数路径,等待上游
|
||||
distributed plugin 解耦后再统一公共接口。
|
||||
|
||||
## 6. 权重加载
|
||||
|
||||
LlamaFactory 保留 `init_on_meta` 和 safetensors 加载流程。父类 `FSDP2Engine` 的加载器通过
|
||||
`self._copy_weights(...)` 动态调用 FSDPTurbo engine 的覆写实现,因此该方法不是未使用代码。
|
||||
它支持包含多个 `Shard` placement 的 DTensor,按各 Mesh 维度依次计算当前 rank 对应的本地切片。
|
||||
模型保存和 checkpoint 接口继续复用 LlamaFactory FSDP2 实现。
|
||||
|
||||
## 7. Kernel plugin
|
||||
|
||||
FLA 算子不属于 distributed config。算子选择通过独立的 `kernel_config` 完成:
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: auto, flash-linear-attention
|
||||
include_kernels: chunk_gated_delta_rule, fused_recurrent_gated_delta_rule
|
||||
chunk_size: 32
|
||||
```
|
||||
|
||||
调用链如下:
|
||||
|
||||
```text
|
||||
ModelEngine
|
||||
-> apply_kernels("auto, flash-linear-attention")
|
||||
-> LlamaFactory 当前加速器对应的 auto kernels
|
||||
-> KernelPlugin("flash-linear-attention").apply(...)
|
||||
-> fsdp_turbo.ops.get_op()
|
||||
-> FSDPTurbo device operator registry
|
||||
-> fsdp_turbo.utils.patch.patch_model_members()
|
||||
-> FLA backend implementation
|
||||
```
|
||||
|
||||
`chunk_size` 当前支持 `16`、`32` 和 `64`,默认值为 `64`。Kernel plugin 与 distributed plugin
|
||||
彼此独立。`name: flash-linear-attention` 只安装所选 FLA 算子;逗号分隔的
|
||||
`name: auto, flash-linear-attention` 会在分布式切分前组合 LlamaFactory 当前加速器的 auto kernels
|
||||
与 FLA plugin。LlamaFactory 负责算子名到模型属性的映射和 `chunk_size` 参数绑定;FSDPTurbo 负责设备
|
||||
算子注册、选择和通用 callable patch。FLA 依赖可选的外部三方件,因此保持显式选择,不属于内置
|
||||
`auto` 集合。FSDPTurbo
|
||||
随后会替换目标专家模块的 `forward`,所以专家计算的最终路径由 `ep_dispatcher` 决定;auto 阶段
|
||||
应用的 MoE kernel 不会作为独立的第二条专家执行路径保留下来。
|
||||
|
||||
## 8. CP 运行约束与验证范围
|
||||
|
||||
`init_on_meta` 构造模型时必须与 `from_pretrained` 路径一样传递 `attn_implementation`,否则模型会退回
|
||||
非 FlashAttention 实现,Ulysses CP 无法启动。Ulysses 在调用 Hugging Face FlashAttention 前重建全局
|
||||
attention mask;只有二维 position IDs 才参与 packed-sequence 检测。Qwen3.5 mRoPE 等多轴 position IDs
|
||||
已经在 rotary embedding 中消费,不应传入 FlashAttention 的 packed-sequence 检测逻辑。
|
||||
|
||||
当前实现已在 Atlas 900 A3 SuperPoD 和 Atlas 950 SuperPoD 上用 Qwen3.5-35B-A3B 完成以下
|
||||
BF16、AdamW full SFT 验证。本次重验证使用 FSDPTurbo `0e96fbc`;A3 环境为 CANN 9.0.0、
|
||||
PyTorch 2.7.1 和 torch-npu 2.7.1.post4,A5 环境为 CANN 9.1.0-beta.3、PyTorch 2.10.0 和
|
||||
torch-npu 2.10.0.post2。表中性能按第 1 步至第 100 步的日志时间戳计算,不包含首步前的初始化、
|
||||
编译和训练后的模型保存时间:
|
||||
|
||||
| 机器型号 | CP | EP | EFSDP | Checkpoint | Kernel / Dispatcher | 步数 | Loss(首步 -> 末步) | 性能 | 结果 |
|
||||
| --- | ---: | ---: | ---: | --- | --- | ---: | --- | ---: | --- |
|
||||
| Atlas 900 A3 SuperPoD | 1 | 16 | 1 | 关闭 | FLA(chunk size 16)/ eager | 100 | 1.3361 -> 0.0793 | 2.51 s/it | 通过并完成保存 |
|
||||
| Atlas 900 A3 SuperPoD | 1 | 16 | 1 | 关闭 | FLA(chunk size 16)/ fused | 100 | 1.3354 -> 0.1179 | 2.17 s/it | 通过并完成保存 |
|
||||
| Atlas 900 A3 SuperPoD | 2 | 4 | 2 | 关闭 | auto + FLA(chunk size 64)/ fused | 100 | 1.8114 -> 0.5260 | 7.65 s/it | 通过并完成保存 |
|
||||
| Atlas 900 A3 SuperPoD | 2 | 4 | 2 | 关闭 | auto + FLA(chunk size 64)/ eager | 100 | 1.8095 -> 0.5596 | 5.88 s/it | 通过并完成保存 |
|
||||
| Atlas 950 SuperPoD | 1 | 8 | 1 | 关闭 | 未配置 kernel plugin / eager | 100 | 1.3575 -> 0.4439 | 2.68 s/it | 通过并完成保存 |
|
||||
|
||||
五组训练的 loss 和 grad norm 均保持有限,并完成 100 步及模型保存。同一切分下,EP16 eager/fused
|
||||
的逐步 loss 相关系数为 0.997,CP2/EP4/EFSDP2 eager/fused 为 0.977,说明两种 dispatcher 的
|
||||
优化轨迹一致。性能收益与切分有关:EP16 下 fused 比 eager 快约 13%,而加入 CP 和 EFSDP 后 fused
|
||||
比 eager 慢约 30%,因此不能把 fused 视为所有 mesh 的默认最优选择。
|
||||
|
||||
EP16 两组使用 global batch 16 和 cutoff length 256;CP2 两组使用 global batch 8 和 cutoff length
|
||||
128;A5 组使用 global batch 8 和 cutoff length 256。因此,首末 loss 用于验证各组自身的收敛趋势,
|
||||
不同切分组之间的绝对 loss 不应直接作为精度等价结论。
|
||||
@@ -1 +0,0 @@
|
||||
# Parallel(DP, TP, EP, SP, CP)
|
||||
@@ -1,119 +0,0 @@
|
||||
# KTransformers LoRA SFT
|
||||
|
||||
KTransformers(KT)将 MoE routed experts 放在 CPU 执行,LLaMA-Factory 继续负责数据、LoRA 参数和训练入口。
|
||||
当前生产范围是 routed-BF16 LoRA 与 routed-INT8 LoRA;Accelerate 配置只负责 FSDP2,不再保存 KT 参数。
|
||||
|
||||
## 安装检查
|
||||
|
||||
必须同时安装带 KT 公共接口的 `ktransformers`、`transformers-kt` 和 `accelerate-kt`。启动前可检查:
|
||||
|
||||
```bash
|
||||
python - <<'PY'
|
||||
from accelerate import Accelerator
|
||||
from kt_kernel.sft import resolve_kt_pretrained_artifacts
|
||||
from transformers import TrainingArguments
|
||||
|
||||
assert hasattr(TrainingArguments, "update_kt_config")
|
||||
assert "adapter_only" in __import__("inspect").signature(Accelerator.get_state_dict).parameters
|
||||
print(resolve_kt_pretrained_artifacts)
|
||||
PY
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
KT 只有一个用户配置源:训练 YAML。LoRA rank、alpha、dropout 和 runtime capacity 由 LLaMA-Factory
|
||||
标准字段派生;不要在 `kt_config` 中重复填写。
|
||||
|
||||
BF16 示例:
|
||||
|
||||
```yaml
|
||||
finetuning_type: lora
|
||||
lora_rank: 8
|
||||
lora_alpha: 16
|
||||
lora_target: all
|
||||
|
||||
use_kt: true
|
||||
disable_gradient_checkpointing: false
|
||||
kt_cpu_activation: retain
|
||||
kt_config:
|
||||
kt_expert_weight_format: bf16
|
||||
kt_backend: AMXBF16
|
||||
kt_num_threads: 96
|
||||
kt_tp_enabled: true
|
||||
kt_threadpool_count: 2
|
||||
kt_max_cache_depth: 2
|
||||
```
|
||||
|
||||
INT8 还需要相互匹配的 routed expert 与 BF16 non-expert cache:
|
||||
|
||||
```yaml
|
||||
kt_weight_path: /abs/path/to/routed-int8-experts
|
||||
kt_non_expert_weight_path: /abs/path/to/bf16-non-expert-cache
|
||||
kt_config:
|
||||
kt_expert_weight_format: int8
|
||||
kt_backend: auto
|
||||
kt_weight_lifecycle: persistent
|
||||
```
|
||||
|
||||
完整配置见:
|
||||
|
||||
- `examples/ktransformers/train_lora/qwen3_5moe_lora_sft_kt.yaml`
|
||||
- `examples/ktransformers/train_lora/deepseek_v3_int8_lora_sft_kt.yaml`
|
||||
|
||||
Activation 策略:
|
||||
|
||||
| `disable_gradient_checkpointing` | `kt_cpu_activation` | CPU / GPU |
|
||||
| --- | --- | --- |
|
||||
| `false` | `recompute` 或省略 | recompute / recompute |
|
||||
| `false` | `retain` | retain / recompute |
|
||||
| `true` | `retain` 或省略 | retain / retain |
|
||||
| `true` | `recompute` | 不支持,启动前报错 |
|
||||
|
||||
## 启动与复用
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0,1 accelerate launch \
|
||||
--config_file examples/ktransformers/accelerate/fsdp2_kt_bf16.yaml \
|
||||
src/train.py examples/ktransformers/train_lora/qwen3_5moe_lora_sft_kt.yaml
|
||||
```
|
||||
|
||||
输出 adapter 同时包含 standard PEFT 与 fused expert LoRA。
|
||||
|
||||
## 新进程加载
|
||||
|
||||
对话或评测必须使用本地的完整 KT adapter 目录,并重复训练时的 LoRA 形状配置:`finetuning_type`、
|
||||
`lora_rank`、`lora_alpha`、`lora_dropout`,以及相同的 KT base weight 配置。routed INT8 尤其要沿用训练时
|
||||
的 `kt_weight_path` 和 `kt_non_expert_weight_path`。
|
||||
|
||||
```yaml
|
||||
model_name_or_path: /abs/path/to/base-model
|
||||
adapter_name_or_path: /abs/path/to/output/checkpoint-300
|
||||
finetuning_type: lora
|
||||
lora_rank: 8
|
||||
lora_alpha: 16
|
||||
lora_dropout: 0.0
|
||||
|
||||
use_kt: true
|
||||
kt_cpu_activation: retain
|
||||
kt_config:
|
||||
kt_expert_weight_format: bf16
|
||||
kt_backend: AMXBF16
|
||||
kt_num_threads: 96
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli chat path/to/kt_adapter_infer.yaml
|
||||
llamafactory-cli eval path/to/kt_adapter_eval.yaml
|
||||
```
|
||||
|
||||
目录必须包含 standard PEFT adapter 文件;使用 fused routed-expert LoRA 时,还必须包含
|
||||
`fused_expert_lora.safetensors` 和 `kt_adapter_manifest.json`。LLaMA-Factory 先加载 standard PEFT,随后由
|
||||
KT 校验并恢复 fused artifact。`adapter_folder` 可以选择本地子目录;越出 adapter 根目录的路径和 Hub
|
||||
adapter ID 会在加载模型前报错,Hub bundle 需要先完整下载到本地。
|
||||
|
||||
续训应保留原训练 YAML,并使用 `resume_from_checkpoint`。分布式 optimizer checkpoint 暂要求相同 world
|
||||
size。artifact 缺失、hash 不匹配或来源模型不一致时会直接失败,不会退回源 checkpoint。
|
||||
|
||||
不要同时启用 Transformers/FSDP activation checkpointing、Unsloth GC,也不要把 `kt_config` 放入
|
||||
Accelerate YAML。每次训练都应确认 loss/grad finite、base model 未修改,并验证 standard/router/fused LoRA
|
||||
均包含非零更新。
|
||||
@@ -1,3 +0,0 @@
|
||||
# Lora
|
||||
|
||||
参数管理(二级参数形式)
|
||||
@@ -1 +0,0 @@
|
||||
# Quantization
|
||||
37
docs/zh/configuration/data.md
Normal file
37
docs/zh/configuration/data.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# 数据参数
|
||||
|
||||
## DataArguments
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `train_dataset` | `str \| None` | `None` | 训练数据集路径、YAML 或 Hub ID |
|
||||
| `eval_dataset` | `str \| None` | `None` | 字段已定义;评估流程尚未实现 |
|
||||
|
||||
## DatasetInfo
|
||||
|
||||
数据集 YAML 的每个顶层条目使用以下字段:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `path` | `str` | 必填 | 本地路径或 Hub ID |
|
||||
| `source` | `local \| hf_hub` | `hf_hub` | 数据来源 |
|
||||
| `split` | `str` | `train` | 数据集 split |
|
||||
| `converter` | `str \| None` | `None` | `alpaca`、`sharegpt`、`pair` 或已注册名称 |
|
||||
| `size` | `int \| None` | 全部 | 重采样后的目标索引数量 |
|
||||
| `weight` | `float` | 不设置 | 索引数量的缩放倍率 |
|
||||
| `streaming` | `bool` | `false` | 字段已定义;当前训练路径不支持 streaming 数据集 |
|
||||
|
||||
### 采样规模的计算
|
||||
|
||||
`size` 和 `weight` 作用于数据集展开后的训练索引。多轮 SFT 中,每个受监督的 assistant turn 对应一个索引条目,因此索引数量可能大于原始数据的行数;偏好对数据则以一组 chosen/rejected 为一个条目。
|
||||
|
||||
使用正数 `size`、`weight` 时,按以下顺序计算:
|
||||
|
||||
1. 设置 `size` 后,先从展开后的索引中有放回抽取 `size` 个条目;省略时保留完整索引。
|
||||
2. 设置 `weight` 后,再从上一步结果中有放回抽取 `int(当前条目数 × weight)` 个条目,小数部分向下取整;省略时保留上一步结果。
|
||||
|
||||
例如,`size: 1000` 与 `weight: 0.5` 同时设置时,先抽取 1000 个条目,再抽取其中的 500 个条目。最终规模为 500,但可能包含重复条目,也可能没有覆盖某些原始记录。
|
||||
|
||||
`weight` 控制每个数据集贡献的索引数量,不是各数据集之间归一化后的抽样概率,也不改变样本的损失权重。`weight > 1` 可以增加索引数量。显式设置 `weight: 1.0` 仍会执行有放回重采样;省略 `size` 和 `weight` 才会直接保留全部展开后的索引。
|
||||
|
||||
数据格式和多数据集组合方式见[数据准备](../feature-guide/data_preparation.md)。
|
||||
30
docs/zh/configuration/index.md
Normal file
30
docs/zh/configuration/index.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 参数说明
|
||||
|
||||
v1 使用一份 YAML 同时描述数据、模型、训练和推理配置。顶层字段来自四个参数类。`peft_config`、`quant_config`、`kernel_config`、`dist_config` 等插件配置通过 `name` 选择具体实现,其余字段由对应实现解析;可用名称和字段统一列在所属的参数页面中。
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
train_dataset: data/v1_sft_demo.yaml
|
||||
|
||||
output_dir: outputs/qwen3_sft
|
||||
micro_batch_size: 1
|
||||
learning_rate: 1.0e-4
|
||||
max_steps: 10
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
|
||||
kernel_config:
|
||||
name: liger_kernel
|
||||
```
|
||||
|
||||
## 参数分类
|
||||
|
||||
| 页面 | 参数 |
|
||||
|------|------|
|
||||
| [数据参数](data.md) | `DataArguments`、`DatasetInfo` |
|
||||
| [模型参数](model.md) | `ModelArguments`、PEFT、量化、初始化和 Kernel |
|
||||
| [训练参数](training.md) | `TrainingArguments`、分布式和优化器 |
|
||||
| [推理参数](inference.md) | `SampleArguments` |
|
||||
|
||||
功能指南中的示例只列出完成对应任务所需的字段。字段类型、默认值和可用选项以本目录为准。
|
||||
10
docs/zh/configuration/inference.md
Normal file
10
docs/zh/configuration/inference.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 推理参数
|
||||
|
||||
## SampleArguments
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `sample_backend` | `str` | `hf` | 采样后端;可用值为 `hf` |
|
||||
| `max_new_tokens` | `int` | `128` | 单次最多生成 token 数 |
|
||||
|
||||
使用方法见[推理](../feature-guide/inference.md)。
|
||||
119
docs/zh/configuration/model.md
Normal file
119
docs/zh/configuration/model.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# 模型参数
|
||||
|
||||
## ModelArguments
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `model` | `str` | `Qwen/Qwen3-4B-Instruct-2507` | 本地模型路径或 Hub ID |
|
||||
| `custom_chat_template` | `str \| None` | `None` | 覆盖 tokenizer/processor 的 Jinja2 chat template |
|
||||
| `trust_remote_code` | `bool` | `false` | 是否加载 Hub 远端代码 |
|
||||
| `flash_attn` | `str` | `sdpa` | `eager`、`sdpa` 或 `flash_attention_2` |
|
||||
| `model_class` | `str` | `llm` | `llm`、`cls` 或 `other` |
|
||||
| `init_config` | `dict \| None` | `None` | 模型初始化配置 |
|
||||
| `peft_config` | `dict \| None` | `None` | LoRA 或 Freeze 配置 |
|
||||
| `kernel_config` | `dict \| None` | `None` | 融合算子加速配置 |
|
||||
| `quant_config` | `dict \| None` | `None` | 量化配置 |
|
||||
|
||||
`llm` 加载因果语言模型或 image-to-text 模型,`cls` 加载单标签 token
|
||||
classification 模型,`other` 使用 `AutoModel`。
|
||||
|
||||
## peft_config
|
||||
|
||||
### LoRA
|
||||
|
||||
设置 `name: lora`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `r` | `int` | `8` | LoRA rank |
|
||||
| `lora_alpha` | `int` | `16` | LoRA alpha |
|
||||
| `lora_dropout` | `float` | `0.05` | LoRA dropout |
|
||||
| `target_modules` | `list[str] \| str` | `all` | 目标模块 |
|
||||
| `use_rslora` | `bool` | `false` | 是否启用 RS-LoRA |
|
||||
| `use_dora` | `bool` | `false` | 是否启用 DoRA |
|
||||
| `modules_to_save` | `list[str] \| None` | `None` | 额外保存模块 |
|
||||
| `adapter_name_or_path` | `list[str] \| str \| None` | `None` | adapter 路径 |
|
||||
| `export_dir` | `str \| None` | `None` | 合并导出目录 |
|
||||
| `export_size` | `int` | `5` | 导出分片大小,GB |
|
||||
| `export_hub_model_id` | `str \| None` | `None` | Hub 仓库 ID |
|
||||
| `infer_dtype` | `str` | `auto` | `auto`、`float16`、`float32` 或 `bfloat16` |
|
||||
| `export_legacy_format` | `bool` | `false` | 是否使用旧式权重格式 |
|
||||
|
||||
### Freeze
|
||||
|
||||
设置 `name: freeze`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `freeze_trainable_layers` | `int` | `2` | 正数选择最后 N 层,负数选择最前 N 层 |
|
||||
| `freeze_trainable_modules` | `list[str] \| str` | `all` | 层内可训练模块 |
|
||||
| `freeze_extra_modules` | `list[str] \| str \| None` | `[]` | 额外可训练模块 |
|
||||
| `cast_trainable_params_to_fp32` | `bool` | `true` | 是否将可训练参数转换为 fp32 |
|
||||
|
||||
## quant_config
|
||||
|
||||
当前 v1 注册了 `bnb` 和 `auto` 两个量化插件入口。`bnb` 使用 bitsandbytes;`auto` 在指定有效位宽后也转交 `bnb`,当前没有按模型或环境切换到其他量化后端的逻辑。
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `name` | `str` | 必填 | `bnb` 或 `auto` |
|
||||
| `quantization_bit` | `int \| None` | `None` | 量化加载位宽,4 或 8 |
|
||||
| `compute_dtype` | `str \| torch.dtype` | `float16` | 4-bit 计算和存储 dtype |
|
||||
| `double_quantization` | `bool` | `true` | 是否启用 4-bit double quant |
|
||||
| `quantization_type` | `str` | `nf4` | 4-bit 量化格式,`nf4` 或 `fp4` |
|
||||
|
||||
4-bit 分支将 `compute_dtype`、`double_quantization` 和 `quantization_type` 传给 [Hugging Face BitsAndBytesConfig](https://huggingface.co/docs/transformers/main_classes/quantization#transformers.BitsAndBytesConfig),其中 NF4 和 FP4 是 bitsandbytes 的两种 4-bit 格式。8-bit 分支设置 `load_in_8bit=True`,不使用这三个 4-bit 专属字段。
|
||||
|
||||
`quantization_bit` 的字段默认值为 `None`,实际行为取决于 `name`:
|
||||
|
||||
- 不设置 `quant_config` 或将其设为 `null` 时,不通过此插件添加量化加载配置。
|
||||
- `name: auto` 且省略 `quantization_bit`(或设为 `null`)时,保持模型加载参数不变。
|
||||
- `name: bnb` 且省略 `quantization_bit`(或设为 `null`)时,使用 4-bit 量化。
|
||||
- `name: auto` 且指定 `quantization_bit` 为 `4` 或 `8` 时,转交 `bnb` 实现处理,仍需满足该实现的依赖和运行条件。
|
||||
|
||||
以上描述插件构造量化加载配置的行为。[SFT 的 QLoRA 示例](../feature-guide/sft.md#qlora)展示 `bnb`、4-bit、NF4 与 LoRA 的组合。
|
||||
|
||||
## init_config
|
||||
|
||||
`init_config` 当前只使用 `name` 选择模型初始化设备:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `name` | `str` | 必填 | 初始化插件名称 |
|
||||
|
||||
| `name` 取值 | 初始化设备 |
|
||||
|-------------|------------|
|
||||
| `init_on_default` | 当前分布式设备 |
|
||||
| `init_on_meta` | meta device |
|
||||
| `init_on_rank0` | rank 0 使用 CPU,其余 rank 使用 meta |
|
||||
|
||||
meta 初始化不能与量化同时使用。
|
||||
|
||||
## kernel_config
|
||||
|
||||
`kernel_config` 可以配置单个融合算子,也可以启用 Liger Kernel 这类包含多项优化的外部加速库。
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `name` | `str` | 必填 | `auto`、单个实现名称或逗号分隔的多个名称 |
|
||||
|
||||
可用名称:
|
||||
|
||||
- `liger_kernel`
|
||||
- `cuda_fused_moe`
|
||||
- `flash-linear-attention`
|
||||
- `npu_fused_moe`
|
||||
- `npu_fused_rmsnorm`
|
||||
- `npu_fused_rope`
|
||||
- `npu_fused_swiglu`
|
||||
|
||||
### Flash Linear Attention
|
||||
|
||||
当 `name` 包含 `flash-linear-attention` 时,可以使用以下专属字段:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `include_kernels` | `str` | `auto` | `auto` 或逗号分隔的 FLA 算子名称 |
|
||||
| `chunk_size` | `int` | `64` | chunk size;可选 `16`、`32`、`64` |
|
||||
|
||||
用法见[融合算子加速](../feature-guide/kernel_acceleration.md)。
|
||||
125
docs/zh/configuration/training.md
Normal file
125
docs/zh/configuration/training.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# 训练参数
|
||||
|
||||
## TrainingArguments
|
||||
|
||||
### 训练过程与精度
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `output_dir` | `str` | `outputs/<uuid>` | 输出目录 |
|
||||
| `micro_batch_size` | `int` | `1` | 基础 micro-batch 大小 |
|
||||
| `global_batch_size` | `int \| None` | `None` | 默认 `dp_size × micro_batch_size` |
|
||||
| `cutoff_len` | `int` | `2048` | 最大序列长度 |
|
||||
| `learning_rate` | `float` | `1e-4` | 训练及优化器插件使用的学习率 |
|
||||
| `num_train_epochs` | `int` | `3` | 训练轮数 |
|
||||
| `max_steps` | `int \| None` | `None` | 设置后使用 step 作为终止条件 |
|
||||
| `max_grad_norm` | `float` | `1.0` | 梯度裁剪阈值 |
|
||||
| `bf16` | `bool` | `true` | 是否使用 bf16 |
|
||||
| `seed` | `int` | `42` | 随机种子 |
|
||||
| `full_determinism` | `bool` | `false` | 是否启用完整确定性模式 |
|
||||
|
||||
`global_batch_size` 与 `micro_batch_size` 共同决定每次参数更新需要累积多少个 micro-batch。省略 `global_batch_size` 时,每个 DP 进程每次更新处理一个 micro-batch;显式设置时,它必须能被 `dp_size × micro_batch_size` 整除,每个进程的累积次数为 `global_batch_size / (dp_size × micro_batch_size)`。
|
||||
|
||||
例如,`dp_size: 4`、`micro_batch_size: 2`、`global_batch_size: 32` 对应每个 DP 进程累积 4 个 micro-batch。固定样本数策略下,一次更新共使用 32 条样本;动态策略中的实际样本数随长度变化,`global_batch_size` 仍决定累积次数,token 预算见[批处理策略](../feature-guide/batching.md)。
|
||||
|
||||
### 批处理配置
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `batching_strategy` | `str` | `normal` | `normal`、`padding_free`、`dynamic_batching` 或 `dynamic_padding_free` |
|
||||
| `batching_workers` | `int` | `16` | 数据加载 worker 数 |
|
||||
| `enable_activation_checkpointing` | `bool` | `true` | 是否启用激活值重算 |
|
||||
|
||||
各策略的 token 预算和使用约束见[批处理策略](../feature-guide/batching.md)。
|
||||
|
||||
### 分布式与优化器
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `dist_config` | `dict \| None` | `None` | FSDP2、FSDPTurbo 或 DeepSpeed 配置 |
|
||||
| `dp_size` | `int \| None` | `None` | 默认由 world size 和 `cp_size` 推导 |
|
||||
| `cp_size` | `int` | `1` | Context Parallel 大小 |
|
||||
| `cp_mode` | `str` | `ulysses` | Context Parallel 实现 |
|
||||
| `mp_replicate_size` | `int` | `1` | FSDP 二维 Mesh 的参数复制维度大小 |
|
||||
| `mp_shard_size` | `int \| None` | `None` | FSDP 二维 Mesh 的参数分片维度大小;默认由 world size 推导 |
|
||||
| `dist_timeout` | `int` | `18000` | 进程组初始化超时,秒 |
|
||||
| `optim_config` | `dict \| None` | `None` | 优化器插件 |
|
||||
| `lr_scheduler_config` | `dict \| None` | `None` | 学习率调度插件;当前没有内置实现 |
|
||||
|
||||
### Checkpoint 与日志配置
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `resume_from_checkpoint` | `str \| None` | `None` | checkpoint 路径或 `auto` |
|
||||
| `save_steps` | `int \| None` | `None` | 每 N 个全局 step 保存 |
|
||||
| `save_epochs` | `float \| None` | `None` | 每 N 个 epoch 保存 |
|
||||
| `save_ckpt_as_hf` | `bool` | `false` | 是否在中间 checkpoint 中额外保存 HF 格式模型 |
|
||||
| `save_total_limit` | `int \| None` | `None` | 最多保留数量 |
|
||||
| `logging_steps` | `int` | `1` | 日志间隔 |
|
||||
|
||||
### 偏好优化参数
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `pref_loss` | `str` | `sigmoid` | `sigmoid`、`orpo` 或 `simpo` |
|
||||
| `pref_beta` | `float` | `0.1` | DPO beta |
|
||||
| `pref_ftx` | `float` | `0.0` | SFT 损失系数 |
|
||||
| `simpo_gamma` | `float` | `0.5` | SimPO reward margin |
|
||||
| `dpo_label_smoothing` | `float` | `0.0` | cDPO label smoothing |
|
||||
| `ld_alpha` | `float \| None` | `None` | LD-DPO 长度差异权重 |
|
||||
|
||||
## dist_config
|
||||
|
||||
### FSDP2
|
||||
|
||||
设置 `name: fsdp2`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `reshard_after_forward` | `bool` | `true` | forward 后是否重新分片 |
|
||||
| `offload_params` | `bool` | `false` | 是否 offload 参数 |
|
||||
| `pin_memory` | `bool` | `true` | 是否使用 pinned memory |
|
||||
| `dcp_path` | `str \| None` | `None` | 初始化 DCP 权重路径 |
|
||||
|
||||
### DeepSpeed
|
||||
|
||||
设置 `name: deepspeed`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `config_file` | `str` | 必填 | DeepSpeed JSON 配置 |
|
||||
|
||||
### FSDPTurbo
|
||||
|
||||
设置 `name: fsdpturbo`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `reshard_after_forward` | `bool` | `true` | forward 后是否重新分片 |
|
||||
| `offload_params` | `bool` | `false` | 是否 offload 参数 |
|
||||
| `pin_memory` | `bool` | `true` | 是否使用 pinned memory |
|
||||
| `dcp_path` | `str \| None` | `None` | 初始化 DCP 权重路径 |
|
||||
| `ep_size` | `int` | `1` | 专家并行组大小 |
|
||||
| `ep_dispatcher` | `str` | `eager` | 专家 token dispatcher |
|
||||
| `fsdp_ignored_modules` | `list[str]` | `[]` | 外层 FSDP2 忽略的额外模块 |
|
||||
| `hook_modules` | `list[str]` | `[]` | EFSDP hook 的模块模式 |
|
||||
| `fsdp_implementation` | `str` | `native` | `native` 或 `custom` |
|
||||
|
||||
`dp_size`、`cp_size`、`mp_replicate_size` 和 `mp_shard_size` 是 `TrainingArguments` 字段,不放在 `dist_config` 中。
|
||||
|
||||
## optim_config
|
||||
|
||||
设置 `name: muon`:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `wd` | `float` | `0.1` | weight decay |
|
||||
| `momentum` | `float` | `0.95` | Muon momentum |
|
||||
| `nesterov` | `bool` | `true` | 是否启用 Nesterov |
|
||||
| `ns_steps` | `int` | `5` | Newton-Schulz 步数 |
|
||||
| `adamw_betas` | `list[float]` | `[0.9, 0.95]` | 内部 AdamW betas |
|
||||
| `adamw_eps` | `float` | `1e-8` | 内部 AdamW epsilon |
|
||||
|
||||
学习率统一使用顶层 `learning_rate`。
|
||||
|
||||
Muon 的完整配置示例见[优化器](../feature-guide/optimizer.md)。
|
||||
@@ -1,479 +0,0 @@
|
||||
# LLaMA-Factory v1 数据预处理
|
||||
|
||||
## 总览
|
||||
|
||||
LLaMA-Factory `v1` 采用了全新的数据处理架构,主要包含以下核心组件:
|
||||
|
||||
- **DataEngine**:数据引擎,负责数据集的加载、索引和转换等各种插件的接入和调用,并提供数据访问接口
|
||||
- **DataConverterPlugin**:数据转换器,将非标准格式转换为统一的标准格式
|
||||
- **DataLoaderPlugin**:数据加载插件,支持多种文件格式的加载
|
||||
- **DataIndexPlugin**:数据索引插件,支持数据集的采样和权重调整
|
||||
- **DataSelectorPlugin**:数据选择插件,支持灵活的数据访问方式
|
||||
|
||||
与 LLaMA-Factory `v0` 版本相比,`v1` 版本采用了统一的数据格式(Messages Format),所有数据都会被转换为标准的对话消息列表;此外,`v1` 版本通过 DataEngine 与 Plugin 机制,提供了自定义数据处理流的接口,具有更好的可扩展性和一致性。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [基本用法](#基本用法)
|
||||
- [标准数据格式](#标准数据格式)
|
||||
- [数据集配置文件](#数据集配置文件)
|
||||
- [完整示例](#完整示例)
|
||||
|
||||
---
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 在训练配置文件,可以通过如下方式配置数据集:
|
||||
|
||||
<details open>
|
||||
<summary>方式 1:使用 HF Hub Repo ID</summary>
|
||||
|
||||
直接指定 HF Hub 上的数据集 Repo ID,DataEngine 会自动从 HF Hub 下载并加载数据集。
|
||||
|
||||
注:使用 Repo ID 直接加载的数据集需要为标准格式
|
||||
|
||||
**训练配置文件示例:**
|
||||
|
||||
```yaml
|
||||
# example_sft.yaml
|
||||
|
||||
...
|
||||
|
||||
dataset: llamafactory/v1-sft-demo # HF Hub Repo ID
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>方式 2:使用 HF Hub 上的 YAML 配置文件</summary>
|
||||
|
||||
`dataset`字段指定 HF Hub 上的 `dataset_info.yaml` 的 URI,DataEngine 会自动下载该配置文件并根据其中的配置加载数据集。
|
||||
|
||||
**训练配置文件示例:**
|
||||
|
||||
```yaml
|
||||
# example_sft.yaml
|
||||
|
||||
...
|
||||
|
||||
dataset: llamafactory/v1-sft-demo/dataset_info.yaml # 远程 dataset_info.yaml 路径
|
||||
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>方式 3:使用本地 HF 数据集文件路径</summary>
|
||||
|
||||
`dataset`字段指定本地的数据集文件路径(`.json`、`.jsonl` 等)
|
||||
|
||||
注:直接指定数据集文件路径,要求该数据文件的格式已为标准格式
|
||||
|
||||
**训练配置文件示例:**
|
||||
|
||||
```yaml
|
||||
# example_sft.yaml
|
||||
|
||||
...
|
||||
|
||||
dataset: ~/data/v1_sft_demo.jsonl # 本地数据集文件绝对路径
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>方式 4:使用本地 YAML 配置文件路径</summary>
|
||||
|
||||
`dataset`字段指定本地的 `dataset_info.yaml` 配置文件路径,DataEngine 会根据该配置加载其中的数据集。
|
||||
|
||||
**训练配置文件示例:**
|
||||
|
||||
```yaml
|
||||
# example_sft.yaml
|
||||
|
||||
...
|
||||
|
||||
dataset: ~/data/dataset_info.yaml # 本地 dataset_info.yaml 文件路径
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 标准数据格式
|
||||
|
||||
v1 使用统一的 **Messages 格式**作为标准数据格式。每个样本都是一个包含 `messages` 字段的 JSON 对象。
|
||||
|
||||
针对alpaca、sharegpt、以及dpo等格式的数据,可以通过内置的`DataConverterPlugin`插件,自动将其转化为标准格式,对于其他自定义格式的数据,用户也可通过自定义`DataConverterPlugin`来实现数据格式标准化,这部分内容参见[`DataConverterPlugin`](../dev-guide/plugins/data-plugins.md/#data-converter-plugin)
|
||||
|
||||
### 1. SFT(监督微调)样本格式
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "value": "You are a helpful assistant."}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": "Hello, who are you?"}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "I am an AI assistant."}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 字段说明:
|
||||
|
||||
- **messages**: 消息列表,包含一轮或多轮对话
|
||||
- **role**: 消息角色,可选值:
|
||||
- `"system"`: 系统提示
|
||||
- `"user"`: 用户输入
|
||||
- `"assistant"`: 模型回复
|
||||
- **content**: 内容列表,每个元素包含:
|
||||
- **type**: 内容类型,可选值:
|
||||
- `"text"`: 文本内容
|
||||
- `"image_url"`: 图像 URL(多模态)
|
||||
- `"audio_url"`: 音频 URL(多模态)
|
||||
- `"video_url"`: 视频 URL(多模态)
|
||||
- `"tools"`: 工具描述
|
||||
- `"tool_calls"`: 工具调用
|
||||
- `"reasoning"`: 推理过程
|
||||
- **value**: 具体内容(字符串)
|
||||
- **loss_weight**: 损失权重(浮点数)
|
||||
- `0.0`: 不计算损失(用于提示词部分)
|
||||
- `1.0`: 完全计算损失(用于回复部分)
|
||||
- 可设置为其他值以调整不同部分的学习权重
|
||||
|
||||
- **_dataset_name** (可选): 数据集名称,由 DataEngine 自动添加
|
||||
- **extra_info** (可选): 额外信息字段
|
||||
|
||||
### 2. DPO(偏好对齐)样本格式
|
||||
|
||||
```json
|
||||
{
|
||||
"chosen_messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": "用户提问"}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "更优的回答"}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
],
|
||||
"rejected_messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": "用户提问"}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "较差的回答"}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 多模态支持
|
||||
|
||||
对于多模态数据,可以在 `content` 列表中添加非文本类型的内容:
|
||||
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "value": "这张图片里有什么?"},
|
||||
{"type": "image_url", "value": "path/to/image.jpg"}
|
||||
],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "图片中有一只猫。"}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:`image_url`、`audio_url`、`video_url` 的路径可以是相对路径或绝对路径,具体加载方式由 `DataLoaderPlugin` 决定。
|
||||
|
||||
---
|
||||
|
||||
## 数据集配置文件
|
||||
|
||||
### 1. dataset_info.yaml 配置文件格式
|
||||
|
||||
`dataset_info.yaml` 支持同时配置多个数据集,支持分别从 HF Hub 和本地获取数据集,数据集默认会混合并打乱顺序。
|
||||
|
||||
**示例配置文件:`data/dataset_info.yaml`**
|
||||
|
||||
```yaml
|
||||
# 数据集 1:使用本地文件 + Alpaca 转换器
|
||||
identity:
|
||||
file_name: ~/data/identity.json #本地数据集文件绝对路径
|
||||
converter: alpaca # 使用 alpaca 转换器
|
||||
|
||||
# 数据集 2:指定自定义数据集目录
|
||||
alpaca_en_demo:
|
||||
file_name: ~/data/alpaca_en_demo.json # 数据集文件名
|
||||
converter: alpaca # 转换器插件
|
||||
size: 500 # 只使用 500 个样本
|
||||
weight: 0.5 # 数据集权重,用于控制该数据集的采样频率
|
||||
split: train # 数据集划分,默认为 train
|
||||
streaming: false # 是否流式加载,默认为 false
|
||||
|
||||
# 数据集 3:从 Hugging Face Hub 加载
|
||||
hf_dataset:
|
||||
hf_hub_url: llamafactory/v1-sft-demo # HF repo ID
|
||||
streaming: false
|
||||
|
||||
# 数据集 4:已经是标准格式,无需转换器
|
||||
standard:
|
||||
file_name: ~/data/v1_sft_demo.jsonl # 本地标准数据集文件路径
|
||||
|
||||
# 数据集 5:自定义数据集和 converter 插件
|
||||
custom_dataset:
|
||||
file_name: custom_data.json
|
||||
converter: custom_converter
|
||||
weight: 1.0
|
||||
```
|
||||
|
||||
### 2. 配置字段说明
|
||||
|
||||
#### 数据源配置(二者必选其一):
|
||||
|
||||
- **hf_hub_url** (str): Hugging Face Hub 数据集仓库 ID
|
||||
- 示例:`"llamafactory/v1-sft-demo"`
|
||||
- 如果指定,则从 HF Hub 加载数据集
|
||||
|
||||
- **file_name** (str): 本地文件路径
|
||||
- 支持格式:`.json`、`.jsonl`、`.csv`、`.parquet`、`.arrow`、`.txt`
|
||||
|
||||
#### 可选配置:
|
||||
|
||||
- **split** (str): 数据集划分,默认为 `"train"`
|
||||
- **converter** (str): 数据转换器名称
|
||||
- 可选值:`"alpaca"`(更多转换器持续添加中,也可在 data_plugin 中添加自定义 converter)
|
||||
- 如果不指定,则假定数据已是标准格式
|
||||
- **size** (int): 使用的样本数量,默认使用全部
|
||||
- **weight** (float): 数据集权重,用于混合数据集时的采样频率,默认为 1.0
|
||||
- **streaming** (bool): 是否流式加载,默认为 `False`
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 1. 基础使用示例
|
||||
|
||||
```python
|
||||
from llamafactory.v1.config.data_args import DataArguments
|
||||
from llamafactory.v1.core.data_engine import DataEngine
|
||||
|
||||
# 使用本地 YAML 配置
|
||||
data_args = DataArguments(
|
||||
dataset="~/data/v1_sft_demo.jsonl",
|
||||
cutoff_len=2048
|
||||
)
|
||||
|
||||
# 初始化 DataEngine
|
||||
engine = DataEngine(data_args=data_args)
|
||||
|
||||
# 查看数据集信息
|
||||
print(f"数据集总样本数: {len(engine)}")
|
||||
print(f"数据集列表: {list(engine.datasets.keys())}")
|
||||
|
||||
# 访问数据样本
|
||||
sample = engine[0]
|
||||
print(f"样本格式: {sample.keys()}")
|
||||
print(f"消息列表: {sample['messages']}")
|
||||
|
||||
# 批量访问
|
||||
batch = engine[0:10]
|
||||
print(f"批量样本数: {len(batch)}")
|
||||
```
|
||||
|
||||
### 2. 输出示例
|
||||
|
||||
**查看数据集信息输出:**
|
||||
|
||||
```
|
||||
数据集总样本数: 500
|
||||
数据集列表: ['default']
|
||||
样本格式: dict_keys(['_dataset_name', 'messages'])
|
||||
消息列表: [{'role': 'user', 'content': [{'type': 'text', 'value': 'hi'}], 'loss_weight': 0.0}, {'role': 'assistant', 'content': [{'type': 'text', 'value': 'Hello! I am {{name}}, an AI assistant developed by {{author}}. How can I assist you today?'}], 'loss_weight': 1.0}]
|
||||
批量样本数: 10
|
||||
```
|
||||
|
||||
**访问单个样本输出:**
|
||||
|
||||
```python
|
||||
{
|
||||
'_dataset_name': 'alpaca_en_demo',
|
||||
'messages': [
|
||||
{
|
||||
'role': 'user',
|
||||
'content': [{'type': 'text', 'value': 'What is the capital of France?'}],
|
||||
'loss_weight': 0.0
|
||||
},
|
||||
{
|
||||
'role': 'assistant',
|
||||
'content': [{'type': 'text', 'value': 'The capital of France is Paris.'}],
|
||||
'loss_weight': 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 混合多数据集配置文件示例
|
||||
|
||||
**配置文件:`data/mixed_datasets.yaml`**
|
||||
|
||||
```yaml
|
||||
dataset_1:
|
||||
file_name: alpaca_en_demo.json
|
||||
converter: alpaca
|
||||
weight: 1.0
|
||||
|
||||
dataset_2:
|
||||
file_name: identity.json
|
||||
converter: alpaca
|
||||
weight: 2.0
|
||||
|
||||
dataset_3:
|
||||
hf_hub_url: llamafactory/v1-sft-demo
|
||||
weight: 1.5
|
||||
```
|
||||
|
||||
|
||||
### 4. 多模态数据示例
|
||||
|
||||
**数据文件:`data/multimodal_demo.jsonl`**
|
||||
|
||||
标准化后数据示例:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "value": "Who are they?"},
|
||||
{"type": "image_url", "value": "mllm_demo_data/1.jpg"}
|
||||
],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "value": "They're Kane and Gretzka from Bayern Munich."}
|
||||
],
|
||||
"loss_weight": 1.0
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "value": "What are they doing?"},
|
||||
{"type": "image_url", "value": "mllm_demo_data/1.jpg"}
|
||||
],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "value": "They are celebrating on the soccer field."}
|
||||
],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "value": "Who is he?"},
|
||||
{"type": "image_url", "value": "mllm_demo_data/2.jpg"}
|
||||
],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "value": "He's Thomas Muller from Bayern Munich."}
|
||||
],
|
||||
"loss_weight": 1.0
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "value": "Why is he on the ground?"}
|
||||
],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "value": "Because he's sliding on his knees to celebrate."}
|
||||
],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```python
|
||||
from llamafactory.v1.config.data_args import DataArguments
|
||||
from llamafactory.v1.core.data_engine import DataEngine
|
||||
|
||||
data_args = DataArguments(dataset="data/multimodal_demo.jsonl")
|
||||
engine = DataEngine(data_args=data_args)
|
||||
|
||||
# 访问多模态样本
|
||||
sample = engine[0]
|
||||
print("用户消息内容:")
|
||||
for content_item in sample['messages'][0]['content']:
|
||||
print(f" 类型: {content_item['type']}, 值: {content_item['value']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**注意事项**:
|
||||
|
||||
1. 所有数据最终都会转换为标准的 Messages 格式
|
||||
2. 通过 `converter` 插件可以支持多种数据格式
|
||||
3. 通过 `weight` 和 `size` 参数可以灵活控制数据分布
|
||||
4. 支持同时使用本地数据集和 HuggingFace Hub 数据集
|
||||
5. 多模态数据通过在 `content` 中添加不同类型的元素来支持
|
||||
6. 更多细节信息请参考我们的 [API REFERENCE](../dev-guide/core/data-engine.md/#data-engine)
|
||||
@@ -1,253 +0,0 @@
|
||||
# DataEngine
|
||||
|
||||
## 1. DataEngine 简介
|
||||
|
||||
|
||||
`DataEngine` 是 LLaMA-Factory v1 数据处理的核心类,继承自 PyTorch 的 `Dataset`,负责各种插件的接入,其他功能(如数据格式转换、数据加载等)均通过插件的形式实现并接入 `DataEngine`。
|
||||
|
||||
`DataEngine`接受一个唯一入参:`DataArguments` 实例,所有的元数据集信息均通过该参数配置传入。
|
||||
|
||||
## 2. DataEngine 与 DataArguments 接口定义
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DataArguments:
|
||||
""" `DataEngine`初始化入参
|
||||
|
||||
args:
|
||||
dataset (str): 数据集路径,远程数据集 repo id / dataset_info.yaml 路径,或本地数据集路径/dataset_info.yaml路径
|
||||
cutoff_len (int): 数据集截止长度,即数据集最大样本采样数量
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
class DataEngine(Dataset):
|
||||
"""数据引擎(DataEngine)
|
||||
|
||||
`DataEngine` 负责数据集的加载与统一管理,支持:
|
||||
- 从本地路径或 Hugging Face Hub 加载数据
|
||||
- 通过插件机制加载自定义数据
|
||||
- 构建统一的数据索引
|
||||
- 支持流式(streaming)与非流式数据访问
|
||||
|
||||
attr:
|
||||
args (DataArguments): 数据参数配置
|
||||
datasets (dict[str, HFDataset]): 数据集名称到数据对象的映射
|
||||
dataset_infos (dict[str, DatasetInfo]): 数据集名称到元信息的映射
|
||||
data_index (list[tuple[str, int]]): 数据索引列表,每项为 (dataset_name, sample_index)
|
||||
streaming (bool): 是否为流式数据集
|
||||
"""
|
||||
|
||||
def __init__(self, data_args: DataArguments) -> None:
|
||||
"""初始化 `DataEngine`
|
||||
|
||||
初始化时自动执行以下步骤:
|
||||
1. 调用 `get_dataset_info`, 从 `data_args` 读取并解析数据集元信息
|
||||
2. 调用 `load_dataset`,根据配置加载数据集
|
||||
3. 调用 `build_data_index`,构建统一的索引列表
|
||||
|
||||
args:
|
||||
data_args (DataArguments): 数据参数配置对象
|
||||
"""
|
||||
...
|
||||
|
||||
def get_dataset_info(self) -> None:
|
||||
"""从配置文件或远程仓库加载数据集元信息
|
||||
|
||||
根据 `self.args.dataset` 确定数据源,数据源支持如下选项:
|
||||
- 本地 YAML 配置文件路径
|
||||
- Hugging Face Hub 上的 YAML 配置文件路径
|
||||
- 本地数据集文件路径
|
||||
- Hugging Face Hub 数据集 repo id
|
||||
|
||||
"""
|
||||
...
|
||||
|
||||
def load_dataset(self) -> None:
|
||||
"""根据数据集元信息加载所有数据集
|
||||
|
||||
每个数据集条目可以包含以下字段:
|
||||
- `hf_hub_url`: 使用 `datasets.load_dataset` 加载
|
||||
- 本地数据文件:通过 `DataLoaderPlugin` 插件加载
|
||||
- `streaming`: 是否启用流式模式
|
||||
|
||||
更新:
|
||||
self.datasets (dict): 数据集名称到已加载数据对象的映射
|
||||
self.streaming (bool): 如果任一数据集为流式模式,则设置为 True
|
||||
"""
|
||||
...
|
||||
|
||||
def build_data_index(self) -> None:
|
||||
"""构建统一的数据索引
|
||||
|
||||
为所有数据集创建全局索引列表 `(dataset_name, sample_index)`
|
||||
|
||||
当启用流式模式时,生成固定长度(例如 1000)的占位索引;
|
||||
否则,为每条样本建立索引。
|
||||
|
||||
插件 `DataIndexPlugin` 可根据数据集大小或权重调整索引分布
|
||||
"""
|
||||
...
|
||||
|
||||
def _convert_data_sample(self, raw_sample: dict[str, Any], dataset_name: str) -> Sample:
|
||||
"""将原始样本转换为统一格式
|
||||
|
||||
根据 `dataset_info` 中的 `converter` 字段,调用对应的转换插件,
|
||||
将原始样本标准化为统一的数据结构。
|
||||
|
||||
args:
|
||||
raw_sample (dict[str, Any]): 原始数据样本
|
||||
dataset_name (str): 样本所属的数据集名称
|
||||
|
||||
return:
|
||||
Sample: 转换后的标准化格式样本
|
||||
"""
|
||||
...
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""返回数据集的总样本数
|
||||
|
||||
return:
|
||||
int: 数据集长度
|
||||
如果为流式数据集,返回 `-1`
|
||||
"""
|
||||
...
|
||||
|
||||
def __getitem__(self, index: Union[int, Any]) -> Union[Sample, list[Sample]]:
|
||||
"""根据索引或选择器获取样本
|
||||
|
||||
args:
|
||||
index (Union[int, Any]): 数据索引,int 或 list[int]
|
||||
|
||||
return:
|
||||
Union[Sample, list[Sample]]: 单个样本或样本列表
|
||||
"""
|
||||
...
|
||||
|
||||
def __iter__(self) -> Iterable:
|
||||
"""返回数据集迭代器
|
||||
|
||||
用于非流式数据集的顺序或随机访问
|
||||
流式模式下需要实现异步加载逻辑
|
||||
|
||||
return:
|
||||
Iterable: 数据集迭代器。
|
||||
"""
|
||||
...
|
||||
|
||||
async def __aiter__(self) -> AsyncIterable:
|
||||
"""返回异步数据集迭代器
|
||||
|
||||
用于流式数据集或异步数据加载场景
|
||||
允许在异步环境中以流的方式读取样本
|
||||
|
||||
return:
|
||||
AsyncIterable: 异步迭代器,按顺序产出样本
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
```
|
||||
|
||||
`DataArguments` 参数说明:
|
||||
|
||||
`dataset`: 数据集路径,支持本地或远程,当传入本地数据集文件路径时,需要满足该数据集为标准格式;否则需要传入 `dataset_info.yaml` 来配置数据集的 `converter` 等元信息,以告知 `DataEngine` 应当如何处理该数据。
|
||||
|
||||
`cutoff_len`: 数据集的截止长度,即该数据集的最大样本数量。
|
||||
|
||||
---
|
||||
|
||||
## 3. DataEngine 核心方法
|
||||
|
||||
### 3.1 `get_dataset_info`:加载数据元信息
|
||||
|
||||
根据 `dataset` 参数加载数据集配置,获取数据位置、数据格式、插件配置等所有数据元信息,在实例化 `DataEngine` 时会自动调用此方法。
|
||||
|
||||
### 3.2 加载数据集:`load_dataset`
|
||||
|
||||
遍历所有数据源,根据不同的数据源加载数据,在实例化 `DataEngine` 时会自动调用此方法。
|
||||
|
||||
```python
|
||||
for key, value in self.dataset_infos.items():
|
||||
split = value.get("split", "train")
|
||||
streaming = value.get("streaming", False)
|
||||
|
||||
if "hf_hub_url" in value:
|
||||
# 从 HF Hub 加载
|
||||
dataset = load_dataset(value["hf_hub_url"], split=split, streaming=streaming)
|
||||
else:
|
||||
# 使用 DataLoaderPlugin 加载本地文件
|
||||
dataset = DataLoaderPlugin(args=self.args).auto_load_data(value)
|
||||
|
||||
self.datasets[key] = dataset
|
||||
```
|
||||
|
||||
### 3.3 `build_data_index`:构建数据索引
|
||||
|
||||
为每个数据集创建索引列表 `[(dataset_name, sample_index), ...]`, `DataIndexPlugin`插件在此处被调用,可控制各数据集的采样频率、采样方式等,在实例化`DataEngine`时会自动调用此方法。
|
||||
|
||||
```python
|
||||
for dataset_name, dataset in self.datasets.items():
|
||||
# 创建基础索引
|
||||
data_index = [(dataset_name, idx) for idx in range(len(dataset))]
|
||||
|
||||
# 根据 size 和 weight 调整索引
|
||||
size = self.dataset_infos[dataset_name].get("size")
|
||||
weight = self.dataset_infos[dataset_name].get("weight")
|
||||
if size or weight:
|
||||
data_index = DataIndexPlugin().adjust_data_index(data_index, size, weight)
|
||||
|
||||
self.data_index.extend(data_index)
|
||||
```
|
||||
|
||||
### 3.4 `_convert_data_sample`:数据格式标准化
|
||||
|
||||
将原始数据转换为标准格式,`DataConverterPlugin`插件在此处被调用,具体调用的插件由 `get_dataset_info` 方法获取的 `converter` 信息指定,若 `converter` 为空则假定数据集为标准格式,此方法由`DataEngine`的 `__getitem__` 方法调用。
|
||||
|
||||
```python
|
||||
def _convert_data_sample(self, raw_sample: dict, dataset_name: str) -> Sample:
|
||||
converter = self.dataset_infos[dataset_name].get("converter")
|
||||
if converter is not None:
|
||||
# 使用指定的转换器
|
||||
from ..plugins.data_plugins.converter import get_converter
|
||||
return {"_dataset_name": dataset_name, **get_converter(converter)(raw_sample)}
|
||||
else:
|
||||
# 已经是标准格式
|
||||
return {"_dataset_name": dataset_name, **raw_sample}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 初始化
|
||||
|
||||
`DataEngine` 初始化过程只需传入一个构建好的 `DataArguments` 即可,后续可通过该 `DataEngine` 访问数据集中的数据。
|
||||
|
||||
```python
|
||||
from llamafactory.v1.config.data_args import DataArguments
|
||||
from llamafactory.v1.core.data_engine import DataEngine
|
||||
|
||||
# 1. 创建数据参数
|
||||
data_args = DataArguments(
|
||||
dataset="~/data/v1_sft_demo.jsonl",
|
||||
cutoff_len=2048
|
||||
)
|
||||
|
||||
# 2. 初始化 Data Engine
|
||||
data_engine = DataEngine(data_args=data_args)
|
||||
|
||||
# 3. 访问数据
|
||||
sample = data_engine[0] # 获取第一个样本
|
||||
```
|
||||
|
||||
## 5. 数据访问方式
|
||||
|
||||
实例化后的`DataEngine`支持整数索引、列表索引、以及切片等访问方式,其数据读取用法可等价于 Python 列表。
|
||||
|
||||
```python
|
||||
sample = data_engine[0] # 获取第一个样本
|
||||
|
||||
sample = data_engine[0:10] # 获取前 10 个样本
|
||||
|
||||
sample = data_engine[[0, 5, 10]] # 获取指定索引的样本
|
||||
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
# ModelEngine
|
||||
@@ -1 +0,0 @@
|
||||
# Trainer
|
||||
@@ -1,467 +0,0 @@
|
||||
# Data Plugins
|
||||
|
||||
## 1. Data Plugins 简介
|
||||
|
||||
## DataConverterPlugin
|
||||
|
||||
### 1. DataConverterPlugin 简介
|
||||
|
||||
DataConverter 负责将非标准格式的数据集转换为 v1 的标准 Messages 格式。这使得用户可以继续使用现有的数据集(如 Alpaca 格式),而无需手动转换。针对自定义格式的数据集,用户也可以通过构建对应的自定义 DataConverter 插件,来负责其数据格式标准化。
|
||||
|
||||
当前,LLaMA-Factory 已内置了 `Alpaca Converter` 和 `Pair Converter`,这两类数据集可以直接使用对应的 converter 进行标准化,无需自定义转换器。
|
||||
|
||||
|
||||
### 2. Alpaca Converter 详解
|
||||
|
||||
#### 2.1 Alpaca 格式
|
||||
|
||||
Alpaca 格式是一种常见的指令微调数据格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"system": "You are a helpful assistant.",
|
||||
"instruction": "Describe a process of making crepes.",
|
||||
"input": "",
|
||||
"output": "Making crepes is an easy and delicious process..."
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Alpaca Converter 接口定义
|
||||
|
||||
```python
|
||||
class AlpacaSample(TypedDict, total=False):
|
||||
"""Alpaca 格式数据样本结构
|
||||
|
||||
attr:
|
||||
system (str, 可选): 系统提示信息(system prompt),用于设定对话背景或模型行为。
|
||||
instruction (str, 可选): 用户指令(user instruction),通常为任务描述。
|
||||
input (str, 可选): 额外的输入内容(input text),可与 instruction 拼接。
|
||||
output (str, 可选): 模型生成的目标输出(expected response)。
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def alpaca_converter(raw_sample: AlpacaSample) -> SFTSample:
|
||||
"""将 Alpaca 样本转换为 SFT(Supervised Fine-Tuning)标准样本格式
|
||||
|
||||
`alpaca_converter` 将 Alpaca 数据集中一条样本转换为通用的 `SFTSample` 格式
|
||||
该格式用于监督微调(SFT)或多轮对话建模
|
||||
|
||||
转换逻辑:
|
||||
- 若存在 `system` 字段,则生成一条系统消息,loss_weight = 0.0
|
||||
- 若存在 `instruction` 或 `input` 字段,则合并为一条用户消息,loss_weight = 0.0
|
||||
- 若存在 `output` 字段,则生成一条助手机器人回复消息,loss_weight = 1.0
|
||||
|
||||
args:
|
||||
raw_sample (AlpacaSample): 原始 Alpaca 数据样本
|
||||
|
||||
return:
|
||||
SFTSample: 转换后的标准化样本,格式如下:
|
||||
|
||||
{
|
||||
"messages": [
|
||||
{"role": "system", "content": [{"type": "text", "value": "..."}], "loss_weight": 0.0},
|
||||
{"role": "user", "content": [{"type": "text", "value": "..."}], "loss_weight": 0.0},
|
||||
{"role": "assistant", "content": [{"type": "text", "value": "..."}], "loss_weight": 1.0},
|
||||
]
|
||||
}
|
||||
|
||||
example:
|
||||
>>> raw = {"instruction": "请将以下句子翻译成英文:", "input": "你好", "output": "Hello"}
|
||||
>>> alpaca_converter(raw)
|
||||
{
|
||||
"messages": [
|
||||
{"role": "user", "content": [{"type": "text", "value": "请将以下句子翻译成英文:你好"}], "loss_weight": 0.0},
|
||||
{"role": "assistant", "content": [{"type": "text", "value": "Hello"}], "loss_weight": 1.0}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
```
|
||||
|
||||
#### 2.3 转换过程
|
||||
|
||||
`alpaca_converter` 函数将 Alpaca 格式转换为标准格式,转换逻辑如下:
|
||||
|
||||
```python
|
||||
def alpaca_converter(raw_sample: AlpacaSample) -> SFTSample:
|
||||
messages = []
|
||||
|
||||
# 1. 添加系统提示词(如果存在)
|
||||
if "system" in raw_sample:
|
||||
messages.append({
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "value": raw_sample["system"]}],
|
||||
"loss_weight": 0.0
|
||||
})
|
||||
|
||||
# 2. 添加用户输入(instruction + input)
|
||||
if "instruction" in raw_sample or "input" in raw_sample:
|
||||
user_content = raw_sample.get("instruction", "") + raw_sample.get("input", "")
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": user_content}],
|
||||
"loss_weight": 0.0
|
||||
})
|
||||
|
||||
# 3. 添加模型回复
|
||||
if "output" in raw_sample:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": raw_sample["output"]}],
|
||||
"loss_weight": 1.0
|
||||
})
|
||||
|
||||
return {"messages": messages}
|
||||
```
|
||||
|
||||
#### 2.4 转换示例
|
||||
|
||||
**输入(Alpaca 格式):**
|
||||
|
||||
```json
|
||||
{
|
||||
"instruction": "What is the capital of France?",
|
||||
"input": "",
|
||||
"output": "The capital of France is Paris."
|
||||
}
|
||||
```
|
||||
|
||||
**输出(标准格式):**
|
||||
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": "What is the capital of France?"}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "The capital of France is Paris."}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 自定义转换器
|
||||
|
||||
#### 3.1 创建自定义转换器
|
||||
|
||||
如果用户有自己的数据格式,可以轻松添加自定义转换器将其标准化,实现过程可参考如下示例:
|
||||
|
||||
```python
|
||||
# src/llamafactory/v1/plugins/data_plugins/converter.py
|
||||
|
||||
from typing import TypedDict, NotRequired
|
||||
from ...extras.types import SFTSample
|
||||
|
||||
# 1. 定义输入格式的类型
|
||||
class MyCustomSample(TypedDict, total=False):
|
||||
question: str
|
||||
answer: str
|
||||
context: NotRequired[str]
|
||||
|
||||
# 2. 实现转换逻辑
|
||||
def custom_converter(raw_sample: MyCustomSample) -> SFTSample:
|
||||
messages = []
|
||||
|
||||
# 构建用户消息
|
||||
user_text = raw_sample["question"]
|
||||
if "context" in raw_sample:
|
||||
user_text = f"Context: {raw_sample['context']}\n\nQuestion: {user_text}"
|
||||
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": user_text}],
|
||||
"loss_weight": 0.0
|
||||
})
|
||||
|
||||
# 构建助手消息
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": raw_sample["answer"]}],
|
||||
"loss_weight": 1.0
|
||||
})
|
||||
|
||||
return {"messages": messages}
|
||||
|
||||
# 3. 注册 custom_converter
|
||||
#src/llamafactory/v1/plugins/data_plugins/converter.py: CONVERTERS
|
||||
CONVERTERS = {
|
||||
"alpaca": alpaca_converter,
|
||||
"custom": custom_converter, # 添加自定义转换器
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 使用自定义转换器
|
||||
|
||||
在 YAML 配置中指定转换器名称:
|
||||
|
||||
```yaml
|
||||
my_dataset:
|
||||
file_name: custom_data.json
|
||||
converter: custom
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DataLoaderPlugin
|
||||
|
||||
### 1. DataLoaderPlugin 简介
|
||||
|
||||
`DataLoaderPlugin` 负责从本地文件加载数据集,当前支持如下文件格式:
|
||||
|
||||
- **JSON**: `.json`
|
||||
- **JSONL**: `.jsonl`
|
||||
- **CSV**: `.csv`
|
||||
- **Parquet**: `.parquet`
|
||||
- **Arrow**: `.arrow`
|
||||
- **Text**: `.txt`
|
||||
|
||||
### 2. DataLoaderPlugin 接口定义
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DataLoaderPlugin:
|
||||
"""数据加载插件(DataLoaderPlugin)
|
||||
|
||||
负责根据数据集信息(`DatasetInfo`)自动加载本地或远程数据集。
|
||||
支持多种文件格式(如 CSV、JSON、Parquet、Text、Arrow),并可选择是否以流式方式加载。
|
||||
|
||||
通常由 `DataEngine` 调用,用于统一封装数据加载逻辑。
|
||||
"""
|
||||
|
||||
args: DataArguments
|
||||
"""数据参数对象,包含数据目录、缓存路径、分片等配置信息。"""
|
||||
|
||||
|
||||
def _get_builder_name(self, path: str) -> Literal["arrow", "csv", "json", "parquet", "text"]:
|
||||
"""获取数据集文件格式
|
||||
|
||||
根据输入文件路径自动判断应使用的 HuggingFace `load_dataset` 构建器类型。
|
||||
通过文件扩展名推断数据类型,例如 `.csv`、`.jsonl`、`.parquet`、`.txt` 等。
|
||||
|
||||
args:
|
||||
path (str): 数据集文件路径,用于识别文件类型。
|
||||
|
||||
return:
|
||||
Literal["arrow", "csv", "json", "parquet", "text"]:
|
||||
数据构建器名称,用于 `datasets.load_dataset()`。
|
||||
|
||||
example:
|
||||
>>> _get_builder_name("data/train.jsonl")
|
||||
"json"
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def auto_load_data(self, dataset_info: DatasetInfo) -> HFDataset:
|
||||
"""根据传入的 `dataset_info` 自动选择合适的加载方式
|
||||
|
||||
args:
|
||||
dataset_info (DatasetInfo): 数据集元信息,通常包含:
|
||||
- `file_name`: 数据文件路径
|
||||
- `split`: 数据划分(如 "train"、"test");
|
||||
- `streaming`: 是否启用流式加载
|
||||
|
||||
return:
|
||||
HFDataset: 加载完成的 Hugging Face 数据集对象。
|
||||
|
||||
example:
|
||||
>>> plugin = DataLoaderPlugin(args)
|
||||
>>> ds = plugin.auto_load_data({"file_name": "~/data.json", "split": "train"})
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def load_data_from_file(self, filepath: str, split: str, streaming: bool) -> HFDataset:
|
||||
"""从文件或目录加载数据集
|
||||
|
||||
根据输入路径自动识别文件类型(CSV、JSON、Parquet、Text 等),
|
||||
并通过 `datasets.load_dataset()` 加载数据集。
|
||||
若 `streaming=True`,则将结果转换为迭代式数据集。
|
||||
|
||||
args:
|
||||
filepath (str): 文件路径或目录路径。
|
||||
split (str): 数据划分名称(如 "train"、"validation")。
|
||||
streaming (bool): 是否启用流式加载模式。
|
||||
|
||||
return:
|
||||
HFDataset: 加载后的数据集对象。
|
||||
|
||||
example:
|
||||
>>> plugin.load_data_from_file("data/train.json", "train", False)
|
||||
"""
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DataIndexPlugin
|
||||
|
||||
### 1. DataIndexPlugin 简介
|
||||
|
||||
`DataIndexPlugin` 负责调整数据索引,支持通过配置 `size`, `weight` 等参数控制数据集样本数量和采样频率。
|
||||
|
||||
- 使用 `size` 参数 限制使用的样本数量:
|
||||
|
||||
```yaml
|
||||
my_dataset:
|
||||
file_name: large_dataset.json
|
||||
size: 1000 # 只使用前 1000 个样本
|
||||
```
|
||||
|
||||
- 使用 `weight` 参数调整数据集在混合数据中的采样频率:
|
||||
|
||||
```yaml
|
||||
dataset_a:
|
||||
file_name: data_a.json
|
||||
weight: 1.0
|
||||
|
||||
dataset_b:
|
||||
file_name: data_b.json
|
||||
weight: 2.0 # dataset_b 的样本出现频率是 dataset_a 的 2 倍
|
||||
```
|
||||
|
||||
**说明**:`weight` 参数适用于在多个数据集混合训练时,调整不同数据集的的采样频率
|
||||
|
||||
- 当 `weight=1.0` 时,数据集按原始比例采样
|
||||
- 当 `weight=2.0` 时,该数据集的索引会复制 2 倍,使其样本出现频率翻倍
|
||||
|
||||
### 2. DataIndexPlugin 接口定义
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DataIndexPlugin:
|
||||
"""数据索引插件(DataIndexPlugin)
|
||||
|
||||
根据 `size` 和 `weight` 调整数据索引列表,控制数据集的样本数量和采样频率
|
||||
通常在多数据集混合训练时使用,以控制不同数据集在总体样本中的占比。
|
||||
|
||||
在 `DataEngine.build_data_index` 中被自动调用,用于实现样本重采样或加权分布。
|
||||
"""
|
||||
|
||||
def adjust_data_index(
|
||||
self, data_index: list[tuple[str, int]], size: Optional[int], weight: Optional[float]
|
||||
) -> list[tuple[str, int]]:
|
||||
"""调整数据索引列表
|
||||
|
||||
根据 `size` 或 `weight` 参数对输入的数据索引进行采样、扩展或缩减。
|
||||
若两个参数同时存在,将依次执行基于大小和基于权重的调整。
|
||||
|
||||
args:
|
||||
data_index (list[tuple[str, int]]):
|
||||
数据索引列表,每个元素为 `(dataset_name, sample_index)`。
|
||||
size (Optional[int]):
|
||||
目标样本数量,若指定则根据该数量裁剪或重复样本。
|
||||
weight (Optional[float]):
|
||||
数据集权重,用于控制数据集在混合训练中的采样比例。
|
||||
|
||||
return:
|
||||
list[tuple[str, int]]:
|
||||
调整后的数据索引列表。
|
||||
|
||||
example:
|
||||
>>> plugin = DataIndexPlugin()
|
||||
>>> adjusted = plugin.adjust_data_index([("ds1", i) for i in range(100)], size=50, weight=None)
|
||||
>>> len(adjusted)
|
||||
50
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def adjust_by_size(self, data_index: list[tuple[str, int]], size: int) -> list[tuple[str, int]]:
|
||||
"""根据目标大小调整数据索引
|
||||
|
||||
通过裁剪或重复样本,使索引总数等于 `size`。
|
||||
常用于统一不同数据集的样本数量。
|
||||
|
||||
args:
|
||||
data_index (list[tuple[str, int]]):
|
||||
原始数据索引列表。
|
||||
size (int):
|
||||
目标样本数量。
|
||||
|
||||
return:
|
||||
list[tuple[str, int]]:
|
||||
调整后长度等于 `size` 的数据索引列表。
|
||||
|
||||
example:
|
||||
>>> plugin.adjust_by_size([("ds1", i) for i in range(10)], 20)
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def adjust_by_weight(self, data_index: list[tuple[str, int]], weight: float) -> list[tuple[str, int]]:
|
||||
"""根据权重调整数据索引
|
||||
|
||||
通过加权采样或重复样本,使数据集样本出现频率符合指定权重。
|
||||
常用于多数据源训练中按比例平衡样本。
|
||||
|
||||
args:
|
||||
data_index (list[tuple[str, int]]):
|
||||
原始数据索引列表。
|
||||
weight (float):
|
||||
数据集权重(相对比例,可与其他数据集共同归一化)。
|
||||
|
||||
return:
|
||||
list[tuple[str, int]]:
|
||||
调整后的加权数据索引列表。
|
||||
|
||||
example:
|
||||
>>> plugin.adjust_by_weight([("ds1", i) for i in range(10)], 0.5)
|
||||
"""
|
||||
...
|
||||
|
||||
```
|
||||
---
|
||||
|
||||
## DataSelectorPlugin
|
||||
|
||||
### 1. DataSelectorPlugin 简介
|
||||
|
||||
`DataSelectorPlugin` 为 `DataEngine`提供基于索引访问数据的功能,由 `DataEngine` 的 `__getitem__` 方法自动调用。
|
||||
|
||||
|
||||
### 2. DataSelectorPlugin 接口定义
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DataSelectorPlugin:
|
||||
"""根据索引选择数据集样本。
|
||||
|
||||
配合 `DataEngine` 使用,通过统一的 `data_index` 结构(包含数据集名与样本索引)来实现灵活的数据选择
|
||||
|
||||
"""
|
||||
|
||||
data_index: list[tuple[str, int]]
|
||||
"""数据索引列表,每个元素为 (dataset_name, sample_index)。"""
|
||||
|
||||
|
||||
def select(self, index: Union[slice, list[int], Any]) -> Union[tuple[str, int], list[tuple[str, int]]]:
|
||||
"""选择数据集样本
|
||||
|
||||
根据输入类型从 `data_index` 中选择对应的样本索引
|
||||
支持三种索引方式:
|
||||
- 切片(slice):返回对应范围内的样本
|
||||
- 索引列表(list[int]):返回指定索引处的多个样本
|
||||
- 其他类型输入将触发异常。
|
||||
|
||||
args:
|
||||
index (Union[slice, list[int], Any]): 数据样本索引
|
||||
可以是切片(`slice`)或索引列表
|
||||
|
||||
return:
|
||||
Union[tuple[str, int], list[tuple[str, int]]]:
|
||||
- 若为单个索引:返回一个 `(dataset_name, sample_index)`
|
||||
- 若为多个索引或切片:返回多个样本的列表
|
||||
|
||||
except:
|
||||
Raises:
|
||||
ValueError: 当输入索引类型不受支持时抛出。
|
||||
...
|
||||
```
|
||||
@@ -1,197 +0,0 @@
|
||||
# Kernels plugins
|
||||
|
||||
## 概览
|
||||
LLaMA-Factory 通过 Kernels plugins 系统,依据不同硬件设备提供高性能计算内核(kernel)实现。该系统通过注册表机制管理所有 kernel,通过 `@register_kernel` 装饰器实现 kernel 定义后自动注册,由 `apply_kernel` 方法来使能指定的 kernel,`apply_default_kernels` 可使能注册表中当前环境所有可用的默认 kernels。
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 核心组件
|
||||
|
||||
#### 1. Registry(注册表)
|
||||
|
||||
`Registry` 是一个用于管理所有 kernel 实现的静态类。它维护一个字典结构:`{kernel_id: KernelClass}`。
|
||||
|
||||
```python
|
||||
# 注册表结构示例
|
||||
{
|
||||
"npu_fused_rmsnorm": NpuRMSNormKernel,
|
||||
"npu_fused_swiglu": NpuSwiGluKernel,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. register_kernel (装饰器)
|
||||
|
||||
`@register_kernel` 是 `Registry.register` 的别名。所有 kernel 类均应使用该装饰器进行注册。
|
||||
|
||||
**注册机制**:
|
||||
- 装饰器检查类是否继承自 `BaseKernel`。
|
||||
- 检查类是否定义了 `_kernel_id` 和 `_device` 属性。
|
||||
- 检查 `_device` 是否与当前运行环境的加速器类型匹配。如果不匹配,则跳过注册。
|
||||
- 如果一切符合要求,将 kernel 类注册到全局注册表中。
|
||||
|
||||
#### 3. BaseKernel(基类)
|
||||
|
||||
所有 kernel 的实现都必须继承自 `BaseKernel` 抽象基类。`BaseKernel` 定义了 kernel 的基本属性和接口。
|
||||
|
||||
#### 4. 标识系统
|
||||
|
||||
**Kernel ID** (`_kernel_id`):
|
||||
每个 kernel 必须拥有一个唯一的字符串标识符,例如 `"npu_fused_rmsnorm"`。
|
||||
|
||||
**Device Type** (`_device`):
|
||||
kernel 必须声明其支持的设备类型,例如 `DeviceType.NPU` 或 `DeviceType.CUDA`。
|
||||
|
||||
## Kernel 系统 API 设计
|
||||
|
||||
### **Registry**:全局 kernel 注册表
|
||||
|
||||
`Registry` 类提供了注册和获取 kernel 的接口:
|
||||
|
||||
```python
|
||||
class Registry:
|
||||
@classmethod
|
||||
def register(cls, kernel_cls: type[BaseKernel]) -> type[BaseKernel] | None:
|
||||
"""注册一个 kernel 类"""
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def get(cls, kernel_id: str) -> type[BaseKernel] | None:
|
||||
"""根据 ID 获取 kernel 类"""
|
||||
...
|
||||
```
|
||||
|
||||
### **BaseKernel**
|
||||
|
||||
`BaseKernel` 定义了所有 kernel 必须实现的协议:
|
||||
|
||||
- `_kernel_id`: 类属性,kernel 的唯一标识符。
|
||||
- `_device`: 类属性,kernel 支持的设备类型。
|
||||
- `check_deps()`: 类方法,检查 kernel 的依赖项是否满足(如 `torch_npu` 是否安装)。
|
||||
- `apply(**kwargs)`: 抽象类方法,实现 kernel 的具体应用逻辑。
|
||||
|
||||
```python
|
||||
class BaseKernel(ABC):
|
||||
_kernel_id: Any = ""
|
||||
_device: DeviceType = DeviceType.CPU
|
||||
|
||||
@classmethod
|
||||
def check_deps(cls) -> bool:
|
||||
"""检查依赖项"""
|
||||
...
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def apply(cls, **kwargs) -> HFModel:
|
||||
"""应用 kernel 到模型"""
|
||||
...
|
||||
```
|
||||
|
||||
### **scan_all_kernels**
|
||||
|
||||
`scan_all_kernels` 函数会自动扫描 `ops` 目录下的所有 `.py` 文件并导入它们,从而触发 `@register_kernel` 装饰器完成自动注册。
|
||||
|
||||
### **apply_kernel**
|
||||
|
||||
对模型使能指定的 kernel。
|
||||
|
||||
```python
|
||||
def apply_kernel(kernel_id: str, **kwargs) -> HFModel:
|
||||
"""应用指定的 kernel 到模型
|
||||
|
||||
Args:
|
||||
kernel_id: 目标 kernel 的 ID
|
||||
**kwargs: 传递给 kernel.apply 的参数,通常包含 model
|
||||
"""
|
||||
```
|
||||
|
||||
**用法示例**:
|
||||
```python
|
||||
from llamafactory.v1.plugins.model_plugins.kernels import apply_kernel
|
||||
|
||||
model = apply_kernel("npu_fused_rmsnorm", model=model)
|
||||
```
|
||||
|
||||
### **apply_default_kernels**
|
||||
|
||||
对模型使能所有默认注册的 kernel。这是一个高级 API,通常在模型加载流程中自动调用。
|
||||
|
||||
```python
|
||||
def apply_default_kernels(model: HFModel, include_kernels: str = None) -> HFModel:
|
||||
"""应用所有默认 kernel
|
||||
|
||||
Args:
|
||||
model: HFModel 实例
|
||||
include_kernels: 包含的 kernel ID 列表(逗号分隔字符串),或者 "auto"/True 表示全部
|
||||
"""
|
||||
```
|
||||
|
||||
## 扩展 Kernels
|
||||
|
||||
如果用户有针对特定模型或者设备的 kernel,可以按照下述步骤去实现并接入 LLaMA-Factory。
|
||||
|
||||
### 创建新 Kernel 的步骤
|
||||
|
||||
#### 1. 创建 Kernel 实现文件
|
||||
|
||||
在 `src/llamafactory/v1/plugins/model_plugins/kernels/ops` 下的相应子目录中创建新的 kernel 实现文件,例如 `mlp/cuda_swiglu.py`:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from ......accelerator.helper import DeviceType
|
||||
from ......utils.types import HFModel
|
||||
from ...base import BaseKernel
|
||||
from ...registry import register_kernel
|
||||
|
||||
# 实现具体的 kernel 函数
|
||||
def _cuda_swiglu_forward(self, hidden_state):
|
||||
# ... CUDA 优化实现 ...
|
||||
pass
|
||||
|
||||
@register_kernel
|
||||
class CudaSwiGluKernel(BaseKernel):
|
||||
_kernel_id = "cuda_fused_swiglu"
|
||||
_device = DeviceType.CUDA
|
||||
|
||||
@classmethod
|
||||
def apply(cls, **kwargs) -> HFModel:
|
||||
model = kwargs.get("model")
|
||||
if model is None:
|
||||
raise ValueError("model is required")
|
||||
|
||||
if not cls.check_deps():
|
||||
raise RuntimeError("Dependencies not met")
|
||||
|
||||
# 遍历模型并替换 forward 方法
|
||||
for name, module in model.named_modules():
|
||||
# ... 匹配和替换逻辑 ...
|
||||
pass
|
||||
|
||||
return model
|
||||
```
|
||||
|
||||
#### 2. 自动发现
|
||||
|
||||
由于 `scan_all_kernels` 会自动扫描 `ops` 目录,只要文件位于该目录下且没有语法错误,系统启动时会自动导入并注册,无需手动修改注册表代码。
|
||||
|
||||
#### 3. 测试 Kernel
|
||||
|
||||
创建测试用例验证 kernel 的正确性:
|
||||
|
||||
```python
|
||||
from llamafactory.v1.plugins.model_plugins.kernels import apply_kernel
|
||||
|
||||
# ... 加载模型 ...
|
||||
model = apply_kernel("cuda_fused_swiglu", model=model)
|
||||
# ... 验证 forward 是否被替换 ...
|
||||
```
|
||||
|
||||
## 异常处理
|
||||
|
||||
### 依赖不可用
|
||||
|
||||
`BaseKernel.check_deps()` 默认会检查当前设备类型是否匹配。子类可以重写此方法以添加额外的依赖检查(如检查特定的库是否安装)。如果 `check_deps()` 返回 `False`,`apply()` 方法应当抛出异常或进行相应处理。
|
||||
|
||||
### Kernel ID 未找到
|
||||
|
||||
如果调用 `apply_kernel` 时传入了不存在的 `kernel_id`,会抛出 `ValueError`。
|
||||
64
docs/zh/developer-guide/architecture_overview.md
Normal file
64
docs/zh/developer-guide/architecture_overview.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# 整体架构
|
||||
|
||||
v1 将命令入口、运行流程和可替换实现分开组织。Core 负责连接配置、数据、模型和训练状态,Plugin 为 Core 提供数据加载、模型处理、批处理和分布式训练等具体实现。
|
||||
|
||||
这样划分后,更换数据格式不需要改训练循环,更换分布式后端也不需要重新实现 SFT 损失。任务入口负责把组件组装成一次运行,Core 决定何时执行操作,Plugin 提供被选择的具体操作。
|
||||
|
||||
下文源码路径均相对于 `src/llamafactory/v1/`。
|
||||
|
||||
## 模块分层
|
||||
|
||||
| 模块 | 目录 | 职责 |
|
||||
|------|------|------|
|
||||
| 命令入口 | `launcher.py` | 路由 `sft`、`dpo`、`rm`、`chat` 和 `merge`,并在多设备训练时通过 `torchrun` 重启 |
|
||||
| 参数配置 | `config/` | 解析数据、模型、训练和推理参数 |
|
||||
| 任务入口 | `trainers/`、`samplers/` | 组装 SFT、DPO、RM 或推理流程 |
|
||||
| Core | `core/` | 管理数据索引、模型加载、样本渲染、批处理、训练循环和推理引擎 |
|
||||
| Plugin | `plugins/` | 提供数据、模型和训练器相关的可替换实现 |
|
||||
| 设备抽象 | `accelerator/` | 管理设备、进程组和 DeviceMesh |
|
||||
|
||||
## 调用关系
|
||||
|
||||
```text
|
||||
llamafactory-cli <command> config.yaml
|
||||
→ launcher
|
||||
→ get_args
|
||||
→ 任务入口(run_sft / run_dpo / run_rm / run_chat 等)
|
||||
├── DataEngine
|
||||
│ ├── DataLoaderPlugin
|
||||
│ └── DataConverterPlugin
|
||||
├── ModelEngine
|
||||
│ ├── InitPlugin
|
||||
│ ├── QuantizationPlugin
|
||||
│ ├── PeftPlugin
|
||||
│ └── KernelPlugin
|
||||
├── BaseTrainer
|
||||
│ ├── BatchGenerator → BatchingPlugin
|
||||
│ ├── DistributedPlugin
|
||||
│ └── OptimizerPlugin
|
||||
└── BaseSampler
|
||||
```
|
||||
|
||||
上图表示组件依赖,实际初始化次序由对应任务入口决定。以 `trainers/sft_trainer.py` 中的 `run_sft` 为例:先解析参数并初始化 `DistributedInterface`,再构造 DataEngine 和 ModelEngine,将数据集、模型与 Renderer 传给 SFTTrainer,最后调用 `fit()`、`save_model()` 并销毁分布式环境。SFTTrainer 继承 BaseTrainer 的运行循环,并提供 SFT 的损失计算。
|
||||
|
||||
## 数据如何到达训练循环
|
||||
|
||||
```text
|
||||
DataEngine[index] → 标准 Sample(仍是消息结构)
|
||||
Renderer.process_samples(samples) → ModelInput 列表(已分词,尚未组 batch)
|
||||
BatchGenerator → 一个更新步所需的 micro-batch 列表
|
||||
Trainer.compute_loss(batch) → 标量 loss
|
||||
BaseTrainer.fit() → 反向传播、参数更新与生命周期事件
|
||||
```
|
||||
|
||||
ModelEngine 同时提供模型和与模型匹配的 Renderer,BatchGenerator 持有这个 Renderer。这样,数据源的读取与字段转换可以独立于模型的 tokenizer、chat template 和多模态 processor。
|
||||
|
||||
## 状态与实现分别由谁管理
|
||||
|
||||
DataEngine 保存数据集和索引,ModelEngine 保存加载结果,BatchGenerator 保存读取进度与缓冲区,BaseTrainer 保存模型、优化器和训练进度。它们都是一次运行中的对象。
|
||||
|
||||
插件注册表保存函数或类对象。调用方每次把模型、配置或缓冲区传给插件,并接收处理结果;插件路由对象本身只记录实现名称。例如,分布式插件可以返回有状态的后端 engine,由 BaseTrainer 持有,但注册表本身不保存某次训练的 engine。
|
||||
|
||||
判断改动位置时,先区分是在改变任务目标、组件流程,还是替换某个操作:新损失属于 Trainer,统一的数据索引逻辑属于 DataEngine,新的原始字段转换属于 DataConverterPlugin。具体扩展边界分别在下方页面说明。
|
||||
|
||||
Core 各组件见[Core(核心模块)](core/index.md),插件的注册方式见[插件注册机制](baseplugin_mechanism.md),内置实现见[插件实现](plugins/index.md)。
|
||||
132
docs/zh/developer-guide/baseplugin_mechanism.md
Normal file
132
docs/zh/developer-guide/baseplugin_mechanism.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# 插件注册机制
|
||||
|
||||
`BasePlugin` 位于 `utils/plugin.py`,负责按名称注册和查找实现。每个 `BasePlugin` 子类表示一个独立的插件类型,并拥有自己的 `_registry`,例如 `OptimizerPlugin` 和 `DistributedPlugin` 的注册项互不共享。
|
||||
|
||||
## 插件类型、路由对象与实现
|
||||
|
||||
以 `DistributedPlugin("fsdp2").shard_model(...)` 为例,这里有三个不同对象:
|
||||
|
||||
| 对象 | 职责 |
|
||||
|------|------|
|
||||
| `DistributedPlugin` | 插件类型,持有这个类型的名称注册表 |
|
||||
| `DistributedPlugin("fsdp2")` | 路由对象,仅保存要查找的名称 |
|
||||
| 注册在 `fsdp2` 下的实现类 | 提供 `shard_model` 等实际操作 |
|
||||
|
||||
创建路由对象只保存名称,不会立即加载或创建后端 engine。第一次调用函数或访问实现方法时,`_resolve` 才从该类型的注册表中查找对象。模型、优化器、buffer 等运行状态由调用方持有并作为参数传入。
|
||||
|
||||
## 注册与调用流程
|
||||
|
||||
```text
|
||||
定义插件类型
|
||||
→ PluginType(BasePlugin)
|
||||
→ PluginType("name").register()
|
||||
→ 将函数或类对象写入 PluginType._registry
|
||||
→ PluginType("name") 按名称查找实现
|
||||
→ 通过 __call__ 或 __getattr__ 调用
|
||||
```
|
||||
|
||||
装饰器在模块导入时完成注册。注册名称必须存在;查找未注册的名称时会抛出 `ValueError`。同一插件类型重复注册相同名称时会记录警告,并使用后注册的实现。
|
||||
|
||||
注册表不会自动扫描文件或按 YAML 名称导入 Python 模块。内置实现通过其入口模块的正常导入完成注册,例如 Kernel 入口显式导入各实现。新增实现也必须在被调用前执行所在模块的导入,仅添加文件或写入配置名称不会触发注册。
|
||||
|
||||
## 函数实现
|
||||
|
||||
一个插件名称只对应一个操作时,直接注册函数。调用 `PluginType("name")(...)` 时,`BasePlugin.__call__` 查找并调用该函数。
|
||||
|
||||
```python
|
||||
class OptimizerPlugin(BasePlugin):
|
||||
pass
|
||||
|
||||
|
||||
@OptimizerPlugin("example").register()
|
||||
def create_optimizer(model, config):
|
||||
return ExampleOptimizer(model.parameters(), lr=config["learning_rate"])
|
||||
|
||||
|
||||
optimizer = OptimizerPlugin("example")(model, config)
|
||||
```
|
||||
|
||||
数据加载、数据转换、模型初始化、PEFT 和优化器等插件使用这种形式。插件类型也可以提供语义化方法,在方法内部调用 `super().__call__`,例如 `DataLoaderPlugin.load(...)`。
|
||||
|
||||
## 类实现(静态方法组)
|
||||
|
||||
同一插件名称需要提供多个相关操作时,注册一个类对象。`BasePlugin.__getattr__` 先查找该类,再把方法访问转发给它。
|
||||
|
||||
```python
|
||||
@DistributedPlugin("example").register()
|
||||
class ExampleDistributed(BaseDistributed):
|
||||
@staticmethod
|
||||
def shard_model(model, dist_config, **kwargs):
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def save_checkpoint(model, optimizer, checkpoint_dir, **kwargs):
|
||||
...
|
||||
|
||||
|
||||
model = DistributedPlugin("example").shard_model(model, dist_config)
|
||||
DistributedPlugin("example").save_checkpoint(model, optimizer, checkpoint_dir)
|
||||
```
|
||||
|
||||
通过 `.method(...)` 访问时,路由会取出注册类上的方法,不创建该类的实例。因此,这类实现使用 `staticmethod` 或 `classmethod`,不在 `self` 中保存运行状态:
|
||||
|
||||
| 方法形式 | 调用时接收 | 用途 |
|
||||
|----------|------------|------|
|
||||
| `staticmethod` | 只接收显式参数 | 实现不依赖类本身的独立操作,例如保存 checkpoint |
|
||||
| `classmethod` | 首个参数为 `cls` | 需要调用子类方法的公共流程,例如 `BaseKernel.apply` |
|
||||
| 普通实例方法 | 首个参数为 `self` | 需要先创建实例,不适用于当前类对象路由 |
|
||||
|
||||
Python 没有单独的“静态类”类型;这里使用的是包含静态方法或类方法的普通类。分布式后端、批处理策略和 Kernel 使用这种方法组形式。对应抽象基类声明的也是静态方法或类方法,`ensure_methods_implemented` 在具体子类定义时检查这些方法是否完整。
|
||||
|
||||
## 两种实现形式的选择
|
||||
|
||||
| 实现形式 | 注册对象 | 调用入口 | 适用情况 |
|
||||
|----------|----------|----------|----------|
|
||||
| 函数 | 函数对象 | `PluginType("name")(...)` | 一个名称对应一个操作 |
|
||||
| 类方法组 | 类对象 | `PluginType("name").method(...)` | 一个名称需要提供多个相关操作 |
|
||||
|
||||
两种形式使用相同的名称注册表。区别只在于注册对象和调用方式,不影响配置文件通过 `name` 选择实现。
|
||||
|
||||
## 参数解析
|
||||
|
||||
注册过程只完成名称到实现的映射,不会自动解析参数。参数配置经过两个不同阶段:
|
||||
|
||||
1. `config/arg_utils.py` 的 `get_plugin_config` 将顶层参数中的插件配置包装成 PluginConfig,并检查是否有 `name`。这时并未根据名称验证插件专属字段。
|
||||
2. 调用进入具体实现后,由实现解析自己的字段。PEFT 和分布式入口使用参数 dataclass 与 `parse_params`;Muon 等实现直接读取配置。插件类型本身没有为所有实现统一选择参数类。
|
||||
|
||||
使用参数 dataclass 的入口可以显式调用 `parse_params(config, ParamsClass)`:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
|
||||
class ExamplePlugin(BasePlugin):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExampleParams:
|
||||
name: Literal["example"] = "example"
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
@ExamplePlugin("example").register()
|
||||
def apply_example(model, config):
|
||||
params = ExamplePlugin.parse_params(config, ExampleParams)
|
||||
if params.enabled:
|
||||
...
|
||||
```
|
||||
|
||||
`parse_params` 的处理规则如下:
|
||||
|
||||
- `config` 为目标 dataclass 实例时直接返回;
|
||||
- `config` 为字典时检查字段名,再创建参数实例;
|
||||
- `config` 为 `None` 时使用 dataclass 默认值创建实例;
|
||||
- 未声明的字段会抛出 `ValueError`;
|
||||
- 参数类不是 dataclass,或配置不是字典、`None`、目标 dataclass 实例时,会抛出 `TypeError`;
|
||||
- 取值范围和字段组合可以在参数 dataclass 的 `__post_init__` 中继续校验。
|
||||
|
||||
这里的严格检查主要针对未知字段和配置对象的形式;Python dataclass 不会自动强制执行每个类型注解或 `Literal` 的可选值,额外约束需要实现显式校验。
|
||||
|
||||
参数 dataclass 由具体插件入口选择,因此不同实现可以使用不同字段。用户可配置字段记录在对应的[参数说明](../configuration/index.md)中。
|
||||
47
docs/zh/developer-guide/core/base_sampler.md
Normal file
47
docs/zh/developer-guide/core/base_sampler.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# BaseSampler
|
||||
|
||||
`BaseSampler` 位于 `core/base_sampler.py`,为推理调用方提供生成接口,并持有具体的推理 engine。模型和 Renderer 由 [ModelEngine](model_engine.md) 创建后传入;Sampler 负责选择后端和转发调用。
|
||||
|
||||
## 组件与状态
|
||||
|
||||
| 组件 | 职责 | 源码 |
|
||||
|------|------|------|
|
||||
| BaseSampler | 根据 `sample_backend` 选择 engine,转发生成请求 | `core/base_sampler.py` |
|
||||
| BaseEngine / HuggingFaceEngine | 定义后端接口,使用模型和 Renderer 执行生成 | `core/utils/inference_engine.py` |
|
||||
| SyncSampler | 将异步生成接口适配为 CLI 使用的同步迭代器 | `samplers/cli_sampler.py` |
|
||||
| `run_chat` | 创建组件,读取用户输入,保存对话历史并输出回复 | `samplers/cli_sampler.py` |
|
||||
|
||||
当前 BaseSampler 直接构造 HuggingFaceEngine,后端选择不经过 BasePlugin 注册表。HuggingFaceEngine 保存模型、Renderer 和推理参数;对话历史由 `run_chat` 中的消息列表持有,每次请求传入完整历史。
|
||||
|
||||
## 单次生成路径
|
||||
|
||||
```text
|
||||
run_chat:追加 user 消息
|
||||
→ SyncSampler.generate(messages)
|
||||
→ BaseSampler.generate(messages, tools)
|
||||
→ HuggingFaceEngine.generate(messages, tools)
|
||||
→ Renderer.render_messages(..., is_generate=True)
|
||||
→ input_ids / attention_mask 转为设备上的张量
|
||||
→ 后台线程调用 model.generate
|
||||
→ AsyncTextIteratorStreamer 异步返回文本片段
|
||||
→ CLI 逐段输出,拼成 assistant 消息并加入历史
|
||||
```
|
||||
|
||||
HuggingFaceEngine 用信号量限制同时进入生成过程的请求数。它将 `max_new_tokens` 和 streamer 传给 `model.generate`,streamer 跳过 prompt 和特殊 token;返回值是解码后的文本片段,不是 token ID,也不保证每个片段恰好对应一个 token。
|
||||
|
||||
SyncSampler 另行维护后台事件循环,逐次等待异步生成器的下一段文本,再交给同步调用方。这个适配层改变调用方式,不改变消息渲染或模型生成逻辑。
|
||||
|
||||
## 接口与当前支持范围
|
||||
|
||||
| 接口 | 输入与输出 | 当前行为 |
|
||||
|------|------------|----------|
|
||||
| `generate(messages, tools=None)` | 标准 Message 列表、可选 tools 字符串;异步产出 `str` | Hugging Face 流式生成 |
|
||||
| `batch_infer(dataset)` | Dataset;约定返回 Sample 列表 | HuggingFaceEngine 抛出 `NotImplementedError` |
|
||||
|
||||
BaseSampler 的非 HF 后端分支会抛出 `ValueError`。CLI 中设置 `train_dataset` 会进入批量推理分支,但当前 engine 尚未实现该接口。因此,已实现的用户路径是 HF 交互式对话,启动方式见[推理](../../feature-guide/inference.md),配置字段见[推理参数](../../configuration/inference.md)。
|
||||
|
||||
## 扩展边界
|
||||
|
||||
新增推理后端时,实现 `BaseEngine` 的接口,并接入 BaseSampler 的后端选择;仅添加文件或写入新的 `sample_backend` 名称不会完成接入。后端需要保持异步文本流接口,并明确批量推理是否可用,SyncSampler 才能沿用现有适配方式。
|
||||
|
||||
改变模板和消息到模型输入的转换时,修改 [Renderer](renderer.md);改变生成参数的传递、模型调用或输出流时,修改 engine;改变命令行输入和对话历史管理时,修改 `run_chat`。当前 HF 生成调用只传递 Renderer 结果中的 `input_ids` 和 `attention_mask`,扩展其他模型输入时还需要补齐 engine 向模型传参的路径。
|
||||
50
docs/zh/developer-guide/core/base_trainer.md
Normal file
50
docs/zh/developer-guide/core/base_trainer.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# BaseTrainer
|
||||
|
||||
`BaseTrainer` 提供 SFT、DPO 和 RM 共用的训练生命周期。子类主要实现 `compute_loss`,必要时覆盖模型分片或输入处理。
|
||||
|
||||
实现位于 `core/base_trainer.py`。任务入口负责加载模型与数据,再把它们传入 Trainer;BaseTrainer 从这些对象开始组织批次生成、优化器更新和训练状态。这样,各训练目标可以共用同一套运行循环。
|
||||
|
||||
## 初始化训练组件
|
||||
|
||||
先保存参数、模型、Renderer 与数据集,创建 BatchGenerator,再确定训练总步数和 checkpoint 间隔。后续组件的创建顺序取决于后端:
|
||||
|
||||
- FSDP2 / FSDPTurbo 先分片模型,再基于处理后的参数创建 optimizer 和 scheduler;没有显式分布式后端时,使用普通模型或 DDP。
|
||||
- DeepSpeed 先构造后端 engine,再创建 optimizer 和 scheduler,最后由 engine 的 `prepare` 统一准备训练对象。
|
||||
|
||||
模型和优化器就绪后,`TrainingCheckpointCoordinator` 才能恢复它们的状态以及批次进度。之后创建 CallbackHandler 和 TrainerState,并把已恢复的 step、epoch 同步给回调状态。CP 模型处理在初始化的最后阶段接入。
|
||||
|
||||
## 训练循环
|
||||
|
||||
```text
|
||||
epoch / global step
|
||||
→ BatchGenerator
|
||||
→ forward + compute_loss
|
||||
→ gradient accumulation
|
||||
→ gradient clipping
|
||||
→ optimizer.step
|
||||
→ scheduler.step
|
||||
→ callback / logging
|
||||
→ 可选 checkpoint
|
||||
```
|
||||
|
||||
`global_batch_size / (dp_size × micro_batch_size)` 决定梯度累积所需的 micro-batch 数。
|
||||
|
||||
BatchGenerator 每次迭代返回一组 micro-batch,对应一次更新步。普通路径对每个 micro-batch 调用 `compute_loss` 并反向传播,累积完成后执行梯度裁剪、参数更新和清零。`compute_loss` 返回标量损失,BaseTrainer 还会根据有效监督 token 数和 DP 规模缩放损失,因此子类不应自行重复执行参数更新。
|
||||
|
||||
DeepSpeed 路径把反向传播和同步边界交给后端 engine;SFT 开启 CP 时,循环改为调用 SequenceParallelLossPlugin。扩展损失时需要同时考虑目标任务是否支持这两条路径。
|
||||
|
||||
## 训练器实现
|
||||
|
||||
- `SFTTrainer`:带 `loss_weights` 的语言模型损失
|
||||
- `DPOTrainer`:policy/reference 偏好损失
|
||||
- `RMTrainer`:chosen/rejected reward 排序损失
|
||||
|
||||
## 保存模型与 Checkpoint
|
||||
|
||||
训练循环在保存 step 调用 `core/utils/checkpoint.py` 中的 TrainingCheckpointCoordinator。它协调模型、优化器、scheduler、批次进度与训练计数等状态;其中依赖分片格式的模型和优化器读写交给 DistributedPlugin。这样,训练器决定何时保存,后端决定如何保存其分布式状态。
|
||||
|
||||
`fit()` 结束后,任务入口另外调用 `save_model()` 保存最终模型。最终模型与用于续训的 checkpoint 用途不同,用户配置见[模型保存与恢复](../../feature-guide/model_saving.md)。
|
||||
|
||||
## 扩展边界
|
||||
|
||||
新增训练目标时,在 Trainer 子类中实现损失和必要的任务准备。替换优化器、批处理或分布式实现时使用[训练器插件](../plugins/trainer_plugins.md),避免在每个任务的训练循环中复制后端分支。只观察生命周期事件时使用 [Callback](callback.md)。
|
||||
45
docs/zh/developer-guide/core/batch_generator.md
Normal file
45
docs/zh/developer-guide/core/batch_generator.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# BatchGenerator
|
||||
|
||||
`core/utils/batching.py` 负责 sampler、DataLoader、collate、梯度累积批次和状态恢复;`trainer_plugins/batching.py` 提供非 normal 策略。
|
||||
|
||||
## 输入、输出与状态
|
||||
|
||||
BatchGenerator 接收 DataEngine、Renderer 和批处理参数。内部的 StatefulDataLoader 按 DP 维度分配样本,并用 `Renderer.process_samples` 把读出的消息转换为 ModelInput 列表。此时还没有完成训练 batch 的组装。
|
||||
|
||||
这些 ModelInput 进入 StatefulBuffer,再由选定策略取出、截断并组织为 BatchInput。`__next__()` 返回的是一个更新步所需的 micro-batch 列表,BaseTrainer 逐个计算损失和累积梯度。
|
||||
|
||||
```text
|
||||
DataEngine + StatefulDistributedSampler
|
||||
→ StatefulDataLoader(Renderer.process_samples)
|
||||
→ StatefulBuffer
|
||||
→ normal collate 或 BatchingPlugin.generate_batch
|
||||
→ list[BatchInput]
|
||||
```
|
||||
|
||||
BatchGenerator 持有 DataLoader、迭代器和缓冲区;策略插件接收缓冲区和 `batch_info`,决定如何填充与取样。读取进度因此不保存在插件注册表中。
|
||||
|
||||
## Normal Batching
|
||||
|
||||
固定取 `micro_batch_size` 个样本,Renderer 处理后按当前 batch 最长序列 padding。
|
||||
|
||||
## Padding-Free Batching
|
||||
|
||||
`BatchingPlugin("padding_free")` 将多个样本拼成无 padding 的序列,并维护能够隔离文档的 attention/position 信息。
|
||||
|
||||
## Dynamic Batching
|
||||
|
||||
动态策略根据样本 token 数决定每个 batch 包含多少样本。纯 `dynamic_batching` 仍执行 padding;`dynamic_padding_free` 同时拼接序列。
|
||||
|
||||
## 保存批次状态
|
||||
|
||||
`state_dict()` 同时保存 DataLoader 的读取状态与 buffer 中已读取、尚未消费的样本。只恢复前者会丢掉预读样本,只恢复后者则无法确定接下来应该读哪里。
|
||||
|
||||
`load_state_dict()` 恢复两部分状态并设置 `_is_resuming`。普通 `__iter__()` 会清空 buffer;恢复后的首次迭代保留 buffer,随后清除恢复标记。新增策略必须保持这个状态约定,不能将剩余样本藏在无法随 checkpoint 保存的全局变量中。
|
||||
|
||||
## 校验动态批处理参数
|
||||
|
||||
纯 `dynamic_batching` 需要正数 `max_steps` 且不能使用 `save_epochs`,这些条件在 `TrainingArguments.__post_init__` 中校验。多模态输入是否能由当前策略处理,则在 BatchGenerator 生成 batch 时检查。配置条件与使用选择见[批处理策略](../../feature-guide/batching.md)。
|
||||
|
||||
## 扩展边界
|
||||
|
||||
改变 token 预算或样本拼接方式时实现 BatchingPlugin 的方法组,接口见[训练器插件](../plugins/trainer_plugins.md#batchingplugin)。改变消息如何变成 token 时修改 Renderer,改变反向传播和更新边界时检查 BaseTrainer。
|
||||
39
docs/zh/developer-guide/core/callback.md
Normal file
39
docs/zh/developer-guide/core/callback.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Callback
|
||||
|
||||
Callback 系统位于 `utils/callbacks/`,用于把日志和生命周期通知从训练循环中分离。
|
||||
|
||||
## Callback 组件
|
||||
|
||||
- `TrainerCallback`:事件接口
|
||||
- `CallbackHandler`:按注册顺序广播事件
|
||||
- `LoggingCallback`:输出 loss、learning rate、grad norm 等指标
|
||||
|
||||
## 事件如何传递
|
||||
|
||||
BaseTrainer 创建 CallbackHandler,并先加入默认 LoggingCallback,再加入构造参数 `callbacks` 中的实例。训练循环在固定位置调用 handler;handler 按列表顺序同步调用每个实例的同名方法,不经过 BasePlugin 注册表。
|
||||
|
||||
```text
|
||||
on_train_begin
|
||||
→ on_epoch_begin
|
||||
→ on_step_begin
|
||||
→ 前向、反向与更新
|
||||
→ on_step_end
|
||||
→ on_log(到达 logging_steps 时)
|
||||
→ on_save(checkpoint 写入后)
|
||||
→ on_epoch_end
|
||||
on_train_end
|
||||
```
|
||||
|
||||
事件位置由 Trainer 和 checkpoint 协调器决定。Callback 无需自行判断什么时候保存模型或推进优化器,只响应已经发生的生命周期事件。
|
||||
|
||||
## Callback 能读取什么
|
||||
|
||||
每个事件接收训练参数 `args`、进度对象 `state` 和额外关键字参数。TrainerState 保存 step、epoch、最近一次损失、梯度范数和学习率等;Handler 还通过关键字参数传入当前 model、optimizer、lr_scheduler 和批次生成器。
|
||||
|
||||
在 `on_step_begin` 时,本步计算尚未发生,损失等指标仍来自此前的更新;本步指标在 `on_step_end` 前写入 state。`on_log` 额外接收本次日志字典。
|
||||
|
||||
## 扩展边界
|
||||
|
||||
自定义 Callback 继承 TrainerCallback,仅覆盖关心的事件,并将实例传给 Trainer 的 `callbacks` 参数。它适合记录指标、连接外部观察工具等附加行为。需要改变损失、更新规则或 checkpoint 格式时,使用 Trainer 或对应插件。
|
||||
|
||||
接口约定将 state 作为供观察的进度信息,不通过修改它来控制训练流程;代码没有把这个 dataclass 冻结。事件也不会统一限制到 rank 0,涉及单次输出的 Callback 需要自行判断 rank,默认 LoggingCallback 就在自身内部处理这个条件。
|
||||
39
docs/zh/developer-guide/core/data_engine.md
Normal file
39
docs/zh/developer-guide/core/data_engine.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# DataEngine
|
||||
|
||||
`DataEngine(dataset_path: str)` 位于 `core/data_engine.py`,把一个或多个原始数据集暴露为可按整数索引访问的统一 Dataset。它处理数据来源、字段转换和样本索引,返回的仍是消息结构;分词和监督标签由后续 [Renderer](renderer.md)生成。
|
||||
|
||||
## 加载数据集
|
||||
|
||||
```text
|
||||
dataset_path
|
||||
→ 识别 YAML、目录、数据文件或 Hub ID
|
||||
→ 生成 dataset name → DatasetInfo 映射
|
||||
→ hf_hub 直接加载,其他 source 调用 DataLoaderPlugin.load
|
||||
→ 逐条转换样本,确定 SFT 的受监督轮次
|
||||
→ 建立 (dataset_name, sample_index, cut) 全局索引
|
||||
→ 根据 size / weight 调整索引
|
||||
```
|
||||
|
||||
初始化时,`datasets` 保存各来源加载出的 Dataset,`dataset_infos` 保存来源配置,`data_index` 保存训练样本到原始行的映射。索引项中的 `cut` 表示取消息列表的哪个前缀;它不是 token 截断长度。
|
||||
|
||||
多轮 SFT 的每个受监督 assistant turn 对应一个索引项,多个索引项可以指向同一条原始对话。DPO 等非 SFT 样本保持完整,`cut` 为 `None`。这一设计让 sampler 能按训练样本分配索引,同时保留原始数据集。
|
||||
|
||||
## 读取一个样本
|
||||
|
||||
`__getitem__` 从全局索引取出数据集名称、原始行号和 `cut`,再由 `_get` 读取原始行、调用 converter,并按 `cut` 截取消息前缀。返回样本带有 `_dataset_name`,供后续处理识别来源。
|
||||
|
||||
Converter 既会在初始化建立索引时调用,也会在实际取样时调用;DataEngine 不把索引阶段的转换结果缓存为新的数据集。因此转换函数应对相同输入产生一致的消息结构,避免依赖调用次数或在转换中改变原始行,否则索引记录的轮次可能与训练读取的内容不一致。
|
||||
|
||||
## 解析 DatasetInfo
|
||||
|
||||
字段结构定义在 `utils/types.py`。`_get_dataset_info` 将路径、Hub ID 或 YAML 统一成名称到 DatasetInfo 的映射,后续加载逻辑只处理这个映射。字段与默认值见[数据参数](../../configuration/data.md#datasetinfo)。
|
||||
|
||||
## 处理 Streaming Dataset
|
||||
|
||||
所有数据集必须同时为 map-style 或同时为 streaming。混合模式无法共享同一种索引和 sampler 语义,因此 DataEngine 初始化阶段会拒绝。当前 BatchGenerator 只支持 map-style dataset;streaming dataset 进入批处理初始化时会抛出 `NotImplementedError`。
|
||||
|
||||
## 扩展数据源与格式
|
||||
|
||||
加载新来源时,扩展 `DataLoaderPlugin`,保持返回 Dataset 的约定;只改变原始字段的含义时,扩展 `DataConverterPlugin`,保持返回标准 Sample 的约定。两种接口及其调用参数见[数据插件](../plugins/data_plugins.md)。
|
||||
|
||||
多轮展开和全局索引属于 DataEngine,共用索引行为应在此处理。模型模板、tokenization 和 padding 分别属于 Renderer 与 BatchGenerator,不放入 loader 或 converter。用户用法见[数据准备](../../feature-guide/data_preparation.md)。
|
||||
26
docs/zh/developer-guide/core/index.md
Normal file
26
docs/zh/developer-guide/core/index.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Core(核心模块)
|
||||
|
||||
Core 负责连接配置、数据、模型和训练流程。各组件由 Trainer 或 Sampler 组合,不通过插件注册表选择。
|
||||
|
||||
| 组件 | 职责 | 源码 |
|
||||
|------|------|------|
|
||||
| [DataEngine](data_engine.md) | 加载、转换和索引数据集 | `core/data_engine.py` |
|
||||
| [ModelEngine](model_engine.md) | 加载 Processor、Renderer 和模型 | `core/model_engine.py` |
|
||||
| [Renderer](renderer.md) | 将 Messages 转换为模型输入 | `core/rendering/` |
|
||||
| [BaseTrainer](base_trainer.md) | 管理通用训练生命周期 | `core/base_trainer.py` |
|
||||
| [BaseSampler](base_sampler.md) | 选择推理后端并连接生成接口 | `core/base_sampler.py` |
|
||||
| [BatchGenerator](batch_generator.md) | 生成批次并恢复批次状态 | `core/utils/batching.py` |
|
||||
| [Callback](callback.md) | 分发训练生命周期事件 | `utils/callbacks/` |
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
data_engine
|
||||
model_engine
|
||||
renderer
|
||||
base_trainer
|
||||
base_sampler
|
||||
batch_generator
|
||||
callback
|
||||
```
|
||||
46
docs/zh/developer-guide/core/model_engine.md
Normal file
46
docs/zh/developer-guide/core/model_engine.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# ModelEngine
|
||||
|
||||
`ModelEngine(model_args, is_train=False)` 拥有 processor、model config、Renderer 和最终 Hugging Face model。
|
||||
|
||||
实现位于 `core/model_engine.py`。它把同一份模型配置转为相互匹配的模型与输入处理组件;任务入口随后把 `model` 和 `renderer` 交给 Trainer 或 Sampler。训练循环、优化器创建和常规分布式分片在后续组件中完成。
|
||||
|
||||
## 模型加载流程
|
||||
|
||||
```text
|
||||
AutoProcessor.from_pretrained
|
||||
→ 同步或覆盖 chat_template
|
||||
→ AutoConfig.from_pretrained
|
||||
→ Renderer(processor)
|
||||
→ 选择初始化设备
|
||||
→ 应用量化加载参数
|
||||
→ 选择 AutoModel 类
|
||||
→ from_pretrained / from_config
|
||||
→ PEFT
|
||||
→ Kernel
|
||||
```
|
||||
|
||||
这个顺序由 ModelEngine 固定:初始化插件先决定在哪里创建模型,量化插件再补充权重加载参数;模型对象创建后,PEFT 决定可训练部分或加载 adapter,Kernel 最后处理实际得到的模型。插件之间不互相调度,后一阶段接收前一阶段的结果。
|
||||
|
||||
`is_train` 会传给量化和 PEFT 路径,并影响未启用 PEFT 时的模型精度处理。它表达本次加载的用途,训练循环仍会在 `fit()` 中设置模型的训练模式。
|
||||
|
||||
## 同步 Chat Template
|
||||
|
||||
多模态 processor 没有模板时,会从其 tokenizer 同步。`custom_chat_template` 则覆盖 processor/tokenizer 模板。Renderer 最终调用 `apply_chat_template`,不再导入模型专属 Python 模板。
|
||||
|
||||
## 选择 Hugging Face 模型类
|
||||
|
||||
- `llm`:根据模型 config 选择 image-to-text、多模态语言模型或因果语言模型类;多模态语言模型类仅在当前 Transformers 提供时参与选择
|
||||
- `cls`:单标签 token classification 模型,RM 使用
|
||||
- `other`:`AutoModel`
|
||||
|
||||
## Meta 与 ZeRO-3 初始化
|
||||
|
||||
普通路径通过 `from_pretrained` 加载权重。选择 meta device 后,ModelEngine 使用 `init_empty_weights()` 和 `from_config` 构造模型结构,此时参数没有真实数据,需要后续分布式加载路径填充。`init_on_rank0` 则让 rank 0 在 CPU 加载,其余 rank 构造 meta 模型。
|
||||
|
||||
Meta 初始化不能与量化同时使用;当前 LoRA 路径也会拒绝 `init_on_meta`。这些检查发生在模型加载阶段,不能通过调整 YAML 中字段的书写顺序绕过。
|
||||
|
||||
DeepSpeed ZeRO-3 需要在 `from_pretrained` 创建参数时介入,因此 ModelEngine 在加载前建立 ZeRO-3 上下文,并在加载后清理;后续 BaseTrainer 再准备训练 engine。它与 FSDP2 在 Trainer 中对已构造模型进行分片的时机不同。
|
||||
|
||||
## 扩展边界
|
||||
|
||||
改变加载顺序或 AutoModel 类选择时,修改 ModelEngine;增加一种初始化、PEFT 或量化实现时,扩展相应[模型插件](../plugins/model_plugins.md)。只需改变消息格式时,使用 chat template 或修改 Renderer 的转换逻辑,无需增加一种模型加载插件。
|
||||
51
docs/zh/developer-guide/core/renderer.md
Normal file
51
docs/zh/developer-guide/core/renderer.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Renderer
|
||||
|
||||
当前 Renderer 位于 `core/rendering/`,把 v1 `Sample` 转成 tokenized `ModelInput`。它不再依赖 `RenderingPlugin` 或模型名称模板表。
|
||||
|
||||
## 在数据路径中的位置
|
||||
|
||||
DataEngine 负责返回标准消息结构,ModelEngine 提供与模型匹配的 processor 并创建 Renderer。BatchGenerator 的 DataLoader 调用 `Renderer.process_samples(samples)`,得到已分词的样本列表,再执行批次组装。
|
||||
|
||||
Renderer 的结果包含 `input_ids`、`attention_mask`、`labels`、`loss_weights` 和位置信息;多模态样本还携带 processor 产生的媒体特征。它负责表达模型输入和监督范围,batch 内的 padding、拼接以及长度截断由后续批处理承担。
|
||||
|
||||
## Chat Template 的来源
|
||||
|
||||
1. 使用 processor/tokenizer 自带 `chat_template`。
|
||||
2. `custom_chat_template` 可以在 ModelEngine 中覆盖它。
|
||||
3. 模型完全没有模板时使用内置 ChatML fallback。
|
||||
|
||||
## 生成训练标签
|
||||
|
||||
多轮对话由 DataEngine 按每个受监督 assistant turn 切分为训练样本(见[DataEngine](data_engine.md))。Renderer 对样本最后一个 assistant turn 分别渲染 prompt 和完整序列,通过两者前缀差恢复监督 token 区间,不维护模型专属 role marker 表。
|
||||
|
||||
```text
|
||||
messages before assistant + generation prompt → prompt ids
|
||||
messages including assistant response → full ids
|
||||
full ids 中超出 prompt 的尾部 → supervised span
|
||||
```
|
||||
|
||||
这种方式兼容模型在历史消息中处理 reasoning 内容的差异。
|
||||
|
||||
该方法要求 prompt 的 token 序列与完整序列的前缀完全一致。Renderer 会实际比较两次编码的结果;如果模板在追加最后一轮后改写了前面的内容,会抛出错误,避免把上下文 token 当作回复标签。
|
||||
|
||||
前缀部分的 `labels` 为 `IGNORE_INDEX`、`loss_weights` 为零;最后回复按该轮的监督权重设置 `loss_weights`,有监督的位置使用实际 token ID 作为 label。生成模式则添加 generation prompt,并把所有位置设为不参与监督。
|
||||
|
||||
## 处理多模态内容
|
||||
|
||||
Renderer 先把标准内容块转换为 Hugging Face 消息结构,再通过 chat template 生成文本。存在媒体内容时,processor 接收文本与图片、视频或解码后的音频,并返回 token 与媒体特征。Renderer 把这些特征和媒体位置标记一并传给批处理,保持文本与媒体对应。
|
||||
|
||||
## 拼接 Chosen/Rejected 序列
|
||||
|
||||
chosen 与 rejected 分别渲染后拼接,并使用 `token_type_ids` 标记两个文档。DPO/RM 根据标记构造 block-diagonal attention 和各自 position ids,避免 rejected 序列读取 chosen 序列。
|
||||
|
||||
Renderer 为两段序列分别从起点生成 position IDs,并用 `token_type_ids` 的 `1`、`2` 保留段边界。物理拼接只改变存储布局;两段仍是独立回答,任务 Trainer 需要保留这个隔离语义。
|
||||
|
||||
## 转义特殊 Token
|
||||
|
||||
`core/rendering/escape.py` 在渲染用户控制的文本和 tools 前处理中和 tokenizer 的特殊 token 字符串,避免输入直接注入特殊 token。
|
||||
|
||||
## 自定义 Chat Template
|
||||
|
||||
新模型通常应在模型仓库的 tokenizer 配置中提供标准 HF chat template。仅在运行时覆盖时使用 `custom_chat_template`,无需注册 Python 插件。
|
||||
|
||||
若原始数据字段需要变化,扩展 converter;若标准消息如何映射到模型输入发生变化,再检查 `rendering/format.py` 和 `rendering/rendering.py`。转换原始字段与生成监督标签分属不同阶段,避免在 converter 中依赖模型的 token ID。
|
||||
20
docs/zh/developer-guide/index.md
Normal file
20
docs/zh/developer-guide/index.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 开发者指南
|
||||
|
||||
开发者指南说明 v1 的运行路径和扩展点。v1 由 Core(核心模块)组织主要运行流程,并通过 Plugin(插件系统)提供可替换实现。
|
||||
|
||||
## 架构
|
||||
|
||||
| 页面 | 内容 |
|
||||
|------|------|
|
||||
| [整体架构](architecture_overview.md) | 模块分层以及 Core 与 Plugin 的调用关系 |
|
||||
|
||||
## Core(核心模块)
|
||||
|
||||
[Core(核心模块)](core/index.md)说明数据加载、模型加载、样本渲染、批处理和训练循环。
|
||||
|
||||
## Plugin(插件系统)
|
||||
|
||||
| 页面 | 内容 |
|
||||
|------|------|
|
||||
| [插件注册机制](baseplugin_mechanism.md) | `BasePlugin` 的注册、路由和参数解析 |
|
||||
| [插件实现](plugins/index.md) | 数据、模型和训练器插件,以及融合算子加速 |
|
||||
57
docs/zh/developer-guide/plugins/data_plugins.md
Normal file
57
docs/zh/developer-guide/plugins/data_plugins.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# 数据插件
|
||||
|
||||
数据插件把数据来源和原始字段格式从 DataEngine 的索引逻辑中分离。Loader 负责获得可读取的数据集,Converter 负责解释其中的一条记录;两者由不同配置字段选择,可以组合使用。
|
||||
|
||||
## 与 DataEngine 的交接
|
||||
|
||||
```text
|
||||
DatasetInfo.source
|
||||
→ hf_hub:DataEngine 直接调用 datasets.load_dataset
|
||||
→ 其他来源:DataLoaderPlugin(source).load(dataset_info)
|
||||
→ Dataset
|
||||
Dataset 中的一条原始记录 + DatasetInfo.converter
|
||||
→ DataConverterPlugin(converter)(raw_sample)
|
||||
→ 标准 SFTSample / DPOSample
|
||||
```
|
||||
|
||||
相同的本地 loader 可以配合 `alpaca` 或 `sharegpt` converter;数据已经是标准消息结构时省略 converter。分词与标签生成发生在后续 Renderer 中。
|
||||
|
||||
## DataLoaderPlugin
|
||||
|
||||
接口定义在 `plugins/data_plugins/loader.py`。DataEngine 调用 `DataLoaderPlugin(source).load(dataset_info)`,而 `load` 会从 DatasetInfo 中提取 `path`、`split` 和 `streaming`,再将这三个位置参数传给注册函数。
|
||||
|
||||
因此,注册函数接收的是以下参数,不是整个 DatasetInfo:
|
||||
|
||||
```python
|
||||
@DataLoaderPlugin("example").register()
|
||||
def load_example(path, split, streaming):
|
||||
...
|
||||
```
|
||||
|
||||
当前注册的 `local` 根据文件扩展名选择 Hugging Face dataset builder,再加载文件或目录。Hub 数据由 DataEngine 直接分派,当前没有通过一个名为 `hf_hub` 的 loader 注册项加载。
|
||||
|
||||
返回的数据集由 DataEngine 持有并用于建立索引。新增 loader 必须保持调用参数与返回数据集的约定;当前训练链路要求可按索引读取的数据集,具体 streaming 边界见 [DataEngine](../core/data_engine.md#处理-streaming-dataset)。
|
||||
|
||||
## DataConverterPlugin
|
||||
|
||||
接口定义在 `plugins/data_plugins/converter.py`。Converter 接收单条原始样本字典,返回一个 v1 `SFTSample` 或 `DPOSample`,不是输入或返回整个 batch。当前注册:
|
||||
|
||||
- `alpaca`
|
||||
- `sharegpt`
|
||||
- `pair`
|
||||
|
||||
```python
|
||||
@DataConverterPlugin("example").register()
|
||||
def convert_example(raw_sample):
|
||||
return {"messages": ...}
|
||||
```
|
||||
|
||||
返回字段必须符合 `utils/types.py` 中的 Messages 类型。SFT 返回 `messages`,偏好数据返回 `chosen_messages` 和 `rejected_messages`;图片等媒体也在这一阶段转为标准内容块,实际媒体特征由 Renderer 的 processor 生成。
|
||||
|
||||
DataEngine 在建立多轮索引和实际取样时都会调用 converter。它应稳定地转换一条记录,避免在函数中随机选择对话轮次或维护读取进度。轮次展开、采样规模和读取顺序分别由 DataEngine 与 sampler 管理。
|
||||
|
||||
## 调整数据索引
|
||||
|
||||
`adjust_data_index` 根据 `size`、`weight` 调整某个数据集的索引,`select_data_sample` 处理索引选择。两者是 `loader.py` 中的普通函数,不通过插件名称注册或路由。改变来源、格式时扩展 loader/converter;改变共用索引语义时,应检查这些函数及 DataEngine 的调用位置。
|
||||
|
||||
注册在模块导入时生效,机制见[插件注册机制](../baseplugin_mechanism.md)。使用配置见[数据准备](../../feature-guide/data_preparation.md)。
|
||||
22
docs/zh/developer-guide/plugins/index.md
Normal file
22
docs/zh/developer-guide/plugins/index.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# 插件实现
|
||||
|
||||
v1 按数据、模型和训练流程组织内置插件。配置文件通过实现名称选择插件,新增实现时使用对应的插件类注册。
|
||||
|
||||
| 分类 | 内容 |
|
||||
|------|------|
|
||||
| [数据插件](data_plugins.md) | DataLoader 与 DataConverter |
|
||||
| [模型插件](model_plugins.md) | 初始化、PEFT、量化、Kernel 和 Sequence Parallel |
|
||||
| [训练器插件](trainer_plugins.md) | 分布式后端、批处理和优化器 |
|
||||
| [融合算子加速](kernel-acceleration/overview.md) | Kernel 选择与调用流程 |
|
||||
|
||||
插件注册和参数解析的通用机制见[插件注册机制](../baseplugin_mechanism.md)。
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 2
|
||||
:hidden:
|
||||
|
||||
data_plugins
|
||||
model_plugins
|
||||
trainer_plugins
|
||||
kernel-acceleration/overview
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
# 融合算子加速
|
||||
|
||||
Kernel 系统在模型加载后应用融合算子加速。一个实现既可以替换单个算子,也可以组合多个融合操作或接入外部加速库。
|
||||
|
||||
入口位于 `plugins/model_plugins/kernels/interface.py`。它负责名称选择与调用顺序,`base.py` 中的 BaseKernel 负责执行公共检查,各实现的 `_apply` 负责识别模型并进行具体替换。注册机制、检查流程和模型适配由这三层分别承担。
|
||||
|
||||
## Kernel 应用流程
|
||||
|
||||
```text
|
||||
ModelEngine
|
||||
→ apply_kernels(model, kernel_config)
|
||||
→ 解析 kernel_config.name
|
||||
→ auto 设备选择或 KernelPlugin(name)
|
||||
→ BaseKernel.apply()
|
||||
→ check_device()
|
||||
→ check_deps()
|
||||
→ _apply()
|
||||
```
|
||||
|
||||
接口模块显式导入内置实现,使装饰器在调用前完成注册。`apply_kernels` 将名称按逗号拆分,逐个调用,并将返回模型传给下一个实现;每个实现收到同一份配置与 `require_logits` 等上下文。
|
||||
|
||||
`auto` 是入口处的特殊分派:根据设备查询 `_AUTO_KERNELS`,再调用其中的已注册实现。它不是自动搜索最快实现的算法;当前映射只包含 NPU,其他设备不会因 `auto` 而执行替换。
|
||||
|
||||
## BaseKernel 与具体实现如何协作
|
||||
|
||||
注册表保存的是实现类。`KernelPlugin(name).apply(...)` 将方法调用转发到该类,继承的 `BaseKernel.apply` 再使用 `cls` 调用该实现的检查和替换方法。
|
||||
|
||||
`check_device` 检查设备,`check_deps` 检查可选依赖,随后公共入口确认存在模型对象,最后调用 `_apply`。模型是否受支持、需要替换哪个模块,由具体 `_apply` 决定。BaseKernel 不统一检测所有模型结构。
|
||||
|
||||
例如,CUDA Fused MoE 按模型架构和模块类名寻找目标并替换 forward;Liger 根据 model type 调用对应外部适配函数;FLA 通过算子注册表匹配模型属性。成功找到注册名称,只说明能进入实现,不能保证模型中存在可替换目标。
|
||||
|
||||
## 组合与扩展边界
|
||||
|
||||
组合时,后一个实现看到的是已经修改过的模型。入口不提供冲突检测、模型快照或失败回滚,也不会把各实现的专属配置拆成独立配置块。新增实现需要清楚界定自己修改哪些模块,并返回后续调用所需的模型对象。
|
||||
|
||||
实现类继承 BaseKernel,提供 `check_device` 和 `_apply`,需要额外依赖时覆盖 `check_deps`;子类定义时会检查必需方法是否实现。名称注册后,还需要确保实现模块在使用前被导入。通用路由与注册规则见[插件注册机制](../../baseplugin_mechanism.md)。
|
||||
|
||||
## 已注册实现
|
||||
|
||||
- `liger_kernel`
|
||||
- `cuda_fused_moe`
|
||||
- `flash-linear-attention`
|
||||
- `npu_fused_moe`
|
||||
- `npu_fused_rmsnorm`
|
||||
- `npu_fused_rope`
|
||||
- `npu_fused_swiglu`
|
||||
|
||||
用户配置见[融合算子加速](../../../feature-guide/kernel_acceleration.md)。
|
||||
47
docs/zh/developer-guide/plugins/model_plugins.md
Normal file
47
docs/zh/developer-guide/plugins/model_plugins.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# 模型插件
|
||||
|
||||
模型插件提供模型加载和处理过程中的可替换操作。初始化、量化、PEFT 和 Kernel 由 ModelEngine 依次调用;Sequence Parallel 需要训练拓扑,因此由 BaseTrainer 在训练初始化阶段调用。
|
||||
|
||||
## 每个插件接收和改变什么
|
||||
|
||||
| 插件 | 接收 | 返回或修改 |
|
||||
|------|------|------------|
|
||||
| InitPlugin | 当前进程的设备与 rank 信息 | 返回用于创建模型的 `torch.device` |
|
||||
| QuantizationPlugin | 模型加载参数、量化配置与训练标记 | 返回补充量化选项后的加载参数 |
|
||||
| PeftPlugin | 已构造模型、PEFT 配置与训练标记 | 设置可训练参数、加载或合并 adapter,返回处理后的模型 |
|
||||
| KernelPlugin | PEFT 处理后的模型与 Kernel 配置 | 替换适配的计算路径,返回处理后的模型 |
|
||||
|
||||
它们的接口不同,不能仅通过替换 `name` 在不同插件族之间互换。具体调用次序及原因见 [ModelEngine](../core/model_engine.md)。
|
||||
|
||||
## InitPlugin
|
||||
|
||||
注册 `init_on_default`、`init_on_meta`、`init_on_rank0`,返回模型创建使用的 `torch.device`。
|
||||
|
||||
实现位于 `plugins/model_plugins/initialization.py`。这些函数不加载模型权重;ModelEngine 根据返回设备决定调用 `from_pretrained` 还是在 meta 上使用 `from_config`。Rank 0 加载与其他 rank 的权重同步需要后续分布式路径协作。
|
||||
|
||||
## PeftPlugin
|
||||
|
||||
注册 `lora` 与 `freeze`。两者分别通过 `LoraParams` 和 `FreezeParams` 严格解析配置。LoRA 还负责 adapter 加载、合并与导出。
|
||||
|
||||
实现位于 `plugins/model_plugins/peft.py`。训练时,LoRA 创建或加载 adapter,Freeze 按层和模块选择可训练权重;后续优化器只收集 `requires_grad` 的参数。推理与合并导出也复用 LoRA 插件,因此同一配置入口的行为还取决于调用时的 `is_train`。
|
||||
|
||||
## QuantizationPlugin
|
||||
|
||||
注册 `auto` 与 `bnb`。插件修改 `from_pretrained` 的 init kwargs,不直接替换已经加载的权重。
|
||||
|
||||
实现位于 `plugins/model_plugins/quantization.py`。调用发生在模型创建之前,使量化选项能参与权重加载;这也解释了它与加载完成后执行的 PEFT、Kernel 所处阶段不同。当前可配置字段见[模型参数](../../configuration/model.md#quant_config)。
|
||||
|
||||
## KernelPlugin
|
||||
|
||||
Kernel 在模型加载和 PEFT 处理后应用。调用流程见[融合算子加速](kernel-acceleration/overview.md)。
|
||||
|
||||
## Sequence Parallel Plugins
|
||||
|
||||
设置 `TrainingArguments.cp_size > 1` 后,BaseTrainer 使用 `cp_mode` 的值选择 `SequenceParallelModelPlugin`。因此,`cp_mode: ulysses` 会调用 `SequenceParallelModelPlugin("ulysses")` 修改模型 forward 所需的通信;训练循环再调用 `SequenceParallelLossPlugin("sequence_parallel_loss")` 处理 loss 聚合。用户配置见[分布式训练](../../feature-guide/distributed_training.md#ulysses-context-parallel)。
|
||||
|
||||
这两个插件共同完成序列并行:模型侧处理 attention 的通信与切分,损失侧处理分布后的输入与监督计算。只替换 forward 而沿用不匹配的损失路径,会破坏这组协作关系。实现位于 `plugins/model_plugins/parallelization/`。
|
||||
|
||||
## Chat Template 迁移
|
||||
|
||||
旧 `RenderingPlugin` 和 `plugins/model_plugins/templates/` 已删除。Chat
|
||||
template 统一由 `core/rendering/` 调用 Hugging Face 模板。
|
||||
51
docs/zh/developer-guide/plugins/trainer_plugins.md
Normal file
51
docs/zh/developer-guide/plugins/trainer_plugins.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 训练器插件
|
||||
|
||||
训练器插件替换训练过程中的具体操作。BaseTrainer 持有模型、优化器和训练计数,BatchGenerator 持有读取进度与缓冲区;插件通过调用参数访问这些对象。替换实现时需要维持调用方依赖的输入、输出和状态约定。
|
||||
|
||||
## DistributedPlugin
|
||||
|
||||
当前注册 `fsdp2`、`fsdpturbo` 和 `deepspeed`。每个实现类提供统一的模型切分、保存和 checkpoint 方法组:
|
||||
|
||||
- `shard_model`
|
||||
- `save_model`
|
||||
- `save_checkpoint`
|
||||
- `load_checkpoint`
|
||||
|
||||
参数分别由 `FSDP2Params`、`FSDPTurboParams` 和 `DeepSpeedParams` 解析。FSDPTurbo 额外实现跨专家并行 Mesh 的梯度裁剪。公共 DeviceMesh 拓扑由 `TrainingArguments` 和 `DistributedInterface` 管理。
|
||||
|
||||
注册和入口位于 `plugins/trainer_plugins/distributed/interface.py`,具体引擎位于同目录下的 `fsdp2.py`、`fsdpturbo.py` 和 `deepspeed.py`。路由层把配置转换为对应 Params,再委托后端执行;参数配置本身不负责创建进程组。
|
||||
|
||||
FSDP2 / FSDPTurbo 的 `shard_model` 返回处理后的模型,BaseTrainer 再创建优化器。DeepSpeed 的该入口返回后端 engine,BaseTrainer 随后调用它的 `prepare`,共同准备模型、优化器和 scheduler。因此,公共入口背后的返回对象与初始化协议仍需结合 BaseTrainer 的后端分支理解。
|
||||
|
||||
保存时,Trainer 和 checkpoint 协调器决定时机与通用训练状态,分布式插件负责其模型和优化器状态格式。扩展新后端需要同时提供分片、最终模型保存、checkpoint 保存与恢复;仅实现分片无法覆盖完整训练生命周期。
|
||||
|
||||
## BatchingPlugin
|
||||
|
||||
`normal` 是 BatchGenerator 默认路径。插件注册:
|
||||
|
||||
- `padding_free`
|
||||
- `dynamic_batching`
|
||||
- `dynamic_padding_free`
|
||||
|
||||
接口与实现位于 `plugins/trainer_plugins/batching.py`。实现类继承 BaseBatcher,提供四个操作:
|
||||
|
||||
| 方法 | BatchGenerator 用它决定什么 |
|
||||
|------|-----------------------------|
|
||||
| `get_data_provider_batch_size` | 底层 DataLoader 每次读多少条样本 |
|
||||
| `compute_length` | 批次生成器报告的长度 |
|
||||
| `fill_buffer` | 何时继续读取样本、怎样填充缓冲区 |
|
||||
| `generate_batch` | 如何取出样本并组织一个更新步的 micro-batch 列表 |
|
||||
|
||||
方法接收 `batch_info`、buffer 或读取函数,状态由调用方管理。`generate_batch` 返回 `None` 时,BatchGenerator 结束本次迭代。新策略需要同时考虑数据耗尽、剩余 buffer 和 checkpoint 恢复,不能只实现拼接张量。
|
||||
|
||||
## OptimizerPlugin
|
||||
|
||||
当前注册 `muon`。未指定插件时 BaseTrainer 使用默认优化器。Muon 将适合正交化更新的二维权重和其余 AdamW 权重分组。用户配置见[优化器](../../feature-guide/optimizer.md)。
|
||||
|
||||
入口位于 `plugins/trainer_plugins/optimizers/optimizer.py`,接收处理后的模型与 `optim_config`,返回 optimizer 实例。当前 Muon 直接读取配置字段;顶层 `learning_rate` 在 TrainingArguments 初始化时写入配置的 `lr`。插件负责参数分组与优化器构造,反向传播和更新时机仍由 Trainer 或 DeepSpeed engine 控制。
|
||||
|
||||
## LRSchedulerPlugin
|
||||
|
||||
插件族存在,但当前没有注册可选的 scheduler 名称。
|
||||
|
||||
接口位于 `plugins/trainer_plugins/lr_scheduler.py`。BaseTrainer 未收到配置时使用固定倍率的 LambdaLR;收到配置时按名称调用插件,传入 optimizer、训练总步数与配置,并保存返回的 scheduler。扩展实现应返回兼容训练循环和 checkpoint 状态保存的 scheduler 对象。
|
||||
42
docs/zh/feature-guide/batching.md
Normal file
42
docs/zh/feature-guide/batching.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 批处理策略
|
||||
|
||||
`batching_strategy` 决定每个 micro-batch 包含多少条样本,以及这些样本是通过 padding 组成矩形张量还是拼接为一条连续序列。
|
||||
|
||||
| 策略 | 样本数 | 序列组织方式 |
|
||||
|------|--------|--------------|
|
||||
| `normal` | 固定 | 按 batch 内最长序列 padding |
|
||||
| `padding_free` | 固定 | 将多条样本拼接为一条连续序列 |
|
||||
| `dynamic_batching` | 动态 | 按最长序列 padding |
|
||||
| `dynamic_padding_free` | 动态 | 按 token 预算选择样本并拼接 |
|
||||
|
||||
例如设置 `cutoff_len: 2048`、`micro_batch_size: 4` 时,动态策略的 token 预算为 `2048 × 4 = 8192`。假设依次读到的样本长度为 2048、512、512、512:
|
||||
|
||||
- `normal` 固定选择 4 条样本,并将每条样本 padding 到 2048,最终处理 8192 个 token 位置。
|
||||
- `padding_free` 仍选择 4 条样本,但将它们拼接为长度 3584 的序列,从而移除 padding。
|
||||
- `dynamic_batching` 在 `最长样本长度 × 样本数` 不超过 8192 的范围内决定样本数,然后按最长样本进行 padding。
|
||||
- `dynamic_padding_free` 在样本总长度不超过 8192 的范围内决定样本数,并将所选样本拼接起来。
|
||||
|
||||
因此,动态策略中的 `micro_batch_size` 用于计算 token 预算,并不表示最终 batch 一定包含相同数量的样本。
|
||||
|
||||
## 配置示例
|
||||
|
||||
`batching_strategy` 是训练 YAML 的顶层字段。以下片段配置 `dynamic_padding_free`,每个 micro-batch 的 token 预算为 `2048 × 4 = 8192`:
|
||||
|
||||
```yaml
|
||||
batching_strategy: dynamic_padding_free
|
||||
micro_batch_size: 4
|
||||
cutoff_len: 2048
|
||||
max_steps: 100
|
||||
flash_attn: flash_attention_2
|
||||
```
|
||||
|
||||
仓库在 `examples/v1/train_batching_strategy/` 下为四种策略提供了完整示例。
|
||||
|
||||
## 使用约束
|
||||
|
||||
- `dynamic_batching` 必须设置正数 `max_steps`。
|
||||
- `dynamic_batching` 不支持 `save_epochs`,应使用 `save_steps`。
|
||||
- `padding_free` 和 `dynamic_padding_free` 需要设置 `flash_attn: flash_attention_2`。
|
||||
- `normal` 以外的策略仅支持纯文本数据;使用其他策略处理多模态数据时,BatchGenerator 会在生成 batch 时抛出 `NotImplementedError`。
|
||||
|
||||
内部 collate 和状态恢复流程见[BatchGenerator](../developer-guide/core/batch_generator.md)。
|
||||
89
docs/zh/feature-guide/data_preparation.md
Normal file
89
docs/zh/feature-guide/data_preparation.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 数据准备
|
||||
|
||||
v1 将训练样本统一为 Messages 结构。`DataEngine` 根据 `train_dataset` 指向的路径加载数据,并在存在 `converter` 时转换原始字段。
|
||||
|
||||
## 配置训练数据集
|
||||
|
||||
训练 YAML 的 `train_dataset` 指定数据来源。数据文件路径或 Hub ID 对应单个 Messages 格式数据集;数据集 YAML 则通过条目描述数据路径、split、converter 和采样配置,并支持组合多个数据集。
|
||||
|
||||
训练 YAML 包含 `model`、`train_dataset` 等训练字段;数据集 YAML 以数据集名称为键,包含 `path`、`source`、`converter` 等字段。下文“组合多个数据集”展示数据集 YAML 的结构。
|
||||
|
||||
`train_dataset` 接受以下形式:
|
||||
|
||||
- 本地数据集 YAML,例如 `data/v1_sft_demo.yaml`
|
||||
- 本地数据文件或目录
|
||||
- Hugging Face Hub 数据集 ID
|
||||
- Hub 数据集仓库中的 YAML
|
||||
|
||||
`eval_dataset` 字段已定义,评估流程尚未实现。完整字段见[数据参数](../configuration/data.md#dataarguments)。
|
||||
|
||||
## SFT 数据格式
|
||||
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "value": "介绍一下你自己。"}],
|
||||
"loss_weight": 0.0
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "value": "我是一个 AI 助手。"}],
|
||||
"loss_weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`content` 是内容块列表;文本使用 `text`,多模态内容可以使用 `image_url`、`audio_url` 或 `video_url`。`loss_weight` 是该 assistant turn 的监督权重,并应用到该回复的每个监督 token。`0.0` 不参与损失计算,`1.0` 使用完整权重,也可以设置 `0.5` 等中间值调整不同回复的相对权重。
|
||||
|
||||
多轮对话会按每个受监督的 assistant turn 展开为多条训练样本,每条样本只监督最后一个 assistant turn。
|
||||
|
||||
多模态 SFT 示例位于 `data/v1_multimodal_demo.yaml`,对应训练配置为 `examples/v1/train_full/train_multimodal.yaml`。
|
||||
|
||||
## DPO/RM 数据格式
|
||||
|
||||
DPO 和 RM 使用 `chosen_messages` 与 `rejected_messages`:
|
||||
|
||||
```json
|
||||
{
|
||||
"chosen_messages": [
|
||||
{"role": "user", "content": [{"type": "text", "value": "问题"}], "loss_weight": 0.0},
|
||||
{"role": "assistant", "content": [{"type": "text", "value": "更优回答"}], "loss_weight": 1.0}
|
||||
],
|
||||
"rejected_messages": [
|
||||
{"role": "user", "content": [{"type": "text", "value": "问题"}], "loss_weight": 0.0},
|
||||
{"role": "assistant", "content": [{"type": "text", "value": "较差回答"}], "loss_weight": 1.0}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 组合多个数据集
|
||||
|
||||
```yaml
|
||||
identity:
|
||||
path: data/identity.json
|
||||
source: local
|
||||
converter: alpaca
|
||||
|
||||
demo:
|
||||
path: organization/dataset
|
||||
source: hf_hub
|
||||
split: train
|
||||
size: 1000
|
||||
weight: 0.5
|
||||
streaming: false
|
||||
```
|
||||
|
||||
同一个 YAML 中的 streaming 配置必须一致;当前训练路径不支持 streaming 数据集。多个条目会组成一个全局数据索引;`size` 与 `weight` 用于控制每个数据集的采样规模,计算顺序与有放回抽样的含义见[采样规模的计算](../configuration/data.md#采样规模的计算)。
|
||||
|
||||
## 转换现有数据格式
|
||||
|
||||
| 名称 | 原始数据 |
|
||||
|------|----------|
|
||||
| `alpaca` | `instruction`、`input`、`output` |
|
||||
| `sharegpt` | `conversations` |
|
||||
| `pair` | chosen/rejected 偏好对 |
|
||||
|
||||
扩展 converter 的接口见[数据插件](../developer-guide/plugins/data_plugins.md)。
|
||||
103
docs/zh/feature-guide/distributed_training.md
Normal file
103
docs/zh/feature-guide/distributed_training.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 分布式训练
|
||||
|
||||
训练命令检测到多设备后会自动通过 `torchrun` 启动。拓扑字段属于 `TrainingArguments`,后端专属字段放在 `dist_config`。
|
||||
|
||||
本页列出后端和拓扑配置,完整任务配置见 [SFT](sft.md)、[DPO](dpo.md)和 [RM](rm.md)。设备安装与支持范围见 [NPU 说明](../multi-backend/npu/index.md)。
|
||||
|
||||
## 数据并行
|
||||
|
||||
未设置 `dist_config` 时,多个 DP 进程使用 DDP,每个进程持有完整模型;单设备直接训练。
|
||||
|
||||
## FSDP2
|
||||
|
||||
FSDP2 通过分片降低每个设备上的模型状态内存开销,配置入口为 `dist_config.name: fsdp2`。
|
||||
|
||||
```yaml
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
reshard_after_forward: true
|
||||
offload_params: false
|
||||
pin_memory: true
|
||||
dcp_path: null
|
||||
```
|
||||
|
||||
## FSDPTurbo
|
||||
|
||||
FSDPTurbo 在 FSDP2 基础上提供 MoE 专家并行和专家参数分片。先安装 FSDPTurbo 依赖:
|
||||
|
||||
```bash
|
||||
python -m pip install -r requirements/fsdpturbo.txt
|
||||
```
|
||||
|
||||
FSDPTurbo 的配置入口为 `dist_config.name: fsdpturbo`:
|
||||
|
||||
```yaml
|
||||
dist_config:
|
||||
name: fsdpturbo
|
||||
ep_size: 16
|
||||
ep_dispatcher: eager
|
||||
```
|
||||
|
||||
`ep_size` 必须能够整除 data parallel size。完整示例见 `examples/v1/train_full/train_full_qwen3_moe_fsdpturbo_ep_fsdp.yaml`。
|
||||
|
||||
## DeepSpeed
|
||||
|
||||
DeepSpeed 后端从 `config_file` 读取 ZeRO 等配置,该字段必填。
|
||||
|
||||
```yaml
|
||||
dist_config:
|
||||
name: deepspeed
|
||||
config_file: examples/deepspeed/ds_z3_config.json
|
||||
```
|
||||
|
||||
## Ulysses Context Parallel
|
||||
|
||||
Ulysses CP 跨设备切分序列计算,由顶层 `cp_mode` 和 `cp_size` 启用:
|
||||
|
||||
```yaml
|
||||
flash_attn: flash_attention_2
|
||||
cp_mode: ulysses
|
||||
cp_size: 2
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
```
|
||||
|
||||
设置 `cp_size > 1` 后,训练使用 Ulysses 通信和 Sequence Parallel loss 完成跨 CP 进程的损失聚合。Ulysses 需要 `flash_attention_2` 和 FSDP2,不要求特定的 `batching_strategy`,支持 `normal` 和符合[批处理约束](batching.md)的 padding-free 策略。
|
||||
|
||||
`cp_size` 需要能够整除 world size。模型的 attention head 数必须能被 `cp_size` 整除,即 `num_attention_heads % cp_size == 0`;例如 32 个 attention head 可以使用 `cp_size: 2`。KV head 数与 `cp_size` 则要求其中一个能被另一个整除,即 `num_key_value_heads % cp_size == 0` 或 `cp_size % num_key_value_heads == 0`。当前只有 SFT 支持 `cp_size > 1`;DPO 和 RM 要求 `cp_size: 1`。
|
||||
|
||||
当前训练器不支持 `model_type: qwen3_5` 的 CP 路径。
|
||||
|
||||
## 配置并行拓扑
|
||||
|
||||
```yaml
|
||||
dp_size: 4
|
||||
cp_size: 2
|
||||
cp_mode: ulysses
|
||||
mp_replicate_size: 2
|
||||
mp_shard_size: 4
|
||||
dist_timeout: 18000
|
||||
```
|
||||
|
||||
上例使用 8 个进程,并同时构造两套 DeviceMesh:
|
||||
|
||||
- Data Mesh 的形状为 `dp_size × cp_size = 4 × 2`,分别用于 Data Parallel 和 Context Parallel。
|
||||
- Model Mesh 的形状为 `mp_replicate_size × mp_shard_size = 2 × 4`。FSDP 在 4 个进程间分片参数,并在 2 个分片组间复制参数。
|
||||
|
||||
`mp_replicate_size` 和 `mp_shard_size` 描述 FSDP 的二维参数 Mesh,不是额外的 Tensor Parallel 配置。未显式指定时,`dp_size` 默认为 `world_size / cp_size`,`mp_shard_size` 默认为 `world_size / mp_replicate_size`。后端完整配置见[训练参数](../configuration/training.md#dist_config)。
|
||||
|
||||
## 配置多机启动
|
||||
|
||||
CLI 读取 `NNODES`、`NODE_RANK`、`NPROC_PER_NODE`、`MASTER_ADDR` 和 `MASTER_PORT`。例如使用 4 台机器、每台机器 8 个设备时,在每台机器上执行:
|
||||
|
||||
```bash
|
||||
NNODES=4 \
|
||||
NODE_RANK=<0到3,各节点不同> \
|
||||
NPROC_PER_NODE=8 \
|
||||
MASTER_ADDR=<rank 0 节点的 IP> \
|
||||
MASTER_PORT=29500 \
|
||||
llamafactory-cli sft config.yaml
|
||||
```
|
||||
|
||||
4 个节点需要使用相同的 `NNODES`、`NPROC_PER_NODE`、`MASTER_ADDR` 和 `MASTER_PORT`,并分别设置 `NODE_RANK=0`、`1`、`2`、`3`。
|
||||
53
docs/zh/feature-guide/dpo.md
Normal file
53
docs/zh/feature-guide/dpo.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 偏好优化(DPO)
|
||||
|
||||
v1 通过统一的 `dpo` 入口运行偏好优化,`pref_loss` 支持 `sigmoid`、`orpo` 和 `simpo`。数据必须是 chosen/rejected 偏好对。
|
||||
|
||||
## 运行 DPO
|
||||
|
||||
```bash
|
||||
llamafactory-cli dpo examples/v1/train_lora/train_lora_dpo.yaml
|
||||
```
|
||||
|
||||
## 训练配置
|
||||
|
||||
`peft_config.name: lora` 启用 LoRA,未配置 `peft_config` 时进行全参训练。以下是完整的 LoRA DPO 配置,保存为 `config.yaml` 后运行 `llamafactory-cli dpo config.yaml`:
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-4B
|
||||
model_class: llm
|
||||
train_dataset: data/v1_dpo_demo.yaml
|
||||
|
||||
peft_config:
|
||||
name: lora
|
||||
r: 16
|
||||
lora_alpha: 32
|
||||
target_modules: all
|
||||
|
||||
pref_loss: sigmoid
|
||||
pref_beta: 0.1
|
||||
pref_ftx: 0.0
|
||||
dpo_label_smoothing: 0.0
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
|
||||
output_dir: outputs/qwen3_dpo
|
||||
micro_batch_size: 1
|
||||
cutoff_len: 2048
|
||||
learning_rate: 1.0e-5
|
||||
max_steps: 10
|
||||
```
|
||||
|
||||
## 偏好损失
|
||||
|
||||
`pref_loss` 指定偏好损失:
|
||||
|
||||
- `sigmoid`:标准 DPO,相对参考策略进行偏好优化,`pref_beta` 控制偏好项缩放。
|
||||
- `orpo`:无参考策略的 odds-ratio 偏好目标,基于回答的平均 log-prob 计算。
|
||||
- `simpo`:无参考策略的平均 log-prob 差值目标,通过 `simpo_gamma` 设置 margin。
|
||||
|
||||
`pref_ftx` 加入 SFT 损失,`dpo_label_smoothing` 用于 cDPO。设置 `ld_alpha` 后,LD-DPO 会将 chosen 和 rejected 中超出较短响应长度的尾部 token log-prob 乘以该系数。参数定义见[训练参数](../configuration/training.md#trainingarguments)。
|
||||
|
||||
## 参考模型
|
||||
|
||||
标准 DPO 需要 reference log-prob:全参训练会建立独立的 reference model;LoRA 训练复用 policy model 的基座权重,并在计算 reference log-prob 时禁用 adapter。ORPO 和 SimPO 的目标计算不使用 reference log-prob。
|
||||
29
docs/zh/feature-guide/index.md
Normal file
29
docs/zh/feature-guide/index.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# 功能指南
|
||||
|
||||
功能指南面向使用 v1 完成训练与推理任务的用户。配置结构、默认值和可用选项统一放在[参数配置](../configuration/index.md)。
|
||||
|
||||
## 训练任务
|
||||
|
||||
| 页面 | 内容 |
|
||||
|------|------|
|
||||
| [数据准备](data_preparation.md) | Messages 格式、数据集 YAML 和 converter |
|
||||
| [SFT](sft.md) | 全参、LoRA、Freeze、QLoRA |
|
||||
| [DPO](dpo.md) | DPO、ORPO、SimPO 与偏好数据 |
|
||||
| [RM](rm.md) | 奖励模型训练 |
|
||||
|
||||
## 训练效率与扩展
|
||||
|
||||
| 页面 | 内容 |
|
||||
|------|------|
|
||||
| [批处理](batching.md) | 四种 batching strategy |
|
||||
| [分布式训练](distributed_training.md) | FSDP2、FSDPTurbo、DeepSpeed、Ulysses |
|
||||
| [优化器](optimizer.md) | AdamW 与 Muon 配置 |
|
||||
| [融合算子加速](kernel_acceleration.md) | Liger、融合算子和组合配置 |
|
||||
|
||||
## 模型保存与使用
|
||||
|
||||
| 页面 | 内容 |
|
||||
|------|------|
|
||||
| [模型保存与恢复](model_saving.md) | 最终模型、checkpoint、断点续训 |
|
||||
| [模型导出](model_export.md) | LoRA 合并和 HF 格式导出 |
|
||||
| [推理](inference.md) | CLI 对话与 adapter 加载 |
|
||||
53
docs/zh/feature-guide/inference.md
Normal file
53
docs/zh/feature-guide/inference.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 推理
|
||||
|
||||
v1 已实现基于 Hugging Face 后端的 `chat` 入口,可以在命令行中进行流式对话。模型对话格式来自 tokenizer 自带的 Hugging Face chat template;没有模板时回退到内置 ChatML。
|
||||
|
||||
当前 `chat` 入口支持 `sample_backend: hf` 的交互式单条推理。批量推理和 `vllm` 采样后端尚未接入该入口;交互式配置中不设置 `train_dataset`。
|
||||
|
||||
## 启动 CLI 对话
|
||||
|
||||
`model` 指定模型 Hub ID 或包含完整权重的 HF 模型目录。LoRA adapter 的加载方式见下文。
|
||||
|
||||
以下对话配置保存为 `chat.yaml`,使用与 [SFT 示例](sft.md)相同的基座:
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
sample_backend: hf
|
||||
max_new_tokens: 512
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli chat chat.yaml
|
||||
```
|
||||
|
||||
## 覆盖模型 Chat Template
|
||||
|
||||
`custom_chat_template` 接收一段 Jinja2 模板字符串,并覆盖 tokenizer 自带模板:
|
||||
|
||||
```yaml
|
||||
model: path/to/model
|
||||
custom_chat_template: >-
|
||||
{% for message in messages %}
|
||||
{{ message['role'] + ': ' + message['content'] }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
v1 使用模板字符串,不接受 `template: <name>` 字段。
|
||||
|
||||
## 使用 LoRA Adapter
|
||||
|
||||
LoRA 推理通过 `model` 指定训练时的基座,通过 `peft_config.adapter_name_or_path` 指定 adapter。以下片段加入 `chat.yaml`,加载 [SFT 的 LoRA 示例](sft.md#lora)产生的 `outputs/qwen3_lora`;对应基座为 `Qwen/Qwen3-0.6B`:
|
||||
|
||||
```yaml
|
||||
peft_config:
|
||||
name: lora
|
||||
adapter_name_or_path: outputs/qwen3_lora
|
||||
```
|
||||
|
||||
推理模式会依次合并 `adapter_name_or_path` 中的 adapter。[模型导出](model_export.md)说明合并结果的持久化保存。
|
||||
|
||||
## 使用训练或合并后的模型
|
||||
|
||||
完成 [SFT 全参示例](sft.md#全参训练)后,将 `chat.yaml` 中的 `model` 改为 `outputs/qwen3_full`;完成[模型导出示例](model_export.md#导出配置)后,改为 `outputs/qwen3_merged`。这两种目录都包含完整模型权重,加载时移除此前的 `peft_config`,保留采样参数并运行 `llamafactory-cli chat chat.yaml`。
|
||||
|
||||
完整字段见[推理参数](../configuration/inference.md)。
|
||||
53
docs/zh/feature-guide/kernel_acceleration.md
Normal file
53
docs/zh/feature-guide/kernel_acceleration.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 融合算子加速
|
||||
|
||||
`kernel_config` 统一配置模型侧的融合算子加速。它可以替换单个算子,也可以像 Liger Kernel 一样同时应用多个融合实现和训练优化。
|
||||
|
||||
`kernel_config.name` 接受一个加速实现名称,也接受逗号分隔的多个名称。未设置 `kernel_config` 或设为 `null` 时,此入口不替换算子。以下为算子配置片段,完整训练配置见 [SFT](sft.md)。
|
||||
|
||||
## 自动配置
|
||||
|
||||
`name: auto` 根据当前设备应用默认组合。当前仅 [NPU](../multi-backend/npu/index.md) 配置了默认组合,CUDA 上不会自动启用 Liger 或 CUDA Fused MoE。
|
||||
|
||||
## Liger Kernel
|
||||
|
||||
Liger Kernel 依赖 `liger-kernel`,并要求模型具有对应适配。
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: liger_kernel
|
||||
```
|
||||
|
||||
Liger Kernel 根据模型类型调用 `liger_kernel.transformers` 中对应的应用函数,可融合 RMSNorm、RoPE、SwiGLU、Cross Entropy 等训练路径。具体启用项由模型支持范围和 Liger Kernel 版本决定。
|
||||
|
||||
## CUDA Fused MoE
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: cuda_fused_moe
|
||||
```
|
||||
|
||||
该方案依赖 CUDA 和 Triton,并要求模型结构匹配,使用融合实现替换 MoE 计算路径。模型架构不匹配时保留原模型。
|
||||
|
||||
## Flash Linear Attention
|
||||
|
||||
`flash-linear-attention` 通过 FSDPTurbo 的算子注册表替换模型中已有的 FLA 实现,支持 CUDA 和 NPU。它依赖 FLA 和 FSDPTurbo,不会将普通 attention 模型转换成线性注意力模型。
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: flash-linear-attention
|
||||
include_kernels: chunk_gated_delta_rule,fused_recurrent_gated_delta_rule
|
||||
chunk_size: 64
|
||||
```
|
||||
|
||||
`include_kernels` 可以设置为 `auto` 或逗号分隔的算子名称;`chunk_size` 支持 `16`、`32` 和 `64`。使用前需要安装 `requirements/fsdpturbo.txt`。
|
||||
|
||||
## 组合多个加速实现
|
||||
|
||||
多个名称以逗号分隔。以下为语法示意,`first_kernel` 和 `second_kernel` 是占位符,运行时替换为实际注册的实现名称:
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: first_kernel,second_kernel
|
||||
```
|
||||
|
||||
多个实现按书写顺序应用,后一个接收前一个处理后的模型;所有实现共享同一份 `kernel_config`。设备与依赖检查在应用前执行,模型匹配由各实现负责。组合入口不自动处理重复替换或顺序冲突。内部调用关系见[开发者指南](../developer-guide/plugins/kernel-acceleration/overview.md),字段定义见[模型参数](../configuration/model.md#kernel_config)。
|
||||
44
docs/zh/feature-guide/model_export.md
Normal file
44
docs/zh/feature-guide/model_export.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 模型导出
|
||||
|
||||
`merge` 命令将一个或多个 LoRA adapter 依次合并到基座模型,并保存为 Hugging Face 格式目录。
|
||||
|
||||
导出目录包含合并后的模型权重。基座与 adapter 的直接加载见[推理](inference.md),训练状态的保存和续训见[模型保存与恢复](model_saving.md)。
|
||||
|
||||
## 导出配置
|
||||
|
||||
以下配置保存为 `merge.yaml`,接续 [SFT 的 LoRA 示例](sft.md#lora):基座为 `Qwen/Qwen3-0.6B`,adapter 位于 `outputs/qwen3_lora`,合并结果保存到 `outputs/qwen3_merged`。`model` 必须与 adapter 训练时的基座一致。
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
peft_config:
|
||||
name: lora
|
||||
adapter_name_or_path: outputs/qwen3_lora
|
||||
export_dir: outputs/qwen3_merged
|
||||
export_size: 5
|
||||
infer_dtype: auto
|
||||
export_legacy_format: false
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli merge merge.yaml
|
||||
```
|
||||
|
||||
导出完成后,可以将推理配置的 `model` 设置为 `outputs/qwen3_merged`,按[推理指南](inference.md#使用训练或合并后的模型)加载。
|
||||
|
||||
`export_size` 的单位为 GB。`infer_dtype` 支持 `auto`、`float16`、`float32` 和 `bfloat16`。完整字段见[模型参数](../configuration/model.md#peft_config)。
|
||||
|
||||
## 合并多个 Adapter
|
||||
|
||||
`adapter_name_or_path` 可以使用列表。系统按照列表顺序将每个 LoRA adapter 合并到前一步得到的模型中:
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
peft_config:
|
||||
name: lora
|
||||
adapter_name_or_path:
|
||||
- outputs/domain_adapter
|
||||
- outputs/task_adapter
|
||||
export_dir: outputs/qwen3_merged
|
||||
```
|
||||
|
||||
上例先合并 `domain_adapter`,再合并 `task_adapter`。这两个目录是独立训练的 adapter 示例,均须与 `Qwen/Qwen3-0.6B` 基座匹配;使用时替换为实际目录。
|
||||
61
docs/zh/feature-guide/model_saving.md
Normal file
61
docs/zh/feature-guide/model_saving.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# 模型保存与恢复
|
||||
|
||||
训练结束时 `save_model()` 保存最终模型;训练过程中可以按 step 或 epoch 保存 checkpoint。
|
||||
|
||||
## 保存训练 Checkpoint
|
||||
|
||||
`save_steps` 按更新步数触发保存,`save_epochs` 按数据遍历进度触发保存。同时设置时,训练器根据 `save_epochs` 重新计算并覆盖 `save_steps`。纯 `dynamic_batching` 只支持按 step 保存。
|
||||
|
||||
以下字段位于训练 YAML 的顶层:
|
||||
|
||||
```yaml
|
||||
save_steps: 500
|
||||
save_epochs: null
|
||||
save_total_limit: 3
|
||||
save_ckpt_as_hf: false
|
||||
```
|
||||
|
||||
`save_steps` 与 `save_epochs` 控制触发时机。`save_total_limit` 删除最旧的完整 checkpoint。
|
||||
|
||||
## 从 Checkpoint 恢复训练
|
||||
|
||||
`resume_from_checkpoint` 恢复训练状态。以下配置从当前 `output_dir` 中自动查找 checkpoint:
|
||||
|
||||
```yaml
|
||||
resume_from_checkpoint: auto
|
||||
```
|
||||
|
||||
`auto` 在 `output_dir` 下寻找最新的完整 checkpoint,也可以直接填写 checkpoint 路径。未设置 `resume_from_checkpoint` 时,即使 `output_dir` 中存在 checkpoint,也不会触发续训。
|
||||
|
||||
## 不同后端的保存格式
|
||||
|
||||
| 训练后端 | 默认 checkpoint | `save_ckpt_as_hf: true` |
|
||||
|----------|-------------------|--------------------------|
|
||||
| FSDP2 / FSDPTurbo | 保存用于续训的分布式 checkpoint | 额外在 checkpoint 中生成 `hf_model` 目录 |
|
||||
| DeepSpeed | 保存 DeepSpeed 训练状态 | 额外在 checkpoint 中生成 `hf_model` 目录 |
|
||||
| 单设备 / DDP | 模型权重使用 HF 格式保存 | 不生成额外的 `hf_model` 目录 |
|
||||
|
||||
FSDP2、FSDPTurbo 和 DeepSpeed 启用 `save_ckpt_as_hf` 后,仍会保留用于恢复训练的原始 checkpoint,同时额外保存 HF 格式模型。聚合完整模型权重会提高保存时的内存占用。
|
||||
|
||||
`save_ckpt_as_hf: false` 是默认值,保存中间 checkpoint 时不额外聚合 HF 格式权重。
|
||||
|
||||
## 初始化权重与恢复训练
|
||||
|
||||
| 配置 | 用途 | 加载时机 | 恢复内容 |
|
||||
|------|------|----------|----------|
|
||||
| `dist_config.dcp_path` | 使用 DCP 权重初始化模型 | FSDP2/FSDPTurbo 模型分片阶段 | 仅模型权重 |
|
||||
| `resume_from_checkpoint` | 从训练 checkpoint 继续训练 | Trainer 初始化阶段 | 模型、优化器、学习率调度器、批次进度、训练步数及可用的随机数状态 |
|
||||
|
||||
以下配置使用已有 DCP 模型权重初始化新训练:
|
||||
|
||||
```yaml
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
dcp_path: path/to/dcp_model
|
||||
```
|
||||
|
||||
以下配置从 `output_dir` 中最新的完整 checkpoint 恢复训练状态:
|
||||
|
||||
```yaml
|
||||
resume_from_checkpoint: auto
|
||||
```
|
||||
39
docs/zh/feature-guide/optimizer.md
Normal file
39
docs/zh/feature-guide/optimizer.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 优化器
|
||||
|
||||
`optim_config` 未设置或为 `null` 时,v1 使用 AdamW,并从顶层 `learning_rate` 读取学习率。
|
||||
|
||||
## Muon
|
||||
|
||||
设置 `optim_config.name: muon` 启用 Muon。Muon 对适合正交化更新的二维权重使用 Muon,并将偏置、归一化参数、embedding、输出层和 LoRA 参数交给内部 AdamW。
|
||||
|
||||
以下为完整的 SFT 配置(`config.yaml`):
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
model_class: llm
|
||||
train_dataset: data/v1_sft_demo.yaml
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
|
||||
optim_config:
|
||||
name: muon
|
||||
wd: 0.1
|
||||
momentum: 0.95
|
||||
nesterov: true
|
||||
ns_steps: 5
|
||||
adamw_betas: [0.9, 0.95]
|
||||
adamw_eps: 1.0e-8
|
||||
|
||||
output_dir: outputs/qwen3_muon
|
||||
micro_batch_size: 1
|
||||
cutoff_len: 2048
|
||||
learning_rate: 1.0e-5
|
||||
max_steps: 10
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli sft config.yaml
|
||||
```
|
||||
|
||||
学习率统一由顶层 `learning_rate` 控制。仓库示例见 `examples/v1/train_full/train_full_muon.yaml`,完整字段见[训练参数](../configuration/training.md#optim_config)。
|
||||
38
docs/zh/feature-guide/rm.md
Normal file
38
docs/zh/feature-guide/rm.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 奖励模型训练(RM)
|
||||
|
||||
`rm` 入口训练回答评分模型,使 chosen 回答的评分高于 rejected 回答。
|
||||
|
||||
RM 与 [DPO](dpo.md) 使用相同的偏好对数据结构,输出模型用于回答评分,不作为普通聊天模型使用。
|
||||
|
||||
## 训练配置
|
||||
|
||||
`peft_config.name: lora` 启用 LoRA,未配置 `peft_config` 时进行全参训练。分布式后端由 `dist_config` 配置,支持条件见[分布式训练](distributed_training.md)。以下为完整的 LoRA RM 配置(`config.yaml`):
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
train_dataset: data/v1_dpo_demo.yaml
|
||||
|
||||
peft_config:
|
||||
name: lora
|
||||
r: 16
|
||||
target_modules: all
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
|
||||
output_dir: outputs/qwen3_rm
|
||||
micro_batch_size: 1
|
||||
cutoff_len: 2048
|
||||
learning_rate: 1.0e-5
|
||||
max_steps: 10
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli rm config.yaml
|
||||
```
|
||||
|
||||
入口会将 `model_class` 设置为 `cls`,初始化 score head,并在训练开始前检查首个样本是否包含 `chosen_messages` 和 `rejected_messages`。
|
||||
|
||||
## 训练约束
|
||||
|
||||
RM 当前要求 `cp_size` 为 `1`。`cutoff_len` 需要保留 chosen 和 rejected 的有效 token;否则当前 micro-batch 无法组成偏好对。
|
||||
91
docs/zh/feature-guide/sft.md
Normal file
91
docs/zh/feature-guide/sft.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 监督微调(SFT)
|
||||
|
||||
`llamafactory-cli sft` 启动监督微调。下文依次说明全参训练、LoRA、Freeze 和量化 LoRA 的配置。
|
||||
|
||||
## 全参训练
|
||||
|
||||
全参训练更新全部模型参数,配置中不设置 `peft_config`。以下完整配置保存为 `config.yaml`,使用 `Qwen/Qwen3-0.6B` 和 FSDP2:
|
||||
|
||||
```yaml
|
||||
model: Qwen/Qwen3-0.6B
|
||||
model_class: llm
|
||||
train_dataset: data/v1_sft_demo.yaml
|
||||
|
||||
output_dir: outputs/qwen3_full
|
||||
micro_batch_size: 1
|
||||
cutoff_len: 2048
|
||||
learning_rate: 1.0e-4
|
||||
max_steps: 10
|
||||
|
||||
dist_config:
|
||||
name: fsdp2
|
||||
```
|
||||
|
||||
```bash
|
||||
llamafactory-cli sft config.yaml
|
||||
```
|
||||
|
||||
## LoRA
|
||||
|
||||
LoRA 冻结基座权重并训练 adapter,通过 `peft_config.name: lora` 配置。在上述训练配置中加入以下块,并将 `output_dir` 改为 `outputs/qwen3_lora`;基座仍为 `Qwen/Qwen3-0.6B`:
|
||||
|
||||
```yaml
|
||||
peft_config:
|
||||
name: lora
|
||||
r: 16
|
||||
lora_alpha: 32
|
||||
lora_dropout: 0.05
|
||||
target_modules: all
|
||||
```
|
||||
|
||||
训练结束后,adapter 保存到 `outputs/qwen3_lora`。[推理](inference.md#使用-lora-adapter)和[模型导出](model_export.md#导出配置)示例沿用这一基座与目录。
|
||||
|
||||
继续训练已有 adapter 时设置 `adapter_name_or_path`。训练只允许一个 adapter;LoRA 参数从 adapter 自身恢复。
|
||||
|
||||
## Freeze
|
||||
|
||||
Freeze 直接更新指定层或模块的权重,其余参数保持冻结。以下 `peft_config` 替换 LoRA 配置,模型、数据与训练字段沿用全参示例:
|
||||
|
||||
```yaml
|
||||
peft_config:
|
||||
name: freeze
|
||||
freeze_trainable_layers: 2
|
||||
freeze_trainable_modules: all
|
||||
freeze_extra_modules: null
|
||||
cast_trainable_params_to_fp32: true
|
||||
```
|
||||
|
||||
正数表示最后 N 层,负数表示最前 N 层。
|
||||
|
||||
## QLoRA
|
||||
|
||||
量化 LoRA 在量化后的基座上训练 adapter,分别由 `quant_config` 和 `peft_config` 控制。当前 v1 的量化插件入口为 `bnb` 和 `auto`:`bnb` 提供 bitsandbytes 的 4-bit、8-bit 加载分支;`auto` 在指定有效位宽时转交 `bnb` 处理。
|
||||
|
||||
下面是使用 bitsandbytes 4-bit 的 QLoRA 示例,运行环境需安装 bitsandbytes。将以下字段加入全参示例,模型、数据与 FSDP2 配置保持一致:
|
||||
|
||||
```yaml
|
||||
output_dir: outputs/qwen3_qlora
|
||||
|
||||
peft_config:
|
||||
name: lora
|
||||
r: 16
|
||||
target_modules: all
|
||||
|
||||
quant_config:
|
||||
name: bnb
|
||||
quantization_bit: 4
|
||||
quantization_type: nf4
|
||||
double_quantization: true
|
||||
```
|
||||
|
||||
`quantization_bit` 表示加载位宽,`quantization_type` 表示 4-bit 量化格式,`double_quantization` 控制 4-bit double quant。位宽分支与字段默认行为见[量化参数](../configuration/model.md#quant_config),后端限制见 [NPU 说明](../multi-backend/npu/index.md)。
|
||||
|
||||
## 激活值重算
|
||||
|
||||
`enable_activation_checkpointing` 默认为 `true`。启用后,训练在反向传播时重新计算部分前向结果,以减少激活值占用的显存或设备内存,并增加计算量。设置为 `false` 关闭重计算:
|
||||
|
||||
```yaml
|
||||
enable_activation_checkpointing: false
|
||||
```
|
||||
|
||||
分布式后端、批处理与算子配置分别见[分布式训练](distributed_training.md)、[批处理](batching.md)和[融合算子加速](kernel_acceleration.md)。
|
||||
@@ -1,161 +0,0 @@
|
||||
# 快速开始
|
||||
|
||||
LLaMA Factory 是一个高效、灵活的大模型微调框架,支持 100+ 种主流大语言模型的微调训练。本文档将帮助您快速上手使用 LLaMA Factory。
|
||||
|
||||
## 支持的训练方法
|
||||
|
||||
| 方法 | 全参数训练 | 部分参数训练 | LoRA | QLoRA |
|
||||
|:---------------------:| ------------------ | ------------------ | ------------------ | ------------------ |
|
||||
| 指令监督微调 (SFT) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| DPO 训练 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
> **提示**: v1 版本目前支持 SFT 和 DPO 两种训练方法,均支持多种加速特性,包括 DeepSpeed、FSDP、FlashAttention-2 等。
|
||||
|
||||
## 软件依赖
|
||||
|
||||
| 必需项 | 至少 | 推荐 |
|
||||
|:---------------------:|--------|--------|
|
||||
| python | 3.11 | 3.12 |
|
||||
| torch | 2.7.1 | 2.7.1 |
|
||||
| torch-npu(Ascend NPU) | 2.7.1 | 2.7.1 |
|
||||
| torchvision | 0.22.1 | 0.22.1 |
|
||||
| transformers | 5.0.0 | 5.0.0 |
|
||||
| datasets | 3.2.0 | 4.0.0 |
|
||||
| peft | 0.18.1 | 0.18.1 |
|
||||
|
||||
|
||||
| 可选项 | 至少 | 推荐 |
|
||||
|:----------------:|--------|--------|
|
||||
| CUDA(NVIDIA GPU) | 11.6 | 12.2 |
|
||||
| deepspeed | 0.18.4 | 0.18.4 |
|
||||
| flash-attn(NVIDIA GPU) | 2.5.6 | 2.7.2 |
|
||||
|
||||
|
||||
## 安装 LLaMA Factory
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 此步骤为必需。请确保您的环境满足上述软件依赖要求。
|
||||
|
||||
### 从源码安装(推荐)
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
|
||||
cd LLaMA-Factory
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### 使用 pip 安装
|
||||
|
||||
```bash
|
||||
pip install llamafactory
|
||||
```
|
||||
|
||||
### 可选依赖
|
||||
|
||||
如果您需要使用特定的加速特性,可以安装相应的依赖:
|
||||
|
||||
```bash
|
||||
# 安装 FlashAttention-2 支持
|
||||
pip install flash-attn --no-build-isolation
|
||||
|
||||
# 安装 DeepSpeed 支持
|
||||
pip install deepspeed
|
||||
|
||||
# 安装 Unsloth 支持(用于加速 LoRA 训练)
|
||||
pip install unsloth
|
||||
```
|
||||
|
||||
## 数据准备
|
||||
|
||||
LLaMA Factory 支持多种数据格式,包括 JSON、JSONL、CSV 等。关于数据集文件的详细格式说明,请参考 [数据准备指南](../../data/README_zh.md)。
|
||||
|
||||
### 使用内置数据集
|
||||
|
||||
LLaMA Factory 提供了多个内置数据集用于快速测试,您可以在 `data/dataset_info.json` 中查看所有可用的数据集。
|
||||
|
||||
### 使用自定义数据集
|
||||
|
||||
您可以使用 HuggingFace / ModelScope 上的数据集或加载本地数据集。
|
||||
|
||||
> [!NOTE]
|
||||
> 使用自定义数据集或自定义数据集格式时,请参照 [数据准备指南](../../data/README_zh.md) 进行配置。如有必要,请重新实现自定义数据集的数据处理逻辑,包括对应的 `converter`。
|
||||
|
||||
### 数据构建工具
|
||||
|
||||
您也可以使用以下工具构建用于微调的合成数据:
|
||||
- **[Easy Dataset](https://github.com/ConardLi/easy-dataset)** - 易于使用的数据集构建工具
|
||||
- **[DataFlow](https://github.com/OpenDCAI/DataFlow)** - 高质量数据准备管道
|
||||
- **[GraphGen](https://github.com/open-sciencelab/GraphGen)** - 基于图的数据生成工具
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 命令行训练
|
||||
|
||||
下面的命令展示了对 Qwen3-0.6B 模型使用 FSDP2 进行全参数微调:
|
||||
|
||||
```bash
|
||||
export USE_V1=1
|
||||
llamafactory-cli sft examples/v1/train_full/train_full_fsdp2.yaml
|
||||
```
|
||||
|
||||
> **提示**: `llamafactory-cli sft` 和 `llamafactory-cli train` 命令等价。
|
||||
|
||||
### Web UI 训练
|
||||
|
||||
LLaMA Factory 提供了直观的 Web 界面(LLaMA Board),您可以通过图形界面进行训练:
|
||||
|
||||
```bash
|
||||
llamafactory-cli webui
|
||||
```
|
||||
|
||||
在浏览器中打开 http://localhost:7860 即可开始使用。
|
||||
|
||||
### 推理部署
|
||||
|
||||
训练完成后,您可以使用以下命令部署模型:
|
||||
|
||||
```bash
|
||||
# 使用 vLLM 后端进行高性能推理
|
||||
llamafactory-cli chat --model_name_or_path path/to/your/model --template qwen --infer_backend vllm
|
||||
|
||||
# 使用 HuggingFace 后端进行推理
|
||||
llamafactory-cli chat --model_name_or_path path/to/your/model --template qwen
|
||||
```
|
||||
|
||||
## 进阶用法
|
||||
|
||||
高级用法请参考 [进阶指南](./advanced/README.md),包括:
|
||||
- 多卡多机分布式训练
|
||||
- LoRA/QLoRA 微调
|
||||
- 模型量化(AWQ/GPTQ/LLM.int8 等)
|
||||
- 各种加速特性(DeepSpeed、FSDP、FlashAttention 等)
|
||||
- 多模态模型微调
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 内存不足怎么办?
|
||||
|
||||
- 使用 LoRA 或 QLoRA 代替全参数训练
|
||||
- 减小 `batch_size` 和 `cutoff_len`
|
||||
- 启用 `gradient_checkpointing`
|
||||
- 使用 DeepSpeed ZeRO-2 或 ZeRO-3
|
||||
|
||||
### 2. 如何选择合适的训练方法?
|
||||
|
||||
- **SFT(指令微调)**: 最常用的方法,适用于大多数场景,通过监督数据训练模型
|
||||
- **DPO(直接偏好优化)**: 用于对齐人类偏好,提升模型输出质量,无需训练奖励模型
|
||||
|
||||
### 3. 训练完成后如何评估模型?
|
||||
|
||||
```bash
|
||||
llamafactory-cli eval --model_name_or_path path/to/your/model --template qwen --dataset mmlu
|
||||
```
|
||||
|
||||
更多评估方法请参考 [评估指南](./advanced/evaluation.md)。
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果您在使用过程中遇到问题:
|
||||
- 查看 [GitHub Issues](https://github.com/hiyouga/LLaMA-Factory/issues)
|
||||
- 加入 [Discord 社区](https://discord.gg/rKfvV9r9FK)
|
||||
- 加入微信群(扫描二维码)
|
||||
@@ -1 +0,0 @@
|
||||
# Data Argument
|
||||
@@ -1,64 +1,51 @@
|
||||
LlamaFactory 文档
|
||||
=================
|
||||
LlamaFactory v1 文档
|
||||
=====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Getting Started
|
||||
|
||||
getting-started
|
||||
installation
|
||||
llamaboard-web-ui
|
||||
quick_start
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Data Preparation
|
||||
:maxdepth: 2
|
||||
:caption: Feature Guide
|
||||
|
||||
data-preparation/data-processing
|
||||
feature-guide/index
|
||||
feature-guide/data_preparation
|
||||
feature-guide/sft
|
||||
feature-guide/dpo
|
||||
feature-guide/rm
|
||||
feature-guide/batching
|
||||
feature-guide/distributed_training
|
||||
feature-guide/optimizer
|
||||
feature-guide/model_saving
|
||||
feature-guide/model_export
|
||||
feature-guide/inference
|
||||
feature-guide/kernel_acceleration
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Training
|
||||
:maxdepth: 2
|
||||
:caption: Configuration
|
||||
|
||||
training/sft
|
||||
training/dpo
|
||||
configuration/index
|
||||
configuration/data
|
||||
configuration/model
|
||||
configuration/training
|
||||
configuration/inference
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Inference
|
||||
:maxdepth: 2
|
||||
:caption: Developer Guide
|
||||
|
||||
inference/deploy
|
||||
developer-guide/index
|
||||
developer-guide/architecture_overview
|
||||
developer-guide/core/index
|
||||
developer-guide/baseplugin_mechanism
|
||||
developer-guide/plugins/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Advanced
|
||||
:maxdepth: 2
|
||||
:caption: Multi-Backend
|
||||
|
||||
advanced/lora-and-quantization/lora
|
||||
advanced/lora-and-quantization/quantization
|
||||
advanced/ktransformers
|
||||
advanced/distributed/fsdp
|
||||
advanced/distributed/deepspeed
|
||||
advanced/distributed/parallel-dp-tp-ep-sp-cp
|
||||
advanced/distributed/fsdpturbo-ep-efsdp
|
||||
advanced/custom-kernels/triton
|
||||
advanced/custom-kernels/fused-operators
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Hyperparameters
|
||||
|
||||
hyperparameters/data-argument
|
||||
hyperparameters/model-argument
|
||||
hyperparameters/sample-argument
|
||||
hyperparameters/training-argument
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Dev Guide
|
||||
|
||||
dev-guide/core/data-engine
|
||||
dev-guide/core/model-engine
|
||||
dev-guide/core/trainer
|
||||
dev-guide/plugins/data-plugins
|
||||
dev-guide/plugins/model-plugins/initialization
|
||||
dev-guide/plugins/model-plugins/kernels
|
||||
dev-guide/plugins/model-plugins/rendering
|
||||
multi-backend/npu/index
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Deploy
|
||||
@@ -1 +0,0 @@
|
||||
# Installation
|
||||
@@ -1 +0,0 @@
|
||||
# LlamaBoard Web UI
|
||||
130
docs/zh/multi-backend/npu/index.md
Normal file
130
docs/zh/multi-backend/npu/index.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Ascend NPU
|
||||
|
||||
本页介绍 Ascend NPU 的手动安装、功能范围和融合算子加速能力。
|
||||
|
||||
## 手动安装
|
||||
|
||||
手动安装需要依次准备 HDK 驱动与固件、CANN 和 `torch-npu`。安装包需要与 NPU 型号、CPU 架构和操作系统匹配。本分支使用以下软件组合:
|
||||
|
||||
| 组件 | 版本 |
|
||||
|------|------|
|
||||
| CANN | `9.1.0` |
|
||||
| PyTorch | `2.10.0` |
|
||||
| torch-npu | `2.10.0.post2` |
|
||||
| torchvision | `0.25.0` |
|
||||
| torchaudio | `2.10.0` |
|
||||
| Triton Ascend | `3.2.1` |
|
||||
|
||||
安装前使用[Ascend 兼容性查询助手](https://www.hiascend.com/hardware/compatibility)确认硬件与操作系统组合,并从[CANN 9.1.0 社区版资源中心](https://www.hiascend.com/developer/download/community/result?cann=9.1.0&module=cann)选择对应 CPU 架构的软件包。
|
||||
|
||||
### 安装驱动与固件
|
||||
|
||||
从 Ascend 下载与设备匹配的 HDK 驱动和固件安装包。以下命令中的文件名需要替换为实际下载的包名:
|
||||
|
||||
```bash
|
||||
chmod +x Ascend-hdk-<chip_type>-npu-driver_<version>_linux-<arch>.run
|
||||
chmod +x Ascend-hdk-<chip_type>-npu-firmware_<version>.run
|
||||
|
||||
sudo ./Ascend-hdk-<chip_type>-npu-driver_<version>_linux-<arch>.run \
|
||||
--full --install-for-all
|
||||
sudo ./Ascend-hdk-<chip_type>-npu-firmware_<version>.run --full
|
||||
```
|
||||
|
||||
根据安装程序提示重启系统,然后验证驱动:
|
||||
|
||||
```bash
|
||||
npu-smi info
|
||||
```
|
||||
|
||||
### 安装 CANN
|
||||
|
||||
先安装 Toolkit,再安装与设备匹配的 ops 算子包:
|
||||
|
||||
```bash
|
||||
chmod +x Ascend-cann-toolkit_<version>_linux-<arch>.run
|
||||
sudo ./Ascend-cann-toolkit_<version>_linux-<arch>.run --install
|
||||
|
||||
chmod +x Ascend-cann-<chip_type>-ops_<version>_linux-<arch>.run
|
||||
sudo ./Ascend-cann-<chip_type>-ops_<version>_linux-<arch>.run --install
|
||||
```
|
||||
|
||||
默认以 root 安装时,加载以下环境变量:
|
||||
|
||||
```bash
|
||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh
|
||||
```
|
||||
|
||||
普通用户安装时,环境脚本位于用户选择的 CANN 安装目录。需要在每个运行 LlamaFactory 的 shell 中加载该脚本,也可以将命令加入 shell 配置文件。
|
||||
|
||||
### 安装 LlamaFactory
|
||||
|
||||
在项目根目录创建 Python 环境,并安装 NPU 依赖和 LlamaFactory:
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e .
|
||||
python -m pip install -r requirements/npu.txt
|
||||
python -m pip install -r requirements/triton_ascend.txt
|
||||
```
|
||||
|
||||
`requirements/npu.txt` 固定了相互匹配的 PyTorch、torchvision、torchaudio 和 `torch-npu` 版本;`requirements/triton_ascend.txt` 安装 NPU 对应的 Triton 实现。如果使用已有 Python 环境,应确认安装完成后的 PyTorch 与 `torch-npu` 版本仍与上述版本一致。
|
||||
|
||||
### 验证 PyTorch NPU
|
||||
|
||||
```bash
|
||||
python -c "import torch, torch_npu; print(torch.npu.is_available())"
|
||||
```
|
||||
|
||||
输出 `True` 表示 PyTorch 已识别 NPU。启用 v1 后即可运行 SFT:
|
||||
|
||||
```bash
|
||||
export USE_V1=1
|
||||
llamafactory-cli sft examples/v1/train_full/train_full_fsdp2.yaml
|
||||
```
|
||||
|
||||
## 功能范围
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|:----:|------|
|
||||
| [SFT 全参训练](../../feature-guide/sft.md) | 支持 | 支持 FSDP2 |
|
||||
| [LoRA / Freeze](../../feature-guide/sft.md) | 支持 | 使用通用 PEFT 路径 |
|
||||
| [QLoRA](../../feature-guide/sft.md#qlora) | 不支持 | 当前量化路径依赖 bitsandbytes |
|
||||
| [DPO](../../feature-guide/dpo.md) | 支持 | 使用偏好对数据 |
|
||||
| [RM](../../feature-guide/rm.md) | 支持 | `cp_size` 需要为 `1` |
|
||||
| [FSDP2](../../feature-guide/distributed_training.md) | 支持 | 使用 NPU 设备和通信后端 |
|
||||
| [FSDPTurbo](../../feature-guide/distributed_training.md) | 支持 | 提供 MoE 专家并行和专家参数分片 |
|
||||
| [Ulysses CP](../../feature-guide/distributed_training.md#ulysses-context-parallel) | 支持 | 依赖适配的 attention 实现 |
|
||||
| [DeepSpeed](../../feature-guide/distributed_training.md#deepspeed) | 依赖环境 | 由 NPU DeepSpeed 发行版和配置决定 |
|
||||
| [HF CLI 推理](../../feature-guide/inference.md) | 支持 | `sample_backend: hf` |
|
||||
|
||||
## 量化支持
|
||||
|
||||
当前 v1 QLoRA 依赖 bitsandbytes,因此不适用于 NPU。
|
||||
|
||||
## 融合算子加速
|
||||
|
||||
`kernel_config.name: auto` 在 NPU 上依次尝试:
|
||||
|
||||
- `npu_fused_moe`
|
||||
- `npu_fused_rmsnorm`
|
||||
- `npu_fused_rope`
|
||||
- `npu_fused_swiglu`
|
||||
|
||||
也可以显式选择一个或多个名称:
|
||||
|
||||
```yaml
|
||||
kernel_config:
|
||||
name: npu_fused_rmsnorm,npu_fused_rope
|
||||
```
|
||||
|
||||
每个实现会检查当前设备及 `torch_npu` 依赖。模型结构不匹配时,具体 Kernel 可能跳过替换或抛出明确错误。
|
||||
|
||||
## Liger Kernel
|
||||
|
||||
`liger_kernel` 接受 CUDA 或 NPU,但仍要求模型类型在当前 Liger 映射中,并且已安装兼容版本的 `liger_kernel`。
|
||||
|
||||
## 分布式训练
|
||||
|
||||
FSDP2、FSDPTurbo 与 Ulysses 使用 accelerator 抽象选择 NPU 通信设备。DeepSpeed 的可用性由 NPU DeepSpeed 发行版、依赖版本和配置共同决定。
|
||||
48
docs/zh/quick_start.md
Normal file
48
docs/zh/quick_start.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 快速开始
|
||||
|
||||
v1 是 LlamaFactory 的实验性架构,通过 `USE_V1=1` 启用。稳定版(v0)的功能与完整文档见[LlamaFactory 文档](https://llamafactory.readthedocs.io/)。
|
||||
|
||||
本页是 v1 的快速指南,介绍安装、启用 v1 和运行 SFT。更完整的环境说明见仓库 README。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/hiyouga/LlamaFactory.git
|
||||
cd LlamaFactory
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## 启用 v1
|
||||
|
||||
```bash
|
||||
export USE_V1=1
|
||||
```
|
||||
|
||||
## 运行 SFT
|
||||
|
||||
仓库提供数据配置 `data/v1_sft_demo.yaml` 和可运行示例。以下训练配置已经通过 `train_dataset` 引用该数据配置,可以直接运行:
|
||||
|
||||
```bash
|
||||
llamafactory-cli sft examples/v1/train_full/train_full_fsdp2.yaml
|
||||
```
|
||||
|
||||
检测到多个设备时,CLI 会自动通过 `torchrun` 重启;单设备需要强制走该入口时可以设置 `FORCE_TORCHRUN=1`。
|
||||
|
||||
## 选择运行命令
|
||||
|
||||
v1 当前支持以下命令:
|
||||
|
||||
| 命令 | 用途 |
|
||||
|------|------|
|
||||
| `sft` | 监督微调 |
|
||||
| `dpo` | 偏好优化 |
|
||||
| `rm` | 奖励模型训练 |
|
||||
| `chat` | 交互式推理 |
|
||||
| `merge` | 合并 LoRA adapter 并导出模型 |
|
||||
|
||||
## 文档导航
|
||||
|
||||
- [功能指南](feature-guide/index.md):训练、推理、分布式训练、模型保存与融合算子加速
|
||||
- [参数说明](configuration/index.md):数据、模型、训练和推理参数
|
||||
- [开发者指南](developer-guide/index.md):v1 架构、Core 与 Plugin
|
||||
- [多后端](multi-backend/npu/index.md):昇腾 NPU 的环境安装与功能说明
|
||||
@@ -1 +0,0 @@
|
||||
# DPO
|
||||
@@ -1 +0,0 @@
|
||||
# SFT
|
||||
Reference in New Issue
Block a user