MindSpore Transformers LLM数据预处理

1 阅读1分钟

​数据预处理是LLM训练与推理的核心前提,直接决定模型训练效果与推理精度。MindSpore Transformers作为昇思生态下的大模型开发套件,提供了便捷、高效的数据预处理接口,支持Hugging Face数据集、本地文本、MindRecord等多种数据格式,可快速完成数据加载、清洗、分词、格式转换、批量处理等全流程操作,适配Qwen、Llama、DeepSeek等主流LLM。MindSpore Transformers LLM数据预处理的核心流程与实操技巧,搭配完整可执行代码,覆盖预训练与微调两大场景,适配昇腾NPU、CPU、GPU多硬件平台,助力开发者高效完成数据预处理工作。

一、数据预处理核心逻辑与环境准备

LLM数据预处理的核心是将原始文本数据转换为模型可识别的张量格式,核心流程为:数据加载→数据清洗→分词编码→格式适配→批量处理→数据优化。MindSpore Transformers集成了Tokenizer分词工具、Dataset数据处理模块,可灵活适配不同场景需求,前期需完成环境搭建,代码如下:

# 1. 创建虚拟环境并激活
conda create -n ms-llm-preprocess python=3.8
conda activate ms-llm-preprocess

# 2. 安装核心依赖(适配多硬件,昇腾NPU为例)
pip install mindspore-npu==2.3.0 mindspore-transformers==1.8.0 datasets sentencepiece -i https://pypi.tuna.tsinghua.edu.cn/simple

# 3. 验证环境(确保模块正常导入)
python -c "import mindspore; import mindspore_transformers; import datasets; print('环境搭建成功')"

二、核心预处理流程及实操代码

结合LLM预训练与微调的不同需求,分别讲解数据预处理全流程,搭配可直接执行的代码,涵盖主流数据格式与处理技巧,同时融入MindSpore Dataset模块的性能优化特性。

2.1 微调场景数据预处理(指令集数据,以Alpaca为例)

微调场景多采用指令-响应对数据集,需进行格式构造、分词编码、长度截断与填充,代码如下,适配Qwen3-8B模型,兼顾数据质量与处理效率:

from mindspore_transformers import AutoTokenizer
from datasets import load_dataset
import mindspore.dataset as ds

# 1. 加载数据集(在线加载Alpaca指令集,简化版用于演示)
dataset = load_dataset("tatsu-lab/alpaca", split="train[:1000]")  # 取前1000条数据

# 2. 加载模型对应的Tokenizer(适配Qwen3-8B)
tokenizer = AutoTokenizer.from_pretrained("qwen3-8b")
tokenizer.pad_token = tokenizer.eos_token  # 配置pad_token,避免编码报错

# 3. 数据清洗(过滤无效数据,处理空值)
def clean_data(examples):
    # 过滤指令或输出为空的数据
    return {
        "instruction": [inst.strip() for inst in examples["instruction"] if inst.strip()],
        "input": [inp.strip() for inp in examples["input"]],
        "output": [out.strip() for out in examples["output"] if out.strip()]
    }

# 应用清洗函数,批量处理数据
dataset = dataset.map(clean_data, batched=True)

# 4. 分词编码(构造指令格式,转换为模型可识别的张量)
def preprocess_function(examples):
    # 构造指令-响应对格式(适配Qwen模型输入规范)
    texts = [
        f"### 指令: {inst}\n### 输入: {inp}\n### 输出: {out}"
        for inst, inp, out in zip(examples["instruction"], examples["input"], examples["output"])
    ]
    # 分词编码,设置最大长度,自动截断与填充
    return tokenizer(
        texts,
        truncation=True,
        max_length=512,
        padding="max_length",
        return_tensors="ms"  # 输出MindSpore张量,适配昇腾硬件
    )

# 批量预处理,启用多线程提升效率(根据硬件调整workers数量)
tokenized_dataset = dataset.map(
    preprocess_function,
    batched=True,
    num_parallel_workers=4  # 多线程处理,降低CPU占用
)

# 5. 格式转换与批量处理(适配MindSpore训练接口)
# 转换为MindSpore Dataset格式
ms_dataset = ds.GeneratorDataset(
    tokenized_dataset,
    column_names=["input_ids", "attention_mask"],
    shuffle=True  # 训练前打乱数据
)
# 批量处理,设置批次大小
ms_dataset = ms_dataset.batch(batch_size=8, drop_remainder=True)

# 验证预处理结果
for batch in ms_dataset.create_dict_iterator():
    print("输入张量形状:", batch["input_ids"].shape)  # 输出:(8, 512)
    print("注意力掩码形状:", batch["attention_mask"].shape)
    break

2.2 预训练场景数据预处理(无标注文本,以WikiText为例)

预训练场景需处理海量无标注文本,核心是文本拼接、分词编码、序列长度对齐,推荐使用Megatron格式或MindRecord格式提升加载效率,代码如下:

# 1. 下载预训练原始文本数据(WikiText简化版)
wget https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-2-v1.zip
unzip wikitext-2-v1.zip && cd wikitext-2

# 2. 文本数据预处理(拼接、去重、过滤)
cat wiki.train.tokens | grep -v "^=" | tr -s ' ' > clean_train.txt  # 过滤标题,去重空格

# 3. 转换为Megatron格式(适配MindSpore Transformers预训练)
# 克隆工具脚本
git clone https://gitee.com/mindspore/mindformers.git
cd mindformers

# 4. 执行预处理脚本,生成Megatron BIN格式数据集
python tools/dataset_preprocess/preprocess_indexed_dataset.py \
--input ../wikitext-2/clean_train.txt \
--tokenizer-type PretrainedFromHF \
--tokenizer-name-or-path qwen3-8b \
--output-prefix ../wikitext-2/wiki_megatron \
--max-seq-length 2048 \
--workers 8

# 5. 转换为MindRecord格式(提升大规模数据加载效率)
python tools/dataset_preprocess/llama/llama_preprocess.py \
--dataset_type wiki \
--input_glob ../wikitext-2/clean_train.txt \
--model_file ../qwen3-8b/tokenizer.model \
--seq_length 2048 \
--output_file ../wikitext-2/wiki_mindrecord

# 6. 加载MindRecord格式数据集(适配预训练)
import mindspore.dataset as ds
pretrain_dataset = ds.MindDataset(
    dataset_dir="../wikitext-2/wiki_mindrecord",
    shuffle=True,
    num_parallel_workers=8,
    prefetch_size=2  # 优化内存占用
)
pretrain_dataset = pretrain_dataset.batch(batch_size=4)

2.3 关键优化技巧(内存与性能优化)

针对大规模数据预处理的内存占用高、CPU占用异常等问题,结合MindSpore特性进行优化,代码如下,提升处理效率并降低硬件开销:

import mindspore.dataset as ds
import cv2
import os

# 1. 内存优化(降低预处理阶段内存占用)
ds.config.set_prefetch_size(2)  # 设置预取大小,减少内存占用
# 批量处理时减少并行线程数(针对内存不足场景)
tokenized_dataset = dataset.map(
    preprocess_function,
    batched=True,
    num_parallel_workers=1
)

# 2. CPU占用优化(解决多线程资源竞争问题)
# 若预处理包含cv2操作,设置cv2全局线程数
cv2.setNumThreads(2)
# 设置numpy线程数,避免资源竞争
os.environ["OPENBLAS_NUM_THREADS"] = "1"

# 3. 数据下沉模式(数据处理与模型训练并行,提升效率)
# 训练时启用数据下沉,构建Pipeline流水线
ms_dataset = ms_dataset.batch(batch_size=8, drop_remainder=True)
ms_dataset = ms_dataset.sink_mode(True)  # 启用数据下沉,减少数据传输耗时

# 4. 自定义预处理函数(适配特殊格式数据)
def custom_preprocess(text):
    # 自定义文本清洗逻辑(如去除特殊字符、统一大小写)
    text = text.replace("\n", " ").replace("\\", "").lower()
    # 分词编码
    return tokenizer(text, truncation=True, max_length=2048)

# 应用自定义函数
dataset = dataset.map(lambda x: custom_preprocess(x["text"]), batched=False)

三、预处理常见问题与解决方案

1. 分词报错“pad_token is None”:需手动配置tokenizer.pad_token = tokenizer.eos_token,确保pad_token存在;2. 内存溢出:减少batch_size、降低num_parallel_workers数量,启用prefetch_size优化,或采用MindRecord格式分块存储数据;3. 数据加载缓慢:使用Megatron或MindRecord二进制格式,启用多线程加载,减少数据IO耗时;4. 张量格式不匹配:确保分词时指定return_tensors="ms",输出MindSpore张量,适配昇腾NPU训练;5. CPU占用异常:合理设置第三方库线程数,避免多线程资源竞争。