数据集

查看源文件

目前MindSpore Transformers的预训练和微调支持多种格式的数据集加载能力,包括Megatron多源数据集、MindRecord数据集以及HuggingFace数据集的加载方式。每种格式的数据集的具体使用方法的参考如下。

Megatron多源数据集

Megatron多源数据集是指从多个不同来源收集的数据集,这些数据集可以包含不同的文本类型、格式和领域。使用多源数据集可以帮助模型学习到更广泛的语言特征和知识,从而提高模型的泛化能力和性能。Megatron框架目前实现的多源数据集,需要先将原数据集预处理成BIN格式的数据集。当前MindSpore Transformers已经原生适配了Megatron多源数据集,提供了制作BIN格式数据集的脚本,支持在训练任务中直接使用Megatron多源数据集。

制作 BIN 格式数据集

MindSpore Transformers 提供了一个预处理脚本 mindformers/tools/dataset_preprocess/preprocess_indexed_dataset.py 将文本数据转换成BIN格式数据集,该脚本当前仅支持处理特定形式的 JSON 格式的文件。用户需要先将原始数据集文件转换成特定形式的JSON格式的文件,再使用预处理脚本生成BIN格式的数据集文件。当前 MindSpore Transformers 中的一些模型已经提供了将特定开源数据集转换成特定形式 JSON 格式文件的脚本,用户如想使用自有数据集,则需要通过自行编写脚本的方式将其转换为所需形式。

所需的 JSON 格式文件内容的形式如下:

{"id": "0", "text": "The quick brown fox", "type": "Eng", "src": "www.nvidia.com", "title": "First Part"}
{"id": "1", "text": "jumps over the lazy dog", "type": "Eng", "src": "The Internet", "title": "Second Part"}
...

其中每条数据由若干键值对组成,支持的键及说明如下:

  • "id": 数据的编号,按顺序编号即可,必须存在

  • "text": 实际用作训练的文本数据,必须存在

  • "type": 注明语言类型,可选

  • "src":注明数据的来源,可选

  • "title":注明数据的标题,可选

下面以处理 Wiki 数据集并用作 Llama2 模型预训练为例,说明制作 BIN 格式数据集的详细步骤:

  1. 下载 Wiki 数据集

    原始 Wiki 数据集的下载参考 Llama2 数据集下载

  2. 生成 JSON 格式文件

    Wiki 数据集的原始格式如下:

    将 Wiki 数据集处理后的 JSON 文件 wiki.json 的格式如下 (省略长文本):

    {"id": 0, "text": "The gold dollar or gold one ..."}
    {"id": 1, "text": "Super Mario Land is a 1989 ..."}
    {"id": 2, "text": "The Sinclair Scientific Programmable ..."}
    ...
    
  3. 下载 Llama2 的词表文件

    预处理脚本中会把原始文本数据使用模型的分词器 Tokenizer 处理成 Tokens 的形式,因此需要提前下载词表文件。

    Llama2 词表文件的下载链接:tokenizer.model

  4. 使用预处理脚本生成 BIN 格式文件

    处理成上述这样特定的 JSON 格式的文件后,调用 mindformers/tools/dataset_preprocess/preprocess_indexed_dataset.py 将其转换成BIN格式的数据集,具体命令如下:

    python mindformers/tools/dataset_preprocess/preprocess_indexed_dataset.py \
    --input ./wiki.json \
    --output-prefix wiki_processed_1024 \
    --tokenizer-type LlamaTokenizer \
    --vocab-file ./tokenizer.model \
    --add_bos_token True \
    --add_eos_token True \
    --pad_or_stitch stitch \
    --seq-length 1024 \
    --workers 1
    

    配置参数说明:

    • --input: JSON 格式文件的路径

    • --output-prefix: 预处理后的输出文件的文件名前缀

    • --tokenizer-type: 模型对应的 tokenizer 的类型

    • --vocab-file: 模型分词器 Tokenizer 的词表文件路径

    • --add_bos_token: 是否在数据的首位置添加 bos_token,默认为 False

    • --add_eos_token: 是否在数据的末位置添加 eos_token,默认为 False

    • --pad_or_stitch: 根据训练任务的要求,设置是否拼接还是补齐,pad为补齐模式,该模式会将长度不足的数据补齐至seq-length长度;stitch为拼接模式,该模式会将多条数据拼接成长度为seq-length的数据

    • --seq-length: 预处理后每条数据长度

    • --workers: 预处理时并行 worker 的数量

执行以上命令之后,会得到两个文件,分别为 .bin.idx 格式的文件,其中 .bin 格式文件存储实际的数据,.idx 格式文件存储每条数据的索引。

在训练任务中使用多源数据集

按照如下方式在训练任务中使用Megatron多源数据集:

  1. 准备parallel_speed_up.json文件

    parallel_speed_up.json 是数据集并行通信配置文件,文件内容如下:

    {
        "dataset_broadcast_opt_level": 3
    }
    
  2. 设置环境变量

    在命令行输入如下命令设置环境变量:

    export MS_DEV_DYNAMIC_SINK1=False
    
  3. 修改训练任务的 YAML 配置文件

    在 YAML 配置文件中配置Megatron多源数据集的相关参数。此处,以 Llama2-7B 模型预训练任务来举例说明,修改 pretrain_llama2_7b.yaml 中的 train_datasetrunner_configparallel_configparallel 以及 context 配置项。具体修改及说明如下:

    train_dataset: &train_dataset
      data_loader:
        type: BlendedMegatronDatasetDataLoader
        datasets_type: "GPTDataset"
        sizes:
          - 1000
          - 0
          - 0
        shuffle: False
        input_columns: ["input_ids", "labels", "loss_mask", "position_ids"]
        config:
          seed: 1234
          seq_length: 1024
          split: "1, 0, 0"
          data_path:
            - 0.3
            - "/path/to/my_wiki_test_1024_text_document"
            - 0.7
            - "/path/to/my_wiki_test_1024_text_document"
          num_dataset_builder_threads: 1
          eod_mask_loss: False
          create_attention_mask: False
    

    其中:

    • data_loader.type:dataloader 的类型,需设置为 BlendedMegatronDatasetDataLoader

    • data_loader.datasets_type:数据集类型,当前仅支持 GPTDataset

    • data_loader.sizes:- 1000- 0- 0 分别为训练集、测试集以及验证集采样的大小,当前只支持配置训练集。

    • input_columns:设置训练数据集输入的数据列,一般配置为 ["input_ids", "labels", "loss_mask", "position_ids"]

    • data_loader.config.seed: 创建数据集时的随机数种子,默认值: 1234

    • data_loader.config.seq_length: 每条数据的长度,必须和 YAML 配置中的 model.model_config.seq_length 保持一致。

    • data_loader.config.split:分割字符串,用逗号分隔训练集、测试集以及验证集的比重,用于从单个分布中绘制样本时分割数据集,当前只支持配置为 "1, 0, 0"

    • data_loader.config.data_path:数字是每个数据集的比重,字符串是数据集 BIN 文件的路径,路径需要去掉文件格式后缀 .bin

    • data_loader.config.num_dataset_builder_threads:创建数据集时使用的进程数,默认值: 1

    • data_loader.config.eod_mask_loss:是否使用 eod mask 的开关,默认值: False

    • data_loader.config.create_attention_mask:是否构造 attention_mask,默认值:True

    当前多源数据集目前还存在限制,仅支持非 full batch 的场景,且不支持序列流水线并行特性,需要根据以下对相应配置项进行修改:

    runner_config:
        sink_mode: True
        sink_size: 1
    
    parallel_config:
        data_parallel: &dp 2
        model_parallel: 2
        pipeline_stage: 1
    
    parallel:
        full_batch: False
        dataset_strategy: [[*dp, 1], [*dp, 1], [*dp, 1], [*dp, 1]]
    
    context:
        ascend_config:
            parallel_speed_up_json_path: "/path/to/parallel_speed_up.json"
    

    需要注意的配置说明如下:

    • parallel.dataset_strategy:仅支持 List of List 类型,List中子List的个数需要等于 train_dataset.input_columns 的长度,并且 List 中的每个子 List 需要和数据集返回的数据的shape保持一致。一般在数据的第1维进行数据并行切分,所以子List的第1位数配置成 *dp ,其他位配置为 1 。具体原理可以参考数据集切分

  4. 编译 Megatron 数据集模块

    MindSpore Transformers 内置了 Megatron 的数据集模块代码,需要在启动训练任务之前执行如下命令进行编译:

    pip install pybind11
    cd mindformers/dataset/blended_datasets
    make
    

MindRecord 数据集

MindRecord 是由 MindSpore 开发的一种高效数据格式,用于存储机器学习或深度学习的数据集。

MindRecord 格式旨在提高数据处理效率,尤其是在大规模数据训练场景下,可以更快地加载和处理数据。 MindRecord 文件通常包含了模型训练所需的输入样本,这些样本经过预处理(如编码、归一化等),以优化读取速度和内存使用。

更多关于 MindRecord 相关接口的实现及案例,请参考 MindSpore 中关于 《MindRecord》 的相关文档

如何制作 MindRecord 数据集

MindRecord 模块提供了一些方法帮助用户将不同数据集转换为 MindRecord 格式, 用户可以使用由 MindSpore 提供的 FileWriter 接口生成 MindRecord 格式数据集。

下面将以 Llama2 为例,提供一个基于 json 格式文件制作 MindRecord 数据集的案例:

  1. 准备 json 文件;

    准备类似这样的 json 文件,命名为 mydata.json

    [
       {
         "text": "I love Beijing, because it is a city that beautifully blends rich history with modern vibrancy."
       },
       {
         "text": "I love Hangzhou, because it is a city that seamlessly combines natural beauty with rich cultural heritage."
       }
    ]
    
  2. 读取 json 文件;

    import json
    
    raw_data = None
    file = open("mydata.json", "r")  # 打开 json 文件
    if file is not None:
       raw_data = json.load(file)  # 读取 json 文件到 raw_data 中
       file.close()
    
  3. 定义一个 MindRecord 的 schema ,并创建一个 FileWriter 对象;

    from mindspore.mindrecord import FileWriter
    
    # 定义一个 MindRecord 的 schema
    schema = {'input_ids': {"type": "int32", "shape": [-1]}}
    # 创建一个 FileWriter 对象
    writer = FileWriter(file_name="output_file", shard_num=1)
    writer.add_schema(schema, "dataset_type")
    
  4. 遍历处理 json 文件中的每一条数据,将其转换为 MindRecord 格式,并写入 MindRecord 文件中。

    词表下载链接: tokenizer.model

    import numpy as np
    from mindformers import LlamaTokenizer
    
    def tokenize_json(tokenizer, raw_data):
        """tokenize json file dataset"""
        content = [] # 读取每个 json 数据,获取其 "input_ids"
        for line in raw_data:
            stripped_line = line['text'].strip()
            if stripped_line:
                line_ids = tokenizer(stripped_line)["input_ids"]
                content.append(line_ids)
    
        for ids in content:
            sample = {}
            sample['input_ids'] = np.array(ids, dtype=np.int32)
            yield sample
    
    # 将文本数据分词
    word_tokenizer = LlamaTokenizer(vocab_file=r"tokenizer.model")
    
    # 遍历处理 json 文件中的每一条数据,将其转化为 MindRecord 格式后写入 MindRecord 文件
    # tokenize_json 为自定义的对 json 中数据进行分词的方法
    for x in tokenize_json(word_tokenizer, raw_data):
        writer.write_raw_data([x])
    writer.commit()
    

详细案例可以参考 Llama2 中的数据预处理案例

在任务中使用 MindRecord 格式数据集

通过在 yaml 配置文件中配置数据集相关参数,可以让训练或评测任务使用准备好的 MindRecord 格式数据集。

此处,以 Llama2-7B 模型预训练任务来举例说明,在 pretrain_llama2_7b.yaml 文件 中的默认配置参数及说明如下:

# dataset
train_dataset: &train_dataset
  data_loader:
    type: MindDataset
    dataset_dir: ""
    shuffle: True
  input_columns: ["input_ids"]
  num_parallel_workers: 8
  python_multiprocessing: False
  drop_remainder: True
  batch_size: 6
  repeat: 1
  numa_enable: False
  prefetch_size: 1

train_dataset_task:
  type: CausalLanguageModelDataset
  dataset_config: *train_dataset

配置如下参数以使用 MindRecord 格式数据集:

  • data_loader.type:dataloader 的类型,此处需要设置为 MindDataset

  • data_loader.dataset_dir:数据集文件路径。

  • input_columns:设置训练数据集输入的数据列。当前为预训练场景,设置为 ["input_ids"]

其余参数介绍可以参考 配置文件说明 的 “模型训练配置” 和 “模型评估配置”。

HuggingFace数据集

目前数据集加载功能已接入 魔乐开源社区HuggingFace社区,并支持数据集在线加载与预处理,同时还可对数据集进行packing,提升模型训练效率。

使用说明

HuggingFace数据集可实现HuggingFace社区以及魔乐开源社区中的数据集在线、离线加载,下面主要针对环境准备、数据集加载流程、以及在如何在配置文件中配置使用HuggingFace数据集功能进行介绍。

对接开源社区

  • 对接HuggingFace社区

    如果需要使用HuggingFace社区中的数据集需要执行如下步骤:

    1. 环境准备

      环境变量 HF_ENDPOINT 可以控制开源社区huggingFace实际使用的远程仓库,未配置时默认为 https://huggingFace.co , 针对国内环境,需要配置成镜像地址 export HF_ENDPOINT=https://hf-mirror.com

    2. 安装依赖

      pip install datasets
      
  • 对接魔乐开源社区

    如果需要使用魔乐开源社区中的数据集需要执行如下步骤:

    1. 环境准备

      环境变量 OPENMIND_HUB_ENDPOINT 可以控制魔乐开源社区实际使用的远程仓库, 未配置时默认为 export OPENMIND_HUB_ENDPOINT=https://telecom.openmind.cn

    2. 安装依赖

      git clone https://gitee.com/openmind-ai/openmind-hub.git
      cd openmind-hub
      pip install -e .
      cd ..
      git clone https://gitee.com/foundation-models/openmind-datasets.git
      cd openmind-datasets
      pip install -e .
      cd ..
      

当环境安装了 openmind-datasets 三方件时,默认对接的是魔乐开源社区,如果这是想对接 HuggingFace,环境变量 USE_OM 可以控制具体对接哪个社区,默认值为 ON 为魔乐社区,修改为 OFF 对接 HuggingFace 社区

数据集加载流程

commondataloader.png

在线数据集加载与处理功能主要通过CommonDataLoader实现,其中数据加载部分可通过配置文件进行自定义配置,具体配置内容可参考dataloader参数说明,在线加载模块需要用户针对不同数据集进行自定义实现,如通过AlpacaInstructDataHandler类可实现对alpaca数据集进行预处理,具体实现过程可参考自定义数据handler

dataloader参数说明

在线数据集加载功能通过在配置文件中对data_loader进行配置来使能,下面是在线数据集加载相关配置的示例:

train_dataset:
  input_columns: &input_columns ["input_ids", "labels", "loss_mask", "position_ids", "attention_mask"]
  construct_args_key: *input_columns
  data_loader:
    type: CommonDataLoader
    load_func: 'load_dataset'
    shuffle: False
    split: "train"
    path: "llm-wizard/alpaca-gpt4-data"
    is_dynamic: False
    packing: pack
    handler:
      - type: AlpacaInstructDataHandler
        tokenizer_name: llama2_7b
        seq_length: 4096
        prompt_key: "conversations"
        output_columns: ["input_ids", "labels"]
      - type: PackingHandler
        seq_length: 4096
        output_columns: ["input_ids", "labels", "actual_seq_len"]
    adaptor_config:
       compress_mask: False
    column_names: *input_columns

其中data_loader中相关参数说明如下:

参数名

概述

类型

type

固定为CommonDataLoader,该模块支持HuggingFace以及魔乐开源社区的数据集加载功能

str

packing

使用handler处理数据集时packing配置项,可选值为packtruncate

str

load_func

加载数据集调用接口名,可选值为load_datasetload_from_disk,读取通过save_to_disk接口保存的数据使用load_from_disk,其他场景使用load_dataset,默认值为load_dataset

str

path

load_func=load_dataset时,该参数含义与datasets.load_dataset中接口相同,在load_func=load_from_disk时,该参数为加载数据集路径

str

data_files

load_func=load_dataset时,该参数含义与datasets.load_dataset中接口相同,在load_func=load_from_disk时不生效

str

handler

可配置多个handler,按配置顺序对加载后的数据集进行预处理,handler配置说明参考自定义数据handler中的handler参数说明

list

adaptor_config

在模型训练过程中数据集的相关配置,当前支持设置compress_mask,在设置packing时生效,开启后返回压缩后的数据掩码,默认为False

dict

shuffle

是否在读取数据集时开启随机采样

bool

column_names

设置数据集返回的列名,不指定时返回所有列

list

is_dynamic

设置数据集返回动态长度的数据,默认为False

bool

除了以上配置外,datasets.load_dataset接口中的所有配置均已支持,且参数含义与功能相同。

数据集在配置packing之后返回actual_seq_len数据列,其含义可参考文档actual_seq_qlen以及ctual_seq_kvlen参数介绍。

功能介绍

动态序列长度微调

CommonDataLoader支持加载HuggingFace数据集进行动态shape微调,HuggingFace数据集加载分为在线加载和离线加载,下面以alpaca数据集为例介绍如何配置动态shape微调。

  • 在线加载

    在线数据名称为llm-wizard/alpaca-gpt4-data,可在HuggingFace官网搜索名称进行下载或使用在线名称进行加载;

    在线加载配置文件示例:

     train_dataset:
       input_columns: &input_columns ["input_ids", "labels"]
       dynamic_batch: True                    # 开启动态shape
       divisor: 32                            # 配置divisor和remainder后,动态shape中seq_length会成为divisor的倍数以及remainder的和
       remainder: 1
       data_loader:
         type: CommonDataLoader
         shuffle: True
         split: "train"                       # 在线数据集子集名称
         path: "llm-wizard/alpaca-gpt4-data"  # 在线数据集名称
         is_dynamic: True
         handler:
           - type: AlpacaInstructDataHandler
             tokenizer_name: llama2_7b
             seq_length: 4096
             prompt_key: "conversations"
             output_columns: *input_columns
       seed: 0
       num_parallel_workers: 8
       python_multiprocessing: False
       drop_remainder: True
       repeat: 1
       numa_enable: False
       prefetch_size: 1
    
    1. train_dataset中参数说明可参考文档

    2. AlpacaInstructDataHandler是针对alpaca数据集开发的在线处理脚本,如果使用其他数据集,用户需要参考自定义数据handler完成自定义数据处理的功能实现。

  • 离线加载

    离线加载需要准备好alpaca数据集中的json文件,离线配置与在线配置仅如下配置项不同。

     train_dataset:
       data_loader:
         path: "json"                               # load_dataset接口加载文件格式
         data_files: '/path/alpaca_gpt4_data.json'  # alpaca数据集文件路径
    

配置完数据集加载方式之后,还需要在模型配置中修改is_dynamic=True来开启模型动态shape训练。

model_config:
  is_dynamic: True

由于动态shape会存在算子编译缓存,当运行环境内存有限时,推荐配置如下环境变量来限制编译缓存的数量,避免出现内存不足的问题:

export ACLNN_CACHE_LIMIT=10
export MS_DEV_RUNTIME_CONF="aclnn_cache_queue_length:64"
  • ACLNN_CACHE_LIMIT参数说明参考文档

  • MS_DEV_RUNTIME_CONF是MindSpore中设置算子缓存序列长度的参数,其中64代表该序列的长度,默认为1024,可根据实际环境进行调整,数值设置过小可能会影响模型训练性能。

完成以上所有配置后,即可参考具体使用的模型文档进行动态shape微调。

自定义数据handler

用户可以使用自定义数据 handler 逻辑,对加载到的数据集进行各种数据预处理定制逻辑。

  • handler参数说明

参数名

概述

类型

type

自定义数据 handler 名称,自定义handler必须继承BaseInstructDataHandler

str

tokenizer_name

使用的 tokenizer 分词器名称

str

tokenizer

tokenizer 相关配置参数, 可以是字典或者字符串,也可以直接配置tokenizer对象,优先级低于tokenizer_name

dict/str

seq_length

处理序列的最大长度,通常与模型的序列长度相同

int

output_columns

数据预处理后返回的数据列名

list

prompt_key

增加 prompt 处理后数据的列名

str

  • 开发样例一

自定义数据 handler 一般放在 mindformers/dataset/handler 目录下,自定义的需要继承抽象基类 BaseInstructDataHandler , 需要实现 format_functokenize_func 两个方法,该方法是对加载到的每条数据进行预处理,可以参考 alpaca_handler.py

@MindFormerRegister.register(MindFormerModuleType.DATA_HANDLER)
class XXXInstructDataHandler(BaseInstructDataHandler):

    def format_func(self, example):
        # 自定义数据格式转换

    def tokenize_func(self, example):
        # 自定义tokenizer分词处理

BaseInstructDataHandler 默认提供的实现了入口 handler 方法,用于遍历每条数据进行数据的预处理, format_func 用于实现如何从原始数据中转换成所需要的数据格式,而 tokenize_func 方法用于把处理后的数据进行按自定义分词, 实例里的入参 example 为获取到的每一条样本数据。

  • 开发样例二

若用户想直接对于整个 dataset 进行数据处理,而不是每条数据分批处理的话,可以在自定义 handler 实现入口 handle 方法,得到的就是完整的 dataset,参考如下:

    def handle(self, dataset):
        """data handler"""
        return dataset.rename_columns({"content":"prompt","summary":"answer"})
  • alpaca 数据集示例

修改任务配置文件 finetune_llama2_7b.yaml

修改如下参数:

train_dataset:
  input_columns: &input_columns ["input_ids", "labels"]
  data_loader:
    type: CommonDataLoader
    shuffle: True
    split: "train"
    path: "llm-wizard/alpaca-gpt4-data"
    handler:
      - type: AlpacaInstructDataHandler
        tokenizer_name: llama2_7b
        seq_length: 4096
        prompt_key: "conversations"
        output_columns: *input_columns

其余参数介绍可以参考 配置文件说明 的 “模型训练配置” 和 “模型评估配置”。

自定义数据 handler:

@MindFormerRegister.register(MindFormerModuleType.DATA_HANDLER)
class AlpacaInstructDataHandler(BaseInstructDataHandler):

    def format_func(self, example):
        """format func"""
        source = PROMPT_INPUT.format_map(example) \
            if example.get(self.input_key, "") != "" \
            else PROMPT_NO_INPUT.format_map(example)
        target = example.get(self.output_key)
        formatted_example = [
            {
                "from": self.user_role,
                "value": source,
            },
            {
                "from": self.assistant_role,
                "value": target,
            },
        ]

        return formatted_example

    def tokenize_func(self, messages):
        """tokenize func"""
        conversation = self.gen_prompt(messages)
        sep = self.template.sep + self.assistant_role + ": "
        # Tokenize conversations
        rounds = conversation.split(self.template.sep2)
        ids = [self.tokenizer.bos_token_id]
        mask = [1]
        for _, rou in enumerate(rounds):
            if rou == "":
                break
            conv_out = self.tokenizer(rou)
            ids.extend(conv_out['input_ids'][1:])
            mask.extend(conv_out['attention_mask'][1:])
        d = {'input_ids': ids, 'attention_mask': mask}
        # pylint: disable=W0212
        if not self.dynamic:
            d = self.tokenizer._pad(d, max_length=self.seq_length + 1, padding_strategy='max_length')
        input_id = d['input_ids'][:self.seq_length + 1]
        target = np.array(d['input_ids'])
        total_len = int(np.not_equal(target, self.tokenizer.pad_token_id).sum())
        cur_len = 1
        target[:cur_len] = self.ignore_token_id
        for _, rou in enumerate(rounds):
            if rou == "":
                break
            parts = rou.split(sep)
            if len(parts) != 2:
                break
            parts[0] += sep
            round_len = len(self.tokenizer(rou)['input_ids']) - 1
            instruction_len = len(self.tokenizer(parts[0])['input_ids']) - 3

            target[cur_len: cur_len + instruction_len] = self.ignore_token_id

            cur_len += round_len
        if self.dynamic:
            return {
                "input_ids": input_id,
                "labels": target[:len(input_id)].tolist()
            }
        target[cur_len:] = self.ignore_token_id
        if cur_len < self.seq_length + 1:
            if cur_len != total_len:
                target[:] = self.ignore_token_id
        else:
            target = target[:self.seq_length + 1]
        label = target.tolist()
        return {
            "input_ids": input_id,
            "labels": label,
        }
  • ADGEN 数据集示例

修改任务配置文件 run_glm3_6b_finetune_2k_800T_A2_64G.yaml

修改如下参数:

train_dataset: &train_dataset
  data_loader:
    type: CommonDataLoader
    path: "xxx/ADGEN"
    split: "train"
    shuffle: True
    handler:
      - type: AdgenInstructDataHandler
        output_columns: ["prompt", "answer"]
  tokenizer:
    type: ChatGLM3Tokenizer
    vocab_file: "/path/to/tokenizer.model"
  input_columns: ["input_ids", "labels"]
  max_source_length: 1024
  max_target_length: 1023
  ignore_pad_token_for_loss: True
  num_parallel_workers: 8
  python_multiprocessing: False
  drop_remainder: True
  batch_size: 8
  repeat: 1
  numa_enable: False
  prefetch_size: 1
  phase: "train"
  version: 3
  seed: 0

其余参数介绍可以参考 配置文件说明 的 “模型训练配置” 和 “模型评估配置”。

自定义 adgen_handler:

@MindFormerRegister.register(MindFormerModuleType.DATA_HANDLER)
class AdgenInstructDataHandler(BaseInstructDataHandler):
    """agden data handler"""
    def handle(self, dataset):
        """data handler"""
        return dataset.rename_columns({"content": "prompt", "summary": "answer"})

数据集packing

CommonDataLoader中配置PackingHandler可以实现对数据进行packing处理,目前需要在前置处理中将原始数据处理为可输入模型的input_ids以及labels

  • 参数说明

参数名

概述

类型

type

固定为PackingHandler,该模块支持对数据进行packing,在dataloader中配置packing=packpacking=truncate时,分别对数据进行非截断和截断的拼接

str

seq_length

packing处理后数据的最大序列长度

int

pad_token

当packing后样本未达到最大长度时,对input_ids填充使用的token id,默认值为0

int

ignore_token

当packing后样本未达到最大长度时,对labels填充使用的token id,默认值为-100

int

  • packing示例

按照如下配置,对alpaca数据集进行预处理,即可实现在线packing。

train_dataset:
  input_columns: &input_columns ["input_ids", "labels", "loss_mask", "position_ids", "attention_mask"]
  construct_args_key: *input_columns
  data_loader:
    type: CommonDataLoader
    shuffle: False
    split: "train"
    path: "llm-wizard/alpaca-gpt4-data"
    packing: pack
    handler:
      - type: AlpacaInstructDataHandler
        tokenizer_name: llama2_7b
        seq_length: 4096
        prompt_key: "conversations"
        output_columns: ["input_ids", "labels"]
      - type: PackingHandler
        seq_length: 4096
        output_columns: ["input_ids", "labels", "actual_seq_len"]
    adaptor_config:
       compress_mask: False

使用上述配置文件处理alpaca数据集,会执行如下流程:

  1. 使用AlpacaInstructDataHandler以及llama2_7btokenizer将原始文本数据处理为input_idslabels

  2. 使用PackingHandler对处理后的input_idslabels进行packing处理,得到拼接到seq_length长度的input_idslabels, actual_seq_len拼接后样本中每个子样本的序列长度,在训练中会根据这个参数生成对应的数据掩码;

  3. 如果在adaptor_config中设置compress_mask=False表示训练时返回完整的数据掩码,否则返回actual_seq_len

数据集离线处理

CommonDataLoader除了支持数据集在线加载与处理,还支持离线处理数据集并进行保存。

使用datasets_preprocess.py脚本可以离线处理 HuggingFace 数据集并进行保存。

  • 参数说明

参数名

概述

类型

config

离线处理数据的配置文件,与在线处理使用方法相同,具体参考dataloader

str

save_path

数据集经过预处理后的保存路径

str

register_path

模型API的注册路径,其中包含模型相关Python文件,通常是research目录下模型文件夹的路径

int

  • 使用示例

使用数据集packing中提供的packing示例的配置文件即可,执行如下命令。

python toolkit/data_preprocess/huggingface/datasets_preprocess.py \
  --config data_process.yaml \
  --save_path /path/processed_data

如果需要加载保存后的数据集,需要对yaml进行如下修改:

train_dataset:
  input_columns: &input_columns ["input_ids", "labels", "loss_mask", "position_ids", "attention_mask"]
  construct_args_key: *input_columns
  data_loader:
    type: CommonDataLoader
    shuffle: False
    load_func: "load_from_disk"
    path: "/path/processed_data"
    adaptor_config:
       compress_mask: False