总览
高质量的训练数据对于提升模型精调效果至关重要。为了帮助用户快速准备训练数据,TI 平台将内部研发所采用的标准数据准备流程沉淀到了 TI 平台“数据中心/数据构建”模块。
本文以简单的原始数据样本为例,详细展示如何使用此模块来生成适用于大模型精调的数据集。
前置要求
物料准备
为了执行“数据构建”流程,您需要准备好如下物料:
原始数据集:请确保您已经将原始数据集下载至本地,或者您具有可访问原始数据集的具体链接;本文假设您使用的是平台提供的样例数据: dataset_preparation_demo.json。
[数据构建代码]:如您没有特殊需求,您可以直接使用平台内置的数据构建代码,只需要按照您的数据集格式,修改示例代码中的某些字段即可;如内置数据构建代码不能满足您的需求,您也可以自行准备构建代码。
如何准备原始训练数据
明确业务诉求
用户需要根据自己的目标或业务需求来准备自己的数据集。具体就是要规范需求中所期望的问题和答案。然后围绕这样的需求,大批量准备训练数据。一般来说,针对某一种特定的任务场景,准备几千条高质量精调数据即可让大模型学会这项能力,发挥出良好的效果。通常情况下,使用具有强烈业务属性的数据集在开源基座模型上进行精调,能够比较显著地提升模型在业务上的能力。
用户也可以使用主流的大模型,对自己所构造的问题进行批量测试,来确定该任务场景是否现有大模型已经做得足够好了,甚至比自己准备的数据集中的回答还要出色。如果出现这样的情况,则需要进一步提升自己数据集的质量。
明确高质量训练数据的标准
1. 数据集的问答需要满足自己的需求(例如回答的准确性,风格,在某些场景下满足某些要求等),并且答案是绝对正确的,且表达方式尽可能优化到极致:这是因为用户的数据集是用来解决实际问题,并且这些数据是大模型学习过程中的重要依据。大模型会很大程度地去理解用户数据集的回答以及表达风格,并在学习中进行快速地适配。因此一旦用户的数据存在瑕疵,大模型也会把这些瑕疵学到,从而影响最终的效果。
2. 数据集的指令需要多样化。以避免大模型产生对某些短语的过拟合,而忽略了自然语言的实际含义。例如对于一个阅读理解数据集,用户只设计了一种指令“根据以下已知内容,请回答问题并说明原因。已知内容:xxxxx。问题:xxxx”。大模型经过这个数据的精调后很有可能会出现这样的情况,大模型一旦看到“根据以下已知内容”这个短语作为输入,他就自然而然地在回答问题的同时说明原因。因为大模型通过这批数据的学习,很有可能错误地认为“根据以下已知内容”与“回答时要说明原因”是等价的。这样如果用户输入“根据以下已知内容,请回答问题,要求只回复答案,不要做其他解释。已知内容:xxxxx。问题:xxxx”,大模型还是会回复原因。这种针对指令的过拟合现象是需要去避免的,解决办法就是扩充数据集的指令集。
构建流程
新建数据构建任务
请根据您的业务场景,选择数据构建 pipeline;每一套数据构建 pipeline 都对应一套标准化数据处理流程,您可以按需选择。


本文假定您选择了 "有监督-单轮问答-pipeline" 。
任务创建完成之后,单击“跳转至对应开发机”即可开始创建(首次创建)或者跳转至数据构建开发机。
关于“通用算法任务”
为了减少您筹备数据集的时间,同时帮助您提升精调效果,平台内置了一些具备知识产权的私有数据集,您可以依据您的业务场景按需使用。
请特别注意: 此部分内置数据,不会参与到本文提及的数据构建流程,但是在您后续使用“大模型精调”模块精调大模型时,平台将在创建训练任务的过程中将您选择的具体业务场景对应的内置数据集按一定比例嵌入您的精调数据集之中,以提升精调效果。
如您不需要平台内置数据集,您只要不选择“通用算法任务”中的任何业务场景即可。
新建数据构建开发机
首次单击“跳转至对应开发机”按钮时,将会触发创建开发机流程;
由于平台内置数据构建流程涉及模型调用(需要 CPU 和内存),此外,当前版本的数据构建流程代码里,需要一次性将原始数据读入内存并执行后续处理过程,因此需要您预留好充足的算力规格;本文以 8C16G 为例,您可以结合原始数据集大小动态调整,但是建议您使用不少于 4C8G 的算力资源执行后续流程。
在创建开发机时,您还需要指定 CFS 信息以存放原始数据集,中间结果以及处理后的结果。本文假定您将如下 CFS 目录挂载至
/home/tione/notebook,挂载的原始cfs路径为:/data/custom/prepare


等待开发机创建完成后,您便可以真正开始数据构建流程。
上传原始数据集
此外,由于平台内置的数据处理 PPL 依赖您将文件放入指定目录,因此建议您将原始数据集上传至如下目录:
开发机:
/home/tione/notebook/<nb-id>/single_round_qa_pipeline/raw_dataset_files
也就是如下的 cfs 目录:
cfs:
/data/custom/prepare/<nb-id>/single_round_qa_pipeline/raw_dataset_files
其中:
-
nb-id
字段代表的是您创建的开发机示例的 ID;您可以在浏览器url输入栏看到当前开发机实例的 ID;

-
single_round_qa_pipeline
是有监督单轮问答的脚本路径,如果您选择的是有监督多轮问答pipeline,该目录名为multi_round_qa_pipeline
;如果您选择的是无监督-pipeline,该目录名为unsupervised_pipeline
;
关于原始数据集格式
有监督数据格式
我们的有监督数据构建脚本代码支持了丰富的大模型常见的数据格式,有监督单轮问答 pipeline 和有监督多轮问答 pipeline 目前支持如下格式:
1. json 文件:json 内容是一个数组,数组中每一项是一个有效的 json 对象,可以转换成单轮问答数据;如果 json 内容不是数组,而是一个 json 对象,我们会解析成长度为1个元素的数组来进行处理;
2. jsonline 文件:每一行是一个有效的 json 对象,可以转换成有监督问答数据;
3. parquet 文件:parquet 列式存储格式是开源数据常见格式(Parquet 文档)。我们会先把 parquet 对象转成 json 对象,您可在下述采样过程中预览转换后的json格式,再进行数据处理;
4. 数据集文件夹:文件夹中包含若干有效的数据文件(格式可以是 json/jsonline/parquet),此时我们会把该文件夹当做一个数据集进行处理,数据集名称即为文件夹名称,在后续数据解析流程完成后,会把所有文件的内容全部合并后再执行后续流程。
单轮有监督:示例代码提供的原始数据集文件格式为 jsonl,示例内容如下:
{"instruction": "请简要回答下面的问题:", "input": "您平时用什么投资理财方式?", "output": "我一般采用银行储蓄,相对风险较低。"}{"instruction": "请简要回答下面的问题:", "input": "基金拆分是什么意思?", "output": "基金拆分是保持基金投资人资产总值不变的前提下,改变基金份额净值和基金总份额的对应关系,重新计算基金资产的一种方式。"}
多轮有监督:示例代码提供的原始数据集文件格式为 jsonl,示例内容如下:
{"conversations": [{"from": "human", "value": "保险是什么,可靠么?"}, {"from": "model", "value": "保险,是指投保人根据合同约定,向保险人支付保险费,保险人对于合同约定的可能发生的事故因其发生所造成的财产损失承担赔偿保险金责任,或者被保险人死亡、伤残、疾病或者达到合同约定的年龄、期限等条件时承担给付保险金责任的商业保险行为。正规渠道购买的保险都是安全可靠的。"}, {"from": "human", "value": "我想买一些投资理财类的保险,有哪些险种?"}, {"from": "model", "value": "年金保险、分红险、投连险等。"}, {"from": "human", "value": "这些投资理财类保险是不是稳赚不赔的?"}, {"from": "model", "value": "不是,收益受到市场因素影响。"}]}{"conversations": [{"from": "human", "value": "我妈妈最近想买一份大病保险,这个是骗人的么?"}, {"from": "model", "value": "不是,重大疾病保险,它是一种针对严重疾病进行保障的保险产品。"}, {"from": "human", "value": "这个大病保险的报销比例有多少?"}, {"from": "model", "value": "重大疾病保险报销比例是根据保险合同中约定的具体条款来确定的,不同的保险公司和不同的保险产品可能有不同的报销比例。"}, {"from": "human", "value": "我妈也想给我买一份,但是我目前17岁,可以买么?"}, {"from": "model", "value": "可以,但是未成年需要父母作为投保人来购买。"}]}
无监督数据格式
我们的无监督数据构建脚本代码支持了丰富的大模型常见的数据格式,无监督 pipeline 目前支持如下格式:
1. json 文件: 支持 json 对象文件和 json 数组文件的解析;
2. jsonline 文件: 支持 jsonline 多行文件格式;
3. parquet 文件: parquet 列式存储格式是开源数据常见格式(Parquet文档)。我们会先把 parquet 对象转成 json 对象,您可在下述采样过程中预览转换后的 json 格式,再进行数据处理;
4. text 文件: txt 文本文件;
5. wet 格式: WET 表示原始网页 WARC 文本化(WET)格式。 我们会把WET解析成json对象,您可在采样过程中预览,再进行数据处理;
6. 数据集文件夹: 支持以上类型的多个文件放在同一文件夹下面处理, 同一文件夹下下面目前只支持一种类型的多个文件同时处理。
数据格式的示例如下:
json:json 数组的每一行作为一条数据
["this is statement 1","this is statement 2"]
jsonl:每一行的"text"key 对应的 value 字段作为一条数据,例如:
{"text": "this is statement 1"}{"text": "this is statement 2"}
text:
this is statement 1this is statement 2
wet:支持标准的 Web Archive,详情请参考 示例数据。
数据构建
开发机创建完成后,单击打开按钮,进入到前述描述的
/home/tione/notebook/<nb-id>/single_round_qa_pipeline/
工作路径下,并打开quick_start.ipynb 之后,既可看到完整的数据构建步骤。如下图所示。

可以看到,整个数据构建流程分为如下步骤:
步骤0:环境初始化:导入必要的 python 包;
步骤1:原始数据解析: 将形式格式不确定的原始数据转换为 tione 平台需要的三元组格式
(system, question, answer)
,并且输出为 jsonl 文件。步骤2:数据清洗: 依据用户指定配置清洗数据数据,例如数据过滤(去除不满足要求的样本),数据改写(繁简转换,全角半角转换等)
步骤3:数据去重: 将清洗完之后的数据计算 embedding 相似度并去重;
步骤4:数据优化: 优化训练数据的 prompt,以提升指令理解效果。
步骤5:生成训练数据: 输出必要的训练数据统计分析结果,prompt 长度,response 长度,以及复合训练要求的数据格式。
上述五个步骤中,除了步骤1您必须根据输入数据格式进行修改之外,其他所有步骤都可以默认采用平台设置;
当您觉得平台默认规则构建的数据依然不理想时,您可以根据每个步骤的提示进行针对性的调整和优化,例如:
数据清洗: 可打开
config/clean_config.yaml
进行清洗规则配置修改;数据清洗: 可以按照平台要求自定义清洗函数并注册;
数据优化: 可打开
config/instruction_dict.yaml
来填充丰富的instruction替换规则;
步骤一: 原始数据解析(需要自定义解析函数)
对于本示例中的单轮有监督 PPL,平台后续清洗去重等步骤要求的输入格式为 jsonl 格式,每一行 json 对象都是如下的三元组:
{"system": "您是一名作家,能理解用户问题并解答", "question": "请写一首关于黄河的诗", "answer": "白日依山尽,黄河入海流;欲穷千里目,更上一层楼"}
因此对于您的原始输入格式(如 json/jsonline/parquet)等格式,您需要编写自定义的解析函数,将原始数据的格式转换成平台要求的格式。
对于原始数据,您指定好您的文件路径后,执行原始数据采样代码块,我们会输出您原始数据的采样格式。


示例如下:
如果您的原始数据是 json 格式或者 jsonline,我们抽样展示部分数据。


如果您的原始数据是 parquet 格式,我们会转成 json 格式之后,再抽样展示部分数据。
在采样了解了原始数据格式之后,您需要将原始数据转换成 TIONE 平台要求的输入格式。对于您的输入文件,我们会解析成多行的 json,并把 json 格式转成 python dict 格式。从您的 json 对应的 dict 格式转成 tione 平台要求的格式需要您自定义
convert_dict_to_tione_format
函数来实现您自己的转换逻辑。您可以参考以下代码段进行实现;

步骤一完成之后,我们会输出原始样本的统计信息,包括样本数量,有监督训练数据 question/answer 字段的长度分布,中英文数据条数统计等信息;


步骤二: 数据清洗(可以自定义清洗规则)
清洗函数分为两类:一类是改写,一类是过滤;
改写函数:输入原始文件和 config,返回改写后的文本;其中 config 就是您在配置文件里面配置的具体清洗方法同名的配置,如果您未设置配置,该参数为 None,可以不使用。您可以参考系统
length_filter
(长度过滤函数)了解config的用法;系统默认的改写函数列表您可以参考:
tools/modify_func.py
如果您需要增加自定义的改写函数,您需要通过python的装饰器
@modify_func.ModifyFunctionManager.register(zh_name="中文名称")
来进行注册,注册后系统会自动执行;其中zh_name
定义了改写函数的中文名称用于可视化,未设置即为使用函数名称; 过滤函数:输入原始文本和 config,返回两个值[bool, str],其中第一个布尔值代表是否需要过滤,str 字符串代表过滤的详细原因用于可视化(您可以选择性实现);其中 config 就是您在配置文件里面配置的具体清洗方法同名的配置,如果您未设置配置,该参数为 None,可以不使用。您可以参考系统length_filter(长度过滤函数)了解 config 的用法;
系统默认的过滤函数列表您可以参考:
tools/filter_func.py
如果您需要增加自定义的过滤函数,您需要通过 python 的装饰器
@filter_func.FilterFunctionManager.register(zh_name="中文名称")
来进行注册,注册后系统会自动执行;其中 zh_name 定义了过滤函数的中文名称用于可视化,未设置即为使用函数名称;过滤只可能被优先命中的规则过滤;改写可能会命中多条改写规则;
默认情况下,平台内置的规则应该能满足很大一部分场景的需求,如果您的场景较为特殊,您可以通过自定义注册的方式在此处新增您的自定义清洗规则。


清洗流程完成后,我们会输出清洗前后的数据量,并采样部分被清洗数据进行可视化展示,便于您比较清洗规则是否符合预期。


步骤三: 数据去重(不建议修改)
平台内置的数据去重的逻辑比较复杂,耗时也比较长(模型加载与数据计算普遍在5分钟以上)。此部分逻辑比较专业,不建议您自行实现。当然您可以指定需要去重的字段,例如 question/answer。


步骤四: 数据优化(修改配置文件)
您可以按需修改
config/instruction_dict.py
自定义场景的 instruction 列表。

数据优化完成后,我们在生成训练数据前,自动统计和采样指定数目的样例数据,执行数据统计脚本,输出数据QA问答对的平均长度,长度分布直方图,和中英文分布的饼图,便于您了解本次数据构建的pipeline执行结果是否符合预期。


步骤五: 训练格式生成(不建议修改)


执行完上述所有流程之后,我们就在开发机里的
/home/tione/notebook/<nb-id>/single_round_qa_pipeline/final_dataset_files
(也就是 cfs:///data/custom/prepare/<nb-id>/single_round_qa_pipeline/final_dataset_files
)里存有构建完之后的数据,您可以在"大模型精调"模块加以使用。
该步骤的输出中包括 cfs 的映射路径,您可以直接在任务式建模中挂载这个 cfs 路径用于训练数据的挂载原路径。


在“大模型精调”模块使用构建好的训练数据