Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
68d9e01
feat: add datasets_v2 module and SFT-V2 training pipeline
weiyixuanxx May 12, 2026
6bded35
First version of changes: the YAML config file requires setting stage…
weiyixuanxx May 15, 2026
21ff444
fix .gitignore
weiyixuanxx May 18, 2026
9a19676
Add datasets_v2/dataset module (LazyEncodeDataset)
weiyixuanxx May 18, 2026
9214b9b
feat(datasets_v2): complete template features migration and pipeline …
weiyixuanxx May 21, 2026
3916027
fix: add missing grounding_plugin.py to datasets_v2
weiyixuanxx May 21, 2026
ebcb25f
refactor(datasets_v2): reduce coupling in encode.py and align encodin…
weiyixuanxx May 21, 2026
5e06bb8
fix(datasets_v2): support erniekit format, tool_calls schema, and dat…
weiyixuanxx May 21, 2026
1477924
fix: revert dataset_type default to "iterable" to avoid breaking old …
weiyixuanxx May 22, 2026
e01933d
feat(datasets_v2): add DPO-V2 support to V2 pipeline
weiyixuanxx May 22, 2026
3c98b4b
fix: lazy import V2 workflows in tuner.py to avoid import side-effects
weiyixuanxx May 22, 2026
880d3bf
fix: restore run_dpo top-level import while keeping datasets_v2 lazy
weiyixuanxx May 25, 2026
6635328
fix: lazy-load sft V2 workflows to prevent datasets_v2 import on old …
weiyixuanxx May 25, 2026
96c360f
fix: use getattr for separate_mtp_headloss in gpt_provider
weiyixuanxx May 25, 2026
1e5e63e
style: minor comment wording in template.py
weiyixuanxx May 25, 2026
dcc4ccb
Merge remote-tracking branch 'upstream/develop' into dev_dataset_v2
weiyixuanxx May 25, 2026
2dca7de
Merge remote-tracking branch 'upstream/develop' into dev_dataset_v2
weiyixuanxx Jun 1, 2026
3e1c15a
fix(datasets_v2): avoid duplicate eos when assistant_slot already con…
weiyixuanxx Jun 1, 2026
14000cf
Merge remote-tracking branch 'upstream/develop' into dev_dataset_v2
weiyixuanxx Jun 1, 2026
87ba0b3
Merge remote-tracking branch 'upstream/develop' into dev_dataset_v2
weiyixuanxx Jun 1, 2026
cf11125
Merge branch 'dev_dataset_v2' of https://github.com/weiyixuanxx/Paddl…
weiyixuanxx Jun 2, 2026
e76fd39
feat(datasets_v2): add true streaming support and refine V2 pipeline
weiyixuanxx Jun 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ csrc/third_party/
dataset/
output/
!tests/dataset/
!paddleformers/datasets_v2/dataset/

# gen codes
autogen/
Expand All @@ -154,6 +155,7 @@ csrc/third_party/
dataset/
output/
!tests/dataset/
!paddleformers/datasets_v2/dataset/

# gen codes
autogen/
Expand Down
224 changes: 224 additions & 0 deletions docs/zh/datasets_v2_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# datasets_v2 架构设计文档

## 1. 概述

datasets_v2 是 PaddleFormers 的新一代数据处理模块,基于 HuggingFace datasets 库构建,目标是提供统一的、可扩展的数据加载与预处理管线。

**核心设计原则:**
- 显式 schema 作为管线契约(所有模块基于同一份字段定义交互)
- 基于 HF Dataset.map() 的批处理框架(兼容 Map 式和 Iterable 流式)
- 多格式归一化:无论输入是什么格式,输出统一为 messages 标准格式
- 面向多模态 + 纯文本双重场景

---

## 2. 模块划分与开发顺序

```
datasets_v2/
├── schema.py # Step 1: 数据契约(字段定义、类型、校验)
├── preprocessors/ # Step 2: 数据预处理(格式归一化)
│ ├── base.py # 批处理框架
│ ├── response.py # query/response 格式
│ ├── messages.py # 对话/ShareGPT 格式
│ ├── extra.py # Alpaca 等薄封装
│ ├── auto.py # 自动格式检测与分发
│ └── __init__.py
├── ops.py # Step 3: 数据集操作(sample/split/concat/shuffle/shard)
├── registry.py # Step 4: 数据集注册表
├── loaders.py # Step 4: 数据加载器(本地/远程/多格式)
├── builder.py # Step 5: load_dataset 统一入口
├── adapters.py # Step 6: 训练框架适配(Paddle DataLoader 对接)
└── __init__.py # 公共 API 导出
```

---

## 3. Step 1: schema.py — 数据契约

### 3.1 标准字段(29 个)

| 类别 | 字段 |
|------|------|
| 核心对话 | messages |
| 多模态 | images, videos, audios |
| 工具调用 | tools |
| Grounding | objects |
| 偏好学习 | rejected_/positive_/negative_ × 上述 6 个 |
| 标量 | rejected_response, label, channel, margin, teacher_prompt |

### 3.2 消息格式

```python
messages = [
{"role": "system", "content": "...", "loss": False}, # loss 可选
{"role": "user", "content": "..."},
{"role": "assistant", "content": "..."},
]
```

合法 role: `system`, `user`, `assistant`, `tool_call`, `tool_response`, `tool`

### 3.3 多模态数据格式

```python
images: List[{"bytes": Optional[bytes], "path": str}]
videos: List[str] # 路径列表
audios: List[str] # 路径列表
```

### 3.4 关键函数

- `check_messages(messages)` — 校验 messages 结构合法性
- `cast_images(images)` — 将 str/dict/list 归一化为 `List[ImageMedia]`
- `cast_media_list(media)` — 将 str 归一化为 `List[str]`
- `remove_non_standard_keys(row)` — 过滤非标准字段

---

## 4. Step 2: preprocessors/ — 数据预处理

### 4.1 BasePreprocessor(base.py)

核心机制:将 `HF Dataset.map(batched=True)` 与逐行处理逻辑桥接。

```
Dataset.map(batched=True, batch_size=1000)
_batched_preprocess(batched_row)
│ _batched_to_rows: 列式 → 行式
│ for row: preprocess(row) → dict / list[dict] / None
│ _check_and_cast: 校验 + 类型归一化
│ _rows_to_batched: 行式 → 列式
返回给 HF 拼接
```

**关键设计:**
- `preprocess(row)` 由子类实现,返回 dict(一行)、list[dict](展开)、None(跳过)
- 容错:`strict=False` 时单行出错只 warning + 跳过,不中断整体
- 列重命名:`DEFAULT_COLUMN_ALIASES` + 用户自定义 `columns` 参数
- `num_proc` 仅对 HfMapDataset 生效(IterableDataset 不支持多进程)

### 4.2 ResponsePreprocessor(response.py)

**输入格式:**
```python
{"query": "...", "response": "...", "system": "...", "history": [["q1","r1"], ...]}
```

**处理逻辑:**
1. pop response(若为 list 取第一个)
2. pop history(支持字符串格式自动 `ast.literal_eval`)
3. `history.append([query, response])`
4. `history_to_messages(history, system)` → 标准 messages

**列别名:** query ← prompt/input/instruction/question/problem; response ← answer/output/targets/text/completion/content

### 4.3 MessagesPreprocessor(messages.py)

**输入格式(三种):**

标准格式:
```python
{"messages": [{"role": "user", "content": "..."}, ...]}
```

非标准 key:
```python
{"conversations": [{"from": "human", "value": "..."}, {"from": "gpt", "value": "..."}]}
```

ShareGPT paired 格式:
```python
{"conversations": [{"human": "...", "gpt": "..."}, ...]}
```

**处理逻辑:**
1. 自动检测 role_key(role/from)、content_key(content/value)
2. 判断是否 ShareGPT 格式(第一条消息无 role/content 字段)
3. 统一角色名:human→user, gpt→assistant, function_call→tool_call 等
4. 插入 system 消息

### 4.4 AlpacaPreprocessor(extra.py)

继承 ResponsePreprocessor,仅做字段拼接:
```python
query = f"{instruction}\n{input}" if both else instruction or input
row['response'] = output
→ 委托给 ResponsePreprocessor.preprocess()
```

### 4.5 AutoPreprocessor(auto.py)

分发逻辑:
```python
if 'messages'/'conversation'/'conversations' in columns → MessagesPreprocessor
elif 'instruction' + 'input' in columns → AlpacaPreprocessor
else → ResponsePreprocessor
```

---

## 5. Step 3-7: 待实现模块

### 5.1 ops.py — 数据集操作

提供:
- `sample_dataset(dataset, n)` — 采样
- `split_dataset(dataset, ratio)` — 训练/验证拆分
- `concat_datasets([ds1, ds2, ...])` — 合并
- `interleave_datasets([ds1, ds2, ...], probs)` — 按比例交错
- `shuffle_dataset(dataset, seed)` — 打乱
- `shard_dataset(dataset, num_shards, index)` — 分片

### 5.2 registry.py — 数据集注册表

- 数据集名称 → 元信息(路径/URL、preprocessor 类型、列映射)的注册机制
- 支持内置数据集和用户自定义注册

### 5.3 loaders.py — 数据加载

- 本地文件加载(json/jsonl/csv/parquet)
- HuggingFace Hub 加载
- 自定义 URL 下载
- 统一返回 HF Dataset/IterableDataset

### 5.4 builder.py — load_dataset 入口

用户侧唯一入口:
```python
from paddleformers.datasets_v2 import load_dataset
dataset = load_dataset("dataset_name", split="train", streaming=False)
```
内部串联 registry → loader → preprocessor → ops

### 5.5 adapters.py — 训练框架适配

- 将 HF Dataset 转为 Paddle DataLoader 可消费的格式
- 处理 collate_fn、padding、动态 batching 等

---

## 6. 关键设计决策记录

1. **schema 独立成文件** — 将字段定义集中到 schema.py 作为单一真相源
2. **HF Dataset 类型命名** — `HfMapDataset` / `HfIterableDataset`,体现来源(HF)和访问模式(Map/Iterable)
3. **DATASET_TYPE 放在 schema** — 跨模块使用的类型定义统一放在契约层
4. **preprocessors 分文件** — 基础类各自独立(response、messages),薄封装合并到 extra.py
5. **AlpacaPreprocessor 移除 instruction/input/output 的列映射** — 避免与 ResponsePreprocessor 的 QUERY_KEYS 冲突,这些字段由 preprocess() 手动处理
6. **_rows_to_batched 使用 set().union()** — 字段顺序不影响 HF Dataset(基于 key 访问),性能优于逐行收集

---

## 7. 测试

测试文件:`tests/datasets_v2/test_preprocessors.py`

调试配置:最外层 `.vscode/launch.json` → "Test datasets_v2 Preprocessors"

运行命令:
```bash
python -m pytest tests/datasets_v2/test_preprocessors.py -v
```
2 changes: 1 addition & 1 deletion examples/config/sft/full.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ _attn_implementation: flashmask

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: full
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/full_function_call.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ loss_subbatch_sequence_length: 8192

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: full
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/full_map.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ _attn_implementation: flashmask

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: full
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/full_tp_pp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ _attn_implementation: flashmask

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: full
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/full_tp_pp_ep.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ _attn_implementation: flashmask

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: full
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/lora.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ lora_rank: 8

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: lora
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/lora_tp_pp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ lora_rank: 8

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: lora
seed: 23
do_train: true
Expand Down
2 changes: 1 addition & 1 deletion examples/config/sft/lora_tp_pp_ep.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ lora_rank: 8

### finetuning
# base
stage: SFT
stage: SFT-V2
fine_tuning: lora
seed: 23
do_train: true
Expand Down
10 changes: 9 additions & 1 deletion paddleformers/cli/train/dpo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@

from .workflow import run_dpo

__all__ = ["run_dpo"]
__all__ = ["run_dpo", "run_dpo_v2"]


def __getattr__(name):
if name == "run_dpo_v2":
from .workflow2 import run_dpo_v2

return run_dpo_v2
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
Loading
Loading