如何训练一个自己偏好的大模型(附代码)

本篇具体介绍奖励模型原理及作用,并结合代码详细介绍实现方法,在文末附有可执行代码。

基于一个大模型,本系列开始讲如何对大模型进行微调、强化学习,基于大模型本身强大的生成能力引导成更适配于多种应用场景的专属领域大模型。

由于基于大模型进行SFT的一系列操作,例如P-tuning、P-tuning v2等已有很多教程与开源代码,因此本系列将重点放在奖励模型、强化学习与大模型结合的内容。

大模型微调分为系列分为:

1)reward:训练一个具有自己偏好的奖励模型

2)大模型、reward与强化学习强强联合:大模型只生成我想要的回答

本篇主要开始结合代码讲解如何训练一个具有自己偏好的奖励模型。下面是一个快捷目录。

1. reward模型及原理介绍

2. 数据处理模块

3. 模型框架模块

4. Loss计算模块

一、reward模型及原理介绍

在介绍原理前,我们来再次回顾一下一个类似于chatGPT这样大模型的训练流程。

1. LLM训练流程

  • 预训练:训练数据是海量无标签文本;

  • 监督式微调:训练数据是「指令 - 输入 - 输出」,举个实体关系抽取的例子。此步骤通过给模型一些可参考知识与指令来微调模型,指令学习阶段可以只动小部分模型参数。

inputjson={``"instruction": "你现在是一个信息抽取模型,请你帮我抽取出关系内容为\"性能故障\", \"部件故障\", \"组成\"和 \"检测工具\"的相关三元组,三元组内部用\"_\"连接,三元组之间用\\n分割。文本:",` `"input": "843号汽车故障报告故障现象热车起动困难",` `"output": "车_部件故障_起动困难"``}
  • 对齐:通过强化学习将输出与人类偏好对齐,训练数据是对模型输出内容的评分。

2. 对齐步骤强化学习具体训练流程

其训练流程再分为三步:

  • 第 1 步:对预训练模型进行监督式微调;

  • 第 2 步:创建一个奖励模型;

  • 第 3 步:通过近端策略优化进行微调。

奖励模型在其中的角色,就是在第三步骤中,目的是训练一个跟人类偏好相同的模型,对大模型生成的结果进行打分,并及时将打分结果反馈给模型,通过强化学习纠正或引导模型生成更符合人类要求的结果。

3.奖励模型训练步骤

分为两步:

  • 对模型生成内容进行排名:用上一步中创建的已微调 LLM 为每个 prompt 生成 4-9 个响应。然后再让人基于自己的偏好对这些响应进行排名。

  • 设计奖励模型:基于使用这些排名构建的数据集,可以设计一个奖励模型RM,其输出的是用于 RLHF 第 3 步后续优化阶段的奖励分数。在原本模型的基础上,需要将其输出层(下一 token 分类层)替换成一个回归层,其具有单个输出节点。

4.奖励模型原理与loss设计

因为涉及对人工排序后的句子进行排序,我们引入Rank Loss

假定模型生成4个答案,我们对4个句子的人工评分排序为 A>B>D>C;那么我们需要训练其对应的打分模型,模型生成的分要满足 r(A) > r(B) > r(D) > r©。

此处直接上损失函数公式:

其中,yi 代表排序排在 y1-i 前面的所有句子。

我们代入上面的例子 A>B>D>C :

loss = r(A) - r(B) + r(A) - r(C) + r(A) - r(D) + r(B) - r(D) + ... + r(D) - r(C)``loss = -loss

为了更好得归一化差值,每两项差值都需要过一个 sigmoid 函数,将值拉到 0 ~ 1 之间。

由于这个loss设计的目的是期望模型能够最大化 好句子得分和坏句子得分的差值,而梯度下降做的是最小化操作,因此loss前面的负号的目的是实现最大化差值。

那么奖励模型原理我们介绍完毕了,更直白的理解就是输入是句子,输出是对该句子的人类偏好评分;这个偏好是可以根据自己的需要去标注评分数据来实现的。 下面我们开始介绍核心代码。

二、数据处理模块

1. 数据示例

本次训练任务:做一个倾向产生好评的奖励模型,为好评给予更高的分数,为差评给予更低的分数。

此模块导入对生成句子进行人工评分后的数据。

数据格式按行切分,每行有多个评价,从前往后,好评在前,差评在后,每个评价间使用’\t’ 分割。

穿着合适,做工很精致,质量不错 穿着特别舒服,而且有弹性。型也好。"非常满意,房间和交通都不错,下次还要住该酒店了"  购买不满意,苹果较酸,不理想,有些吹牛。

2. 数据处理

这里数据处理的关键就是一定要将每一行内的多条评价文本拼到同一个数组内,代码见代码路径中的 loaddata.py,这里只展示核心代码。

try:  ``rank_texts = line.strip().split('\t')`  `except:  ``     print(f'"{line}" -> {traceback.format_exc()}')   ``     exit()   ``rank_texts_prop = {  ``     'input_ids': [],   ``     'token_type_ids': [],   ``     'position_ids': [],   ``'attention_mask': []`  `}`  `for rank_text in rank_texts:  ``     encoded_inputs = tokenizer(   ``             text=rank_text,   ``             truncation=True,   ``             max_length=max_seq_len,   ``             padding='max_length')   ``     rank_texts_prop['input_ids'].append(encoded_inputs["input_ids"])   ``     rank_texts_prop['token_type_ids'].append(encoded_inputs["token_type_ids"])   ``     rank_texts_prop['position_ids'].append([i for i in range(len(encoded_inputs["input_ids"]))])   ``rank_texts_prop['attention_mask'].append(encoded_inputs["attention_mask"])`  `for k, v in rank_texts_prop.items():  ``    tokenized_output[k] = v

三、模型框架

这里的模型,我们可以任意选择一个预训练好的模型,在原本模型的基础上,将其输出层(下一 token 分类层)替换成一个回归层,这个模型结构就设计完成了。

在本次实践中采用的预训练模型是ernie-3.0-base-zh ,其是用于语言理解和生成的大规模知识强化预训练模型。代码见代码路径中的 model.py,这里只展示核心代码。

class RewardModel(nn.Module):  ``     def __init__(self, encoder):   ``         """   ``         init func.   ``         Args:            encoder (transformers.AutoModel): backbone, 默认使用 ernie 3.0        """        super().__init__()   ``         self.encoder = encoder   ``         self.reward_layer = nn.Linear(768, 1)   ``     def forward(   ``         self,   ``         input_ids: torch.tensor,   ``         token_type_ids: torch.tensor,   ``         attention_mask=None,   ``         pos_ids=None,   ``     ) -> torch.tensor:   ``         """   ``        forward 函数,返回每句话的得分值。`    `"""``     pooler_output = self.encoder(   ``             input_ids=input_ids,   ``             token_type_ids=token_type_ids,   ``             position_ids=pos_ids,   ``             attention_mask=attention_mask,   ``         )["pooler_output"]                              # (batch, hidden_size)   ``         reward = self.reward_layer(pooler_output)       # (batch, 1)   ``        return reward

四、Loss计算模块

1. 加载batch阶段

这里就需要注意结合前面加载数据时,每一行的数据是一个数组,其中包含有多条评价数据且按数组顺序从前到后,由好评到差评,因此我们在加载数据时需要对应数据处理模块的数据结构,将同一行的句子分别送入模型计算出的值装到一个数组。

batch_rank_rewards = []`  `for batch_idx in range(len(batch['input_ids'])):  ``     rank_texts_count = len(batch['input_ids'][batch_idx])   ``     rank_rewards = []   ``     for text_idx in range(rank_texts_count):   ``         reward = model(   ``             batch['input_ids'][batch_idx][text_idx].unsqueeze(dim=0).to(args.device),   ``             batch['token_type_ids'][batch_idx][text_idx].unsqueeze(dim=0).to(args.device),   ``             batch['attention_mask'][batch_idx][text_idx].unsqueeze(dim=0).to(args.device),   ``             batch['position_ids'][batch_idx][text_idx].unsqueeze(dim=0).to(args.device),   ``         )   ``         rank_rewards.append(reward[0])                       ``    batch_rank_rewards.append(rank_rewards)

2.训练阶段

这里比较常规,直接上代码。

loss = compute_rank_list_loss(batch_rank_rewards, device=args.device)`  `loss.backward()`  `optimizer.step()`  `lr_scheduler.step()`  `optimizer.zero_grad()

3. loss计算部分

从上面我们可以,看到核心函数就是 compute_rank_list_loss,这里的关键依然是每一行的句子评分是在前面计算时有序(从高到低)排序句子的reward列表。

def compute_rank_list_loss(rank_rewards_list: List[List[torch.tensor]], device='cpu') -> torch.Tensor:  ``   if type(rank_rewards_list) != list:   ``           raise TypeError(f'@param rank_rewards expected "list", received{type(rank_rewards)}.')   ``     loss, add_count = torch.tensor([0]).to(device), 0   ``     for rank_rewards in rank_rewards_list:   ``         for i in range(len(rank_rewards)-1):                                   # 遍历所有前项-后项的得分差   ``             for j in range(i+1, len(rank_rewards)):   ``                 diff = F.logsigmoid(rank_rewards[i] - rank_rewards[j])         # sigmoid到0~1之间   ``                 loss = loss + diff   ``                 add_count += 1   ``     loss = loss / add_count   ``    return -loss

那么,至此为什么要训练reward模型,以及如何训练reward模型就说完了。

完整的预训练模型下载地址、数据以及代码见

https://github.com/sailerml/RLHF_GLM

后续我们结合奖励模型,基于大模型进行强化学习实践,并分享一些训练技巧,欢迎大家持续关注~

读者福利:如果大家对大模型感兴趣,这套大模型学习资料一定对你有用

对于0基础小白入门:

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。

包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

👉AI大模型学习路线汇总👈

大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

👉大模型实战案例👈

光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉大模型视频和PDF合集👈

观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

在这里插入图片描述

在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员二飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值