LLM - 数据处理之 Process Dataset For LLM With PT、SFT、RM

目录

一.引言

二.PT 数据流程

1.数据样式

2.生成代码

3.数据生成

三.SFT 数据流程

1.数据样式

2.生成代码

3.数据生成

四.RM 数据流程

1.生成逻辑

2.RM 模型测试

五.总结


一.引言

上篇文章 LLM - 批量加载 dataset 并合并介绍了如何加载多个文件并合成一个 dataset 数据集,本文基于上文生成的 dataset,生成后续任务所需的样式,这里任务分下面三个类型:

- pt 即 pretrain,预训练

- sft 即 Supervised fine tuning ,有监督的微调

- rm 即 reward model,奖励模型

Tips:

本文数据集与代码主要参考 Github LLaMA-Efficient-Tuning。

二.PT 数据流程

pretrain 的目的是对模型预训练,使得模型具备基础的知识。这里我们可以把知识理解为记忆面包,统统一股脑喂给模型即可。

1.数据样式

以 wiki_demo.txt 为例,其中每一行信息就是我们上面说到的记忆面包的知识。PT 也是一种自学习的方法,就像之前版本给出的那样,PT 的样本 source 和 target 是一样的。

2.生成代码

def preprocess_pretrain_dataset(examples: Dict[str, List[Any]]) -> Dict[str, Any]:# build grouped texts with format `X1 X2 X3 ...`if isinstance(getattr(tokenizer, "tokenizer", None), tiktoken.Encoding):token_kwargs = dict(allowed_special="all")  # for tiktoken tokenizer (Qwen)else:token_kwargs = dict(add_special_tokens=True)if hasattr(tokenizer, "add_bos_token") and hasattr(tokenizer, "add_eos_token"):setattr(tokenizer, "add_bos_token", True)  # for LLaMA tokenizersetattr(tokenizer, "add_eos_token", True)tokenized_examples = tokenizer(examples["instruction"], **token_kwargs)concatenated_examples = {k: list(chain(*tokenized_examples[k])) for k in tokenized_examples.keys()}total_length = len(concatenated_examples[list(concatenated_examples.keys())[0]])block_size = 512# we drop the small remainder, and if the total_length < block_size, we exclude this batchtotal_length = (total_length // block_size) * block_size# split by chunks of max_source_lengthresult = {k: [t[i: i + block_size] for i in range(0, total_length, block_size)]for k, t in concatenated_examples.items()}return result

- examples: Dict[str, List[Any]]

examples 为我们加载文件数据得到的 dataset,这里默认 pretrain 要训练的知识存储在每条 json 的 instruction 字段中。

- tokenized_examples

通过 tokenizer 批量 tokenzier 文本能得到 input_ids,形式大概是 List[List] 嵌套。这里 Baichuan 模型可以不需要 bos_token_id 和 eos_token_id,LLaMA 需要 bos_token_id 和 eos_token_id。

- concatenated_examples

通过 chain 将 input_ids 与 attention_mask 都连在一起。

- result

将上面 chain 整合在一起的 input_ids 按照 block 为尺寸进行包装,并存储至 results 中。result 中的 input_ids 中每个 list 保持 block 的大小。 

 

3.数据生成

import os.path
from datasets import load_dataset, concatenate_datasets, interleave_datasets
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Literal, Union, Tuple
from transformers import GPT2Tokenizer
from itertools import chain
import tiktokentokenizer = GPT2Tokenizer.from_pretrained("gpt2")if __name__ == '__main__':# 多文件地址base_path = "/Users/LLaMA-Efficient-Tuning-main/data"data_files = ['alpaca_data_zh_51k.json', 'alpaca_gpt4_data_zh.json']strategy = 'concat'train_dataset = getBatchDataSet(base_path, data_files, strategy)kwargs = dict(num_proc=4,load_from_cache_file=False,desc="Running tokenizer on dataset")stage = 'pt'if stage == "pt":train_dataset = train_dataset.filter(lambda example: example["instruction"])preprocess_function = preprocess_pretrain_datasetcolumn_names = list(next(iter(train_dataset)).keys())dataset = train_dataset.select(range(1024)).map(preprocess_function,batched=True,remove_columns=column_names,**kwargs)limit = 5if stage == "pt":for source in dataset.select(range(limit))['input_ids']:print(len(source), source)

为了快速演示 demo,我们对原始数据集进行了 select 1024 的限制,并且在最后取 5 条数据打印,这里 tokenizer 为了便捷我们继续使用 GPT-2 进行测试:

这里 block_size = max_source_length = max_target_length = 512。

三.SFT 数据流程

1.数据样式

以 aplace_gpt4_data_zh.json 为例,SFT 有监督微调的数据以 QA 的形式提供,其中 instruction 可以作为 prompt 使用即 Q,如果 instrution 和 input 都有值,则逻辑会把二者拼接在一起作为统一个 Source。output 为 A ,在有监督微调的情况下,前面的 Prompt 会以 mask 的形式进行遮蔽,从而构造 label_ids。

 

2.生成代码

def preprocess_supervised_dataset(examples: Dict[str, List[Any]]) -> Dict[str, Any]:# build inputs with format `<bos> X Y <eos>` and labels with format `<ignore> ... <ignore> Y <eos>`# for multi turn examples, we only mask the prompt part in each prompt-response pair.model_inputs = {"input_ids": [], "attention_mask": [], "labels": []}max_source_length = 512max_target_length = 512max_length = max_source_length + max_target_lengthr"""Encodes formatted inputs to pairs of token ids.Turn 0: bos + prefix + sep + query    resp + eosTurn t: sep + bos + query             resp + eos"""# special tokensbos_ids = [tokenizer.bos_token_id]eos_ids = [tokenizer.eos_token_id]sep_ids = [tokenizer.sep_token_id]print("bos_id: %s eos_id: %s sep_id: %s" % (str(tokenizer.bos_token_id), str(tokenizer.eos_token_id), str(tokenizer.sep_token_id)))# 开始标记is_start = True# token 配置token_kwargs = dict(add_special_tokens=False)for query, response, history, system in construct_example(examples):input_ids, labels = [], []prefix = "{{system}}"prefix_ids = [] + tokenizer.encode(prefix, **kwargs)if is_start:if len(prefix_ids) != 0:  # has prefixprefix_ids = bos_ids + prefix_ids + sep_idselse:prefix_ids = bos_ids# 重置is_start = Falseelse:prefix_ids = sep_ids + bos_idssource_ids = prefix_ids + tokenizer.encode(query, **token_kwargs)target_ids = tokenizer.encode(response, **token_kwargs) + eos_idsif len(source_ids) > max_source_length:source_ids = source_ids[:max_source_length]if len(target_ids) > max_target_length:target_ids = target_ids[:max_target_length]if len(input_ids) + len(source_ids) + len(target_ids) > max_length:breaksource_mask = [IGNORE_INDEX] * len(source_ids)input_ids += source_ids + target_idslabels += source_mask + target_idsmodel_inputs["input_ids"].append(input_ids)model_inputs["attention_mask"].append([1] * len(input_ids))model_inputs["labels"].append(labels)return model_inputs

这里的生成代码相对 PT 较长一些,这里博主按块的形式分解:

- Init Model Input

input_ids 和对应的 labels 即为有监督微调的监督部分,其次定义了 max_source_length 和 max_target_length,这个数值和不同模型支持的最大长度也有关系。

- Special Token

定义特殊的分割 token_id,同时需要注意第一个样本开头包含 bos。如果包含自定义的 template 模板或者前缀,也可以结合 sep 添加到 souce 中。

- Encode Query And Response

根据是否 start 以及是否包含 prefix,获取 prefix_ids,常规情况下,prefix_ids 只包含一个 bos_token_id,后续的样本需要在  bos_token_id 前增加一个 sep_token_id。source_id 通过 prefix_ids 和 query [instruction] token 得到的 ids 拼接而成,target_ids 通过 response [output] token 得到的 ids 和 eos_ids 拼接而成。

- construct_example

上面生成 token_ids 使用 construcj_example 对原始数据做了第一道处理,可以看到对应的 key 的关系。同时也看到如果有 input 输入,query 会将 input 拼接到一起构成新的 query。由于这里我们并未用到 history 和 system [框架里对应模板],所以这两个 None 可以忽略。

- get Model Input

首先根据 init model input 的 max_length 相关定义对得到的 source_ids 和 target_ids 进行截断,并为 labels 构建 source_mask 将 source 部分遮蔽,其中 IGNORE_INDEX 为 -100。最终全部添加至 model_input 即可。

3.数据生成

if __name__ == '__main__':# 多文件地址base_path = "/Users/LLaMA-Efficient-Tuning-main/data"data_files = ['alpaca_data_zh_51k.json', 'alpaca_gpt4_data_zh.json']strategy = 'concat'train_dataset = getBatchDataSet(base_path, data_files, strategy)kwargs = dict(num_proc=4,load_from_cache_file=False,desc="Running tokenizer on dataset")stage = 'pt'if stage == "pt":train_dataset = train_dataset.filter(lambda example: example["instruction"])preprocess_function = preprocess_pretrain_datasetelif stage == 'sft':train_dataset = train_dataset.filter(lambda example: example["instruction"] and example["output"])preprocess_function = preprocess_supervised_datasetelse:raise ValueError("UnKnown process stage")column_names = list(next(iter(train_dataset)).keys())dataset = train_dataset.select(range(1024)).map(preprocess_function,batched=True,remove_columns=column_names,**kwargs)limit = 5if stage == "pt":for source in dataset.select(range(limit))['input_ids']:print(len(source), source)else:for source, target in zip(dataset.select(range(limit))['input_ids'], dataset.select(range(5))['labels']):print(source, target)

添加 stage == 'sft' 的逻辑,下图为 GPT2-Tokenizer 对应的 special token:

 最终的样例数据:

四.RM 数据流程

1.生成逻辑

RM 模型用于针对给定的 QA 对进行评分,因此训练 RM 模型需要传给模型好的回复和不好的回复,这里我们主要看代码的逻辑,不再输出测试。

    def preprocess_pairwise_dataset(examples):# build input pairs with format `<bos> X`, `Y1 <eos>` and `Y2 <eos>`model_inputs = {"prompt_ids": [], "chosen_ids": [], "rejected_ids": []}for query, response, history, system in construct_example(examples):prompt_ids, chosen_ids = template.encode_oneturn(tokenizer, query, response[0], history, system)_, rejected_ids = template.encode_oneturn(tokenizer, query, response[1], history, system)if len(prompt_ids) > data_args.max_source_length:prompt_ids = prompt_ids[:data_args.max_source_length]if len(chosen_ids) > data_args.max_target_length:chosen_ids = chosen_ids[:data_args.max_target_length]if len(rejected_ids) > data_args.max_target_length:rejected_ids = rejected_ids[:data_args.max_target_length]model_inputs["prompt_ids"].append(prompt_ids)model_inputs["chosen_ids"].append(chosen_ids)model_inputs["rejected_ids"].append(rejected_ids)return model_inputs

和前面 sft 的逻辑比较相似,sft 只有 source 和 target,这里 prompt 相当于 source,chosen_ids 相当于 positive_target 的 token ids,rejected_ids 相当于 negative_target 的 token ids,最终全部添加至 model_inputs 即可。原始样本的格式我们虽然未给出,但是大家可以自行构建,只需要在 sft 的基础上增加 bad case 即可,不过这一步需要有正负情感的数据标注。

2.RM 模型测试

Ziya 类模型提供原生的 Reward Model,下面我们展示下其工作流程:

import torch
from transformers import AutoModelForSequenceClassification,LlamaTokenizer
reward_model = AutoModelForSequenceClassification.from_pretrained("/data2/ziya/Ziya-LLaMA-7B-Reward", trust_remote_code=True)
reward_model = reward_model.eval().half().cuda()lora_reward_model = AutoModelForSequenceClassification.from_pretrained("./MergeZiya", trust_remote_code=True)
lora_reward_model = lora_reward_model.eval().half().cuda()tokenizer = LlamaTokenizer.from_pretrained("/data2/ziya/Ziya-LLaMA-7B-Reward",add_eos_token=True)prefix_user = "Human:"
prefix_bot = "\n\nAssistant:"
query = "列举一种空气污染。"
response = "一种常见的空气污染源是化石燃料的燃烧产生的尾气排放,包括来自汽车、卡车、飞机、火车和工业厂房的废气排放。这会导致大气中的二>氧化硫、氮氧化物、一氧化碳、臭氧和颗粒物(例如灰尘和烟雾)等污染物含量增加,对人类健康和环境造成不利影响。"text = prefix_user + query + prefix_bot+response
batch = tokenizer(text, return_tensors="pt", padding=True, truncation=True, max_length=1024)
with torch.no_grad():reward = reward_model(batch['input_ids'].cuda(), attention_mask = batch['attention_mask'].cuda())print("ori:",reward.item())reward = lora_reward_model(batch['input_ids'].cuda(), attention_mask = batch['attention_mask'].cuda())print("lora:",reward.item())

最终会打印一个 0-1 之间的值代表二者的相关性。

五.总结

经过前面的 Dataset 生成与本文的 PreProcess 预处理,我们已经得到可训的 Dataset,后续我们继续熟悉框架代码,看看 trainer 如何构建,整个训练任务怎么进行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/131117.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode:67. 二进制求和

题目&#xff1a; 函数原型&#xff1a; char * addBinary(char * a, char * b) 思路&#xff1a; 二进制相加&#xff0c;首先我们考虑先将字符串逆序。由此要写一个逆序函数reserve。字符串逆序后&#xff0c;从前往后相加&#xff0c;以较长的字符串的长度为标准长度n&#…

【光谱超分辨率:综述】

Spectral super-resolution meets deep learning: Achievements and challenges &#xff08;面向深度学习的光谱超分辨率&#xff1a;成就和挑战&#xff09; 光谱超分辨率是一种从RGB图像获取高光谱图像的重要技术&#xff0c;可以有效地克服高光谱图像获取成本高、空间分辨…

vite + react + typescript + uni-app + node 开发一个生态系统

简介 使用 vite react typescript uni-app node 来开发一个简易的生态系统案例&#xff0c;包含 APP&#xff0c;H5&#xff0c;微信小程序&#xff0c;控制台&#xff0c;服务端 开发 admin 技术栈&#xff1a;vite react typescript初始化控制台项目选择自定义预设…

Gitlab仓库部署

Gitlab仓库部署 一、Gitlab的概述1、gitlab介绍2、gitlab主要功能3、gitlab和github的区别 二、部署环境1、安装依赖环境2、安装Postfix邮箱3、Gitlab优势4、Gitlab工作流程 三、Gitlab部署过程1、Yum安装Gitlab2、配置gitlab站点URL3、启动并访问Gitlab 四、Gitlab具体操作1、…

CSS盒子模型

盒子模型的组成 CSS会把所有的HTML元素都看成一个盒子&#xff0c;所有的样式也都是基于这个盒子 content&#xff08;内容&#xff09;&#xff1a;盒子的内容padding&#xff08;内边距&#xff09;&#xff1a;用于控制元素内部与边框之间的距离border&#xff08;边框&…

Qt打开及创建项目,运行程序(1)

安装之后&#xff0c; 1.文件->新建文件或项目 2.Application->Qt Widgets Application 3.自己设置名称和路径 4.这一步非常非常重要&#xff0c;要选择编译器&#xff0c;&#xff08;MinGW是可以在Qt里用&#xff0c;如果想与VS交互&#xff0c;要选择MSVC&#xff09…

去除pdf/word的水印艺术字

对于pdf中的水印如果无法去除水印&#xff0c;则先另存为word&#xff0c;然后再按下面办法处理即可&#xff1a; 查看宏&#xff0c;创建&#xff1a;删除艺术字 添加内容&#xff1a; Sub 删除艺术字()Dim sh As ShapeFor Each sh In ActiveDocument.ShapesIf sh.Type msoT…

如何使用谷歌浏览器连接linux服务器SSH服务

环境&#xff1a; 谷歌浏览器 版本 116.0.5845.141&#xff08;正式版本&#xff09; &#xff08;64 位&#xff09; Win10 专业版 安全外壳 (SSH)v.0.58 问题描述&#xff1a; 如何使用谷歌浏览器连接linux服务器SSH服务 解决方案&#xff1a; 1.找了有台安装好了这个插…

计算机视觉实战项目(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别)

图像分类 教程博客_传送门链接:链接 在本教程中&#xff0c;您将学习如何使用迁移学习训练卷积神经网络以进行图像分类。您可以在 cs231n 上阅读有关迁移学习的更多信息。 本文主要目的是教会你如何自己搭建分类模型&#xff0c;耐心看完&#xff0c;相信会有很大收获。废话不…

Vite+React+Electron开发入门,10分钟搭建本地环境并打包

前言 想使用vite和react开发跨平台桌面的软件方案有electron和tauri两种&#xff0c;但是我个人更喜欢tauri&#xff0c;无奈electron名声大燥&#xff0c;面试要求里很多都写着&#xff1a;electron...可见这类公司多么落后。但是呢&#xff0c;又秉持着存在即合理的理念&…

Ubuntu22.04开启后屏幕黄屏

1. 故障现象 系统&#xff1a;Ubuntu22.04 现象&#xff1a;电脑从开机到进入桌面一直屏幕黄屏 2. 故障分析 可能为屏幕色彩调节出现故障 3. 解决方案 系统设置——》色彩——》删除原来的配置&#xff08;remove profile&#xff09;——》添加配置Colorspace:Compatibl…

八股——const 关键字

1.const作用 作用&#xff1a;const用于保护指针指向数据不被修改 测试代码1 显示数组的函数不小心修改了指针指向的值&#xff0c;这时候没有加const关键字&#xff0c;编译器不会报错 #include <stdio.h> void showar(int ar[]);int main(void) {int ar[4]{2,3,4,5…

antd react 文件上传只允许上传一个文件且上传后隐藏上传按钮

antd react 文件上传只允许上传一个文件且上传后隐藏上传按钮 效果图代码解析 效果图 代码解析 import { Form, Upload, message } from antd; import { PlusOutlined } from ant-design/icons; import { useState, useEffect } from react; import { BASE_URL } from /utils/…

kafka增加磁盘或者分区,topic重分区

场景&#xff1a;kafka配置文件log.dirs增加了几个目录&#xff0c;但是新目录没有分区数据写入&#xff0c;所以打算进行重分区一下。 1.生成迁移计划 进入kafka/bin目录 新建 topic-reassign.json,把要重分区的topic按下面格式写。 { "topics": [{ …

深度学习基础之梯度下降

1. 引言 梯度下降是一种用于最小化&#xff08;或最大化&#xff09;损失函数的优化算法。它是机器学习和深度学习中的一个关键概念&#xff0c;通常用于调整学习算法中的参数。 梯度下降背后的核心思想是迭代调整参数以最小化损失函数。它的工作原理是计算损失函数相对于每个…

2023-09-12 LeetCode每日一题(课程表 IV)

2023-03-29每日一题 一、题目编号 1462. 课程表 IV二、题目链接 点击跳转到题目位置 三、题目描述 你总共需要上 numCourses 门课&#xff0c;课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite &#xff0c;其中 prerequisites[i] [ai, bi] 表示如果你…

C基础-操作符详解

操作符分类&#xff1a; 算数操作符&#xff1a; - * / % //算数操作符 // int main() // { // // /除法 1.整数除法(除号两端都是整数) 2浮点数除法&#xff0c;除号的两端只要有一个小数就执行小数除法 // // 除法中&#xff0c;除数为0 // int a 7 / 2; /…

Matlab图像处理-彩色图像基础

彩色的物理认识 人类能够感知的物体的颜色是由物体反射的光的性质决定的。如图8-2所示&#xff0c;可见光是由电磁波谱中较窄的波段组成。 如果物体反射的光在所有可见光波长范围内都是平衡的&#xff0c;那么从观察者的角度来看&#xff0c;它是白色的&#xff1b; 如果物体…

UG\NX CAM二次开发 设置工序检查边界 UF_CAMBND_append_bnd_from_curve

文章作者:代工 来源网站:NX CAM二次开发专栏 简介: UG\NX CAM二次开发 设置工序检查边界 UF_CAMBND_append_bnd_from_curve 效果: 代码: static int init_proc(UF_UI_selection_p_t select, void* user_data) { int errorCode = 0; int num_triples = 1; //…

解决php导出excel中小数尾部0不显示的问题

调整代码前&#xff1a; 新增代码&#xff1a; //小数避免末尾0不显示的问题 foreach ($list as &$line) {foreach ($line as &$column) {if (is_numeric($column) && strpos($column, .)!false) {$column " {$column} ";}} } 效果&#xf…