数据处理
使用方式
支持的本地数据格式:json、jsonl、parquet、txt、csv。
运行脚本tools/preprocess_data.py。
以下例子进行说明
huggingface上有完整数据:(比如THUCNews)
运行脚本:
python tools/preprocess_data.py \
--input /your/path/to/cnews.train.txt \
--output-prefix thucnews \
--dataset-impl mmap \
--tokenizer-type GPT2BPETokenizer \
--merge-file /your/path/to/gpt2-merges.txt \
--vocab /your/path/to/gpt2-vocab.json \
--append-eod \
--workers 2
huggingface仅提供数据解析脚本:(比如wiki)
huggingface上没有wiki的完整数据,只有一个运行脚本,该运行脚本会根据用户传入的参数在线下载,或读取本地路径的数据。此时需要配置参数:
hf_config_json="./hf_ds_json.json"
cat <<EOT > $hf_config_json
{
"path": "wikipedia",
"name": "20220301.en"
}
EOT
运行脚本:
python tools/preprocess_data.py \
--input /home/to/data/wikipedia \
--output-prefix wikipedia \
--hf-datasets-params ${hf_config_json} \
--dataset-impl mmap \
--tokenizer-type GPT2BPETokenizer \
--merge-file /your/path/to/gpt2-merges.txt \
--vocab /your/path/to/gpt2-vocab.json \
--append-eod \
--workers 2
微调数据制作:(比如alpaca)
获取数据集:
wget https://huggingface.co/datasets/c-s-ale/alpaca-gpt4-data-zh/tree/main
运行脚本:
python tools/preprocess_data.py \
--input /your/path/to/alpaca_cn/data \
--handler-name GeneralInstructionHandler \
--output-prefix alpaca_cn \
--dataset-impl mmap \
--tokenizer-type PretrainedFromHF \
--tokenizer-name-or-path your/path/to/llama_model \
--tokenizer-not-use-fast \
--append-eod \
--workers 8
主要参数说明:
- --input:文件路径,如/your/path/to/data.json或者数据文件夹/your/path/to/data。
- --handler-name:数据处理类,默认使用:GeneralPretrainHandler(适用于处理预训练数据), 其余可选GeneralInstructionHandler(适用于处理alpaca等指令微调数据集)、BelleMultiTurnInstructionHandler(用于处理BelleMultiTurn微调数据集)。
- --json-keys:预训练数据的要处理的数据key值。
- --split-sentences:是否对文档进行句子切分,默认不处理。
- --tokenizer-type:tokenizer的类型,可选 BERT、GPT2或者PretrainedFromHF加载huggingface预训练tokenizer。
- --tokenizer-name-or-path:tokenizer路径,当指定了从huggingface加载tokenizer时生效。
- --append-eod:是否在文档末尾添加eod token符号。
- --vocab-file:词表文件,不使用huggingface预训练tokenizer时需指定。
- --merge-file:使用GPT2 tokenizer时需指定。
- --dataset-impl:数据序列化方式,一般采用mmap。
概述
针对huggingface公开数据集,进行的数据预处理流程如下:
- 数据加载:支持本地加载数据集或者从huggingface上进行数据的加载。raw_datasets的加载统一使用如下的格式进行:
raw_datasets = load_dataset( args.input, split=split_flag, num_proc=None if args.streaming else args.workers, cache_dir=cache_dir, streaming=args.streaming )如果是从本地上进行数据的加载,还需要判断数据的格式(支持的是json还是txt)并且对数据进行相应的filter处理,之后再进行load_dataset生成raw_dataset:data_files = [args.input] if os.path.isfile(args.input) else \ glob.glob(os.path.join(args.input, '*')) ext, data_format = _get_data_format(data_files) filtered_data_files = list(filter(lambda x: x.split('.')[-1] == ext, data_files)) - Prompt数据处理:不同类型的数据集需要进行不同的处理,比如Prompt数据,需要在文本内容中增加一些指令和标签。代码发布的时候,会注册常用数据的处理方法,同时也支持注册自定义处理方法。针对Prompt的制作也会提供相应的模板,以下以alpaca数据集进行举例:
class AlpacaTemplate: system_token = "" user_token = "### Instruction:" assistant_token = "### Response:" end_token = "" system = "Below is an instruction that describes a task, paired with an input that provides further context. " "Write a response that appropriately completes the request. " "Please note that you need to think through your response logically and step by step."代码实现主要体现在以下过程:def generate_training_prompt(self, messages) -> str: prompt = self.template.system_token + "\n" + self.template.system + self.template.end_token + "\n" for message in messages: if message["role"] == self.user_role: prompt += self.template.user_token + "\n" + message["content"] + self.template.end_token + "\n" else: prompt += self.template.assistant_token + "\n" + message["content"] \ + self.template.end_token + "\n" return prompt最终呈现的prompt的形式是:instruction+content+end_token的结构。
- tokenizer id化:将处理后的文本id化,用于输入模型。id化中使用的tokenizer也会进行更新,兼容huggingface模型库上的tokenizer,与开源保持一致。
def get_tokenized_data(self): """get tokenized(and prompted) data""" columns = next(iter(self.raw_datasets)).keys() remove_columns = list(set(columns) - set(self.args.json_keys)) proc_kwargs = {} if self.args.streaming else {"num_proc": self.args.workers} return self.raw_datasets.map(self._filter, remove_columns=remove_columns, **proc_kwargs) - 数据dump:将数据落盘,预训练或者微调可以直接加载数据。需要考虑序列化后数据大小和数据加载的速度不产生明显劣化,特别是数据加载过程。
父主题: 解决方案