MS-SWIFT 的数据缓存分为三个层次:
数据预处理后的缓存使用 HuggingFace Datasets 的Arrow格式缓存。
默认缓存目录:
python展开代码# 通过 modelscope 的 get_cache_dir() 获取
from modelscope.hub.utils.utils import get_cache_dir
cache_dir = get_cache_dir() # 默认: ~/.cache/modelscope/
dataset_cache = os.path.join(cache_dir, 'datasets', 'map_cache')
实际路径:
展开代码~/.cache/modelscope/datasets/map_cache/
或者在你的环境中可能是:
展开代码/mnt/jfs6/g-xiedong/.cache/modelscope/datasets/map_cache/
缓存文件名基于数据集的 fingerprint (指纹)生成:
python展开代码# 代码位置: swift/llm/dataset/preprocessor/core.py
if isinstance(dataset, HfDataset) and not dataset.cache_files:
map_kwargs['cache_file_name'] = os.path.join(
get_cache_dir(),
'datasets',
'map_cache',
f'{dataset._fingerprint}.arrow' # 使用数据集指纹作为文件名
)
缓存文件示例:
展开代码~/.cache/modelscope/datasets/map_cache/ ├── abc123def456.arrow # 预处理后的数据集1 ├── xyz789uvw012.arrow # 预处理后的数据集2 └── ...
在你的 qwen3_vl_8b_train_swanlab.yaml 中:
yaml展开代码load_from_cache_file: true # 启用缓存 (默认)
# load_from_cache_file: false # 禁用缓存,每次重新处理
bash展开代码# 在 train_swanlab.sh 中设置
export MODELSCOPE_CACHE=/mnt/jfs6/g-xiedong/.cache/modelscope
首次运行:
mask_history_sample,进行样本拆分.arrow 缓存文件后续运行:
load_from_cache_file=true,直接加载缓存缓存失效条件:
在你的配置中:
yaml展开代码packing: true # 启用packing
Packing 将多个短样本打包到一个序列中,提高训练效率,减少padding浪费。
默认目录:
python展开代码# 代码位置: swift/llm/dataset/indexed_dataset.py
cache_dir = os.getenv('PACKING_CACHE') or os.path.join(get_cache_dir(), 'tmp')
cache_dir = os.path.join(cache_dir, dataset_name)
实际路径:
展开代码~/.cache/modelscope/tmp/<dataset_name>/
或通过环境变量自定义:
bash展开代码export PACKING_CACHE=/mnt/jfs6/g-xiedong/.cache/packing
展开代码~/.cache/modelscope/tmp/<dataset_name>/ ├── data.idx # 索引文件 (pickle格式) ├── data-00000.bin # 数据分片1 (pickle序列化) ├── data-00001.bin # 数据分片2 ├── data-00002.bin # 数据分片3 └── ...
索引文件内容 (data.idx):
python展开代码{
'idx': [0, 1024, 2048, ...], # 每个样本的字节偏移量
'length': [512, 1024, 768, ...], # 每个样本的长度
'n_shard': 3, # 分片数量
'shard_offset': [0, 10GB, 20GB] # 每个分片的起始偏移
}
数据文件特点:
python展开代码# 1. 读取预处理后的数据集
train_dataset = load_dataset(...)
# 2. 启用packing后,创建 PackingDataset
if args.packing:
from swift.llm.dataset.utils import PackingDataset
train_dataset = PackingDataset(
template=template,
dataset=train_dataset,
packing_length=max_length,
packing_num_proc=num_proc
)
# 3. Packing过程:
# - 按长度排序样本
# - 贪心算法打包到packing_length
# - 多进程加速
# 4. 写入IndexedDataset缓存
builder = IndexedDatasetBuilder(dataset_name)
builder.add_items(packed_samples)
builder.finalize()
优点:
缓存复用条件:
python展开代码cache_dir = os.path.join(get_cache_dir(), 'media_resources')
# 实际: ~/.cache/modelscope/media_resources/
images 字段videos 字段audios 字段在你的 dataset_info.json 中:
json展开代码{
"mmdu_val": {
"file_name": "data.jsonl",
"media_dir": "/mnt/jfs6/g-xiedong/mmdu_val/images"
}
}
处理逻辑:
python展开代码# 如果jsonl中是相对路径
{"images": ["img1.jpg", "img2.jpg"]}
# 自动拼接为绝对路径
images = [
"/mnt/jfs6/g-xiedong/mmdu_val/images/img1.jpg",
"/mnt/jfs6/g-xiedong/mmdu_val/images/img2.jpg"
]
注意: 媒体文件本身不缓存,只有URL下载的资源会缓存。
yaml展开代码# qwen3_vl_8b_train_swanlab.yaml
load_from_cache_file: true # ✅ 启用数据预处理缓存
packing: true # ✅ 启用packing缓存
dataset_num_proc: 8 # 8进程并行处理
bash展开代码# 预处理缓存
/mnt/jfs6/g-xiedong/.cache/modelscope/datasets/map_cache/
└── <fingerprint>.arrow # 约几百MB到几GB
# Packing缓存 (如果使用Megatron packing)
/mnt/jfs6/g-xiedong/.cache/modelscope/tmp/mmdu_val/
├── data.idx
└── data-00000.bin
# 媒体文件 (直接访问,不缓存)
/mnt/jfs6/g-xiedong/mmdu_val/images/
└── *.jpg
展开代码1. 读取 /mnt/jfs6/g-xiedong/mmdu_val/dataset_info.json 2. 加载 mmdu_val 数据集 3. 检查缓存: ~/.cache/modelscope/datasets/map_cache/<hash>.arrow - 不存在 → 执行预处理 - 解析jsonl - 应用MessagesPreprocessor - 如果有mask_history_sample,拆分样本 - 拼接media_dir路径 - 写入.arrow缓存 4. 如果启用packing: - 检查 ~/.cache/modelscope/tmp/mmdu_val/data.idx - 不存在 → 执行packing - 计算样本长度 - 贪心打包 - 写入IndexedDataset 5. 训练使用缓存数据
展开代码1. 检查预处理缓存 → 存在,直接加载 2. 检查packing缓存 → 存在,直接加载 3. 立即开始训练 (跳过所有预处理)
bash展开代码# 清理所有数据缓存
rm -rf ~/.cache/modelscope/datasets/map_cache/*
# 清理packing缓存
rm -rf ~/.cache/modelscope/tmp/*
# 或设置环境变量后清理
rm -rf /mnt/jfs6/g-xiedong/.cache/modelscope/datasets/map_cache/*
展开代码原始数据 (jsonl) ↓ 预处理器 (MessagesPreprocessor) ↓ [mask_history_sample=true, max_human_steps=2] 样本拆分 (1个样本 → N个样本) ↓ 写入Arrow缓存 ↓ [load_from_cache_file=true] 从缓存加载 (已拆分的N个样本) ↓ [packing=true] Packing (打包成更少的序列) ↓ 写入IndexedDataset缓存 ↓ 训练
根据我添加的日志,你会看到:
展开代码[数据集注册] 数据集 mmdu_val 启用了mask_history_sample功能 [数据集注册] - mask_history_sample: True [数据集注册] - max_human_steps: 2 [数据集拆分] 预处理前数据集大小: 1000 个样本 [数据集拆分] 第一个样本拆分详情: [数据集拆分] 原始对话轮数: 5 轮 [数据集拆分] 将拆分为: 5 个训练样本 [数据集拆分] 拆分样本 #1: 2条消息 [数据集拆分] 拆分样本 #2: 4条消息 [数据集拆分] 拆分样本 #3: 4条消息 [数据集拆分] 预处理后数据集大小: 5000 个样本 [数据集拆分] 样本数量变化: 1000 -> 5000 (扩增5.00x) # 写入缓存: ~/.cache/modelscope/datasets/map_cache/abc123.arrow # 包含5000个已拆分的样本 # 下次训练直接从缓存加载5000个样本
bash展开代码# 查看缓存大小
du -sh ~/.cache/modelscope/datasets/map_cache/
du -sh ~/.cache/modelscope/tmp/
# 清理旧缓存
find ~/.cache/modelscope/datasets/map_cache/ -mtime +7 -delete
方法1: 修改配置
yaml展开代码load_from_cache_file: false
方法2: 删除缓存
bash展开代码rm -rf ~/.cache/modelscope/datasets/map_cache/*
✅ 安全! 缓存基于数据指纹(fingerprint),不同配置会生成不同缓存文件。
仅在启用 packing: true 且使用 Megatron 训练时生效。
❌ 不会。数据改变后需要手动清理缓存或设置 load_from_cache_file: false。
数据预处理缓存 在 ~/.cache/modelscope/datasets/map_cache/
Packing缓存 在 ~/.cache/modelscope/tmp/<dataset_name>/
媒体文件 直接访问,不缓存
mask_history_sample拆分 在预处理阶段完成
load_from_cache_file: true (加速启动)load_from_cache_file: false (实时看效果)生成时间: 2026-01-10
ms-swift 版本: 最新
文档作者: Claude (根据代码分析生成)


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!