已开启
[RFC] Offline IDX/BIN 使用与转测说明 #348
huilan_li创建于  29 天前
huilan_li成员
29 天前 创建

Offline IDX/BIN 使用与转测说明

本文只说明 LLM Offline Indexed Dataset(.idx/.bin)的应用场景,不依赖现有训练 YAML。
内容分为两部分:

  1. 使用转换工具把原始文本转换为 IDX/BIN。
  2. 拿到已有 IDX/BIN 后,检查数据并接入训练。

不测试 VLM、图片或视频数据。转测以命令能否正常结束、数据能否读取、训练能否持续运行和 loss 是否正常等
应用侧可观测结果为准,不把内部索引或 Dataset 实现细节作为验收项。

测试人员不需要分析 position ID、attention mask 或 loss mask 等内部 Tensor;涉及这些开关的用例,只验收
训练能否正常启动和持续运行,以及 loss 是否为有限值。

统一验收标准:

  • 转换或读取命令退出码为 0,日志中没有 ERRORTraceback
  • 训练场景至少连续完成 3 个训练 step,进程无异常,loss 不为 NaNInf
  • 测试人员不需要检查 batch shape、记录长度或内部 Tensor 的具体数值。

一、使用转换工具生成 IDX/BIN

1. 适用场景

转换工具支持 JSON、JSONL 文件、目录或 glob 输入,并根据 --json-keys 读取文本字段。

示例 JSONL:

{"text": "first training document"}
{"text": "second training document"}

转换结果分为两类:

转换模式 使用场景 关键参数 输出记录长度
Non-packed 普通变长文档训练 不设置 --pack-to-seq-len 可以不同
Packed/pre-cut 提前制作定长训练记录 --pack-to-seq-len <seq_length> 固定为 seq_length + 1

2. 生成 Non-packed 数据

Non-packed 模式只进行 tokenization,不在离线阶段补齐或切成定长训练记录。

python -m hyper_parallel.auto_models.components.datasets.tools.offline_preparation \
  --dataset-name-or-path /path/to/train.jsonl \
  --json-keys text \
  --output-prefix /path/to/indexed/train \
  --tokenizer-name-or-path /path/to/tokenizer \
  --tokenizer-use-fast true \
  --workers 8 \
  --append-eod true

不要设置 --pack-to-seq-len

输出:

/path/to/indexed/train_text_document.bin
/path/to/indexed/train_text_document.idx

3. 生成 Packed/pre-cut 数据

Packed 模式用于提前生成与模型训练长度匹配的定长记录。假设训练的 seq_length=2048

python -m hyper_parallel.auto_models.components.datasets.tools.offline_preparation \
  --dataset-name-or-path /path/to/train.jsonl \
  --json-keys text \
  --output-prefix /path/to/indexed/train_packed \
  --tokenizer-name-or-path /path/to/tokenizer \
  --tokenizer-use-fast true \
  --workers 8 \
  --append-eod true \
  --pack-to-seq-len 2048

每条输出记录包含 2049 个 token:

2049 token
├── input_ids = text[:-1]  # 2048
└── labels    = text[1:]   # 2048

输入结束时不足 2049 个 token 的尾部会被丢弃,不写入 PAD。

4. EOD 选项

--append-eod true 会在每个非空文档末尾追加 tokenizer 定义的 EOS/EOD token。

  • 训练时必须使用相同 tokenizer,或提供完全一致的 vocab_sizeeod_token_id
  • tokenizer 必须定义 eos_token_idsep_token_id,否则追加 EOD 会失败。
  • Packed 数据可以设置 --append-eod false,但记录中将没有可用于文档边界处理的 EOD。

5. 检查转换结果

先检查两个文件均存在且非空:

test -s /path/to/indexed/train_text_document.bin
test -s /path/to/indexed/train_text_document.idx

再读取元数据和少量样本:

python -m hyper_parallel.auto_models.components.datasets.tools.read_indexed_dataset \
  --path /path/to/indexed/train_text_document \
  --tokenizer /path/to/tokenizer \
  --num-samples 3

Non-packed 数据应满足:

  • sequence 和 document 数量大于 0。
  • sequence 长度允许不同。
  • token ID 在模型词表范围内。
  • 启用 append-eod 时,非空文档末尾包含正确的 EOD ID。

Packed 数据应满足:

min_length = max_length = seq_length + 1

例如 seq_length=2048 时,所有记录长度必须为 2049。

6. 转换工具限制

  • 输入字段必须与 --json-keys 一致,字段值应为可 tokenization 的文本。
  • 输出目录必须存在或允许创建,并且具有足够的磁盘空间。
  • 同一个 prefix 的 .bin/.idx 必须来自同一次转换。
  • 离线转换和训练必须使用相同的 tokenizer 规则。
  • Packed 数据不支持 PAD;尾部不足完整记录时直接丢弃。
  • --pack-to-seq-len 必须大于 0,并与后续训练的 seq_length 一致。
  • 数据量过小时,Packed 转换可能无法生成任何完整记录。

7. 转换工具转测场景

用例 操作 预期结果
C-1 JSONL 转换为 Non-packed 数据并接入训练 转换和读取命令正常结束,训练至少完成 3 个 step,无异常且 loss 正常
C-2 JSONL 转换为 Packed 数据并接入训练 转换和读取命令正常结束,训练至少完成 3 个 step,无异常且 loss 正常
C-3 指定多个 --json-keys 进行转换 转换命令正常结束,各输出数据均能正常读取
C-4 分别设置 append-eod=true/false 后接入训练 两种配置均至少完成 3 个训练 step,无异常且 loss 正常

二、拿到 IDX/BIN 后接入训练

1. 确认文件和 Dataset prefix

一个 Dataset prefix 对应两个文件:

<prefix>.bin
<prefix>.idx

配置中的 dataset.data_path 填 prefix,不带 .bin.idx 后缀。

文件:
/data/train_text_document.bin
/data/train_text_document.idx

配置:
dataset.data_path: /data/train_text_document

如果不了解数据的制作方式,先使用读取工具查看长度:

python -m hyper_parallel.auto_models.components.datasets.tools.read_indexed_dataset \
  --path /data/train_text_document \
  --tokenizer /path/to/tokenizer \
  --num-samples 3

根据检查结果选择模式:

已有数据特征 is_dataset_from_mr 要求
变长、未提前 packing 的文档 false 不含离线 PAD
固定长度的 Packed/pre-cut 记录 true 每条严格为 seq_length + 1

2. Non-packed 数据配置示例

dataset:
  model_assets:
    tokenizer:
      _target_: hyper_parallel.auto_models.components.datasets.llm.build_tokenizer.AutoTokenizer.from_pretrained
      pretrained_model_name_or_path: /path/to/tokenizer
      tokenizer_type: hf
      use_fast: true
      local_files_only: true

  _target_: hyper_parallel.auto_models.components.datasets.llm.build_indexed_text_dataset
  data_path: /data/train_text_document
  data_config:
    seq_length: 2048
    split: "1, 0, 0"
    is_dataset_from_mr: false
    labels_are_shifted: true

Indexed Dataset 返回的 labels 已经是与 logits 对齐的 next-token labels,因此必须配置
labels_are_shifted: true,避免模型或 loss 再次 shift。未列出的 Dataset 参数使用默认值。转测只检查训练至少
连续完成 3 个 step,无异常且 loss 正常。

3. Packed/pre-cut 数据配置示例

dataset:
  model_assets:
    tokenizer:
      _target_: hyper_parallel.auto_models.components.datasets.llm.build_tokenizer.AutoTokenizer.from_pretrained
      pretrained_model_name_or_path: /path/to/tokenizer
      tokenizer_type: hf
      use_fast: true
      local_files_only: true

  _target_: hyper_parallel.auto_models.components.datasets.llm.build_indexed_text_dataset
  data_path: /data/train_packed_text_document
  data_config:
    seq_length: 2048
    split: "1, 0, 0"
    is_dataset_from_mr: true
    labels_are_shifted: true

Packed Indexed Dataset 同样已经生成 next-token labels,必须配置 labels_are_shifted: true。未列出的 Dataset
参数使用默认值。已有 Packed 数据的记录长度必须为 2049;转测只检查训练至少连续完成 3 个 step,无异常且
loss 正常。

4. 只有 token 元数据时

如果没有可加载的 Hugging Face tokenizer,但明确知道数据使用的词表和 EOD ID,可以使用
pretokenized

dataset:
  model_assets:
    tokenizer:
      _target_: hyper_parallel.auto_models.components.datasets.llm.build_tokenizer.AutoTokenizer.from_pretrained
      pretrained_model_name_or_path: /path/to/stable/tokenizer-identity
      tokenizer_type: pretokenized
      vocab_size: 32000
      eod_token_id: 2
  • vocab_sizeeod_token_id 必须与数据制作阶段完全一致。
  • pretrained_model_name_or_path 使用稳定、可区分该 tokenizer 的身份路径。
  • Pretokenized 模式不能编码或解码原始文本,只适合读取已有 token 数据。

检查命令:

python -m hyper_parallel.auto_models.components.datasets.tools.read_indexed_dataset \
  --path /data/train_text_document \
  --tokenizer-type pretokenized \
  --vocab-size 32000 \
  --eod-token-id 2 \
  --num-samples 3

5. DataLoader 配置示例

两种模式都使用 Indexed 数据源:

dataloader:
  _target_: hyper_parallel.auto_models.components.datasets.FixedBatchDataLoader

  collate_fn:
    _target_: hyper_parallel.auto_models.components.datasets.build_indexed_collate_fn

  get_batch:
    _target_: hyper_parallel.auto_models.components.datasets.ParallelBatch
    source_type: indexed

未列出的 DataLoader 参数使用默认值。

6. EOD 训练选项

dataset:
  data_config:
    reset_position_ids: false
    reset_attention_mask: false
    eod_mask_loss: false
  • reset_position_ids=true:EOD 后 position ID 从 0 重新开始。
  • reset_attention_mask=true:EOD 后的 token 不再关注前一个文档。
  • eod_mask_loss=true:EOD 对应位置不参与 loss。
  • 三项均为 false:token 流按连续序列训练。

7. 已有 IDX/BIN 的使用限制

  • .bin/.idx 必须成对存在,data_path 必须填写 prefix。
  • 必须确认数据是 Non-packed 还是 Packed,不能只根据文件名判断。
  • Packed 数据的制作 seq_length 必须与训练配置一致。
  • 模型 vocab_size 必须大于数据中的最大 token ID。
  • tokenizer 和 EOD ID 必须与数据制作阶段一致。
  • tokenizer 的 PAD ID 如果存在,必须与 EOD/EOS ID 不同。
  • Non-packed 数据配置 is_dataset_from_mr: false
  • Packed 数据配置 is_dataset_from_mr: true,且不允许 PAD。
  • Non-packed 和 Packed Indexed 数据都必须配置 labels_are_shifted: true
  • global_batch_size 必须能被 micro_batch_size * dp_world_size 整除。
  • 数据量至少能够提供一个完整的全局 DP micro-batch。

8. 已有 IDX/BIN 转测场景

用例 操作 预期结果
U-1 接入已有 Non-packed IDX/BIN 至少完成 3 个训练 step,无异常且 loss 正常
U-2 接入已有 Packed IDX/BIN 至少完成 3 个训练 step,无异常且 loss 正常
U-3 使用 Pretokenized 元数据接入 数据正常读取,至少完成 3 个训练 step,无异常且 loss 正常
U-4 分别单独启用 reset_position_idsreset_attention_maskeod_mask_loss 每种配置均至少完成 3 个训练 step,无异常且 loss 正常

更多数据结构说明见 Indexed Dataset 使用教程

likedislike
Hhuilan_li成员
29 天前 修改标题为 “[RFC] Indexed Dataset 使用教程”,原标题为“[RFC]”
Hhuilan_li成员
29 天前 修改了issue 的描述
Hhuilan_li成员
29 天前 修改标题为 “[RFC] 使用与转测说明”,原标题为“[RFC] Indexed Dataset 使用教程”
Hhuilan_li成员
29 天前 修改标题为 “[RFC] Offline IDX/BIN 使用与转测说明”,原标题为“[RFC] 使用与转测说明”
Hhuilan_li成员
29 天前 修改了issue 的描述
Hhuilan_li成员
29 天前 修改了issue 的描述