reinforcement-learning-in-llm 代码解读复现(2)
继续上一篇文章的内容我们来做一个Reward model。1、加载模型base_model AutoModelForCausalLM.from_pretrained(./llm_sft).to(device) base_model这是在上一篇文章当中训练好的模型我们查看一下模型结构。上述代码输出为LlamaForCausalLM((model): LlamaModel((embed_tokens): Embedding(49152, 576, padding_idx2)(layers): ModuleList((0-29): 30 x LlamaDecoderLayer((self_attn): LlamaAttention((q_proj): Linear(in_features576, out_features576, biasFalse)(k_proj): Linear(in_features576, out_features192, biasFalse)(v_proj): Linear(in_features576, out_features192, biasFalse)(o_proj): Linear(in_features576, out_features576, biasFalse))(mlp): LlamaMLP((gate_proj): Linear(in_features576, out_features1536, biasFalse)(up_proj): Linear(in_features576, out_features1536, biasFalse)(down_proj): Linear(in_features1536, out_features576, biasFalse)(act_fn): SiLUActivation())(input_layernorm): LlamaRMSNorm((576,), eps1e-05)(post_attention_layernorm): LlamaRMSNorm((576,), eps1e-05)))(norm): LlamaRMSNorm((576,), eps1e-05)(rotary_emb): LlamaRotaryEmbedding())(lm_head): Linear(in_features576, out_features49152, biasFalse))(embed_tokens): Embedding(49152, 576, padding_idx2) 这里是一个超大的嵌入向量相当于字典对于某一个token都有一个576长度的嵌入一共有49152种tokenpadding_idx2表示第二个token是paddingtoken。(lm_head): Linear(in_features576, out_features49152, biasFalse)是输出了一个49152维度的向量每一个维度都是对应token的出现概率然后采样获得下一个token。对于一个奖励模型来说我们不会要某一个token出现的分数而是对于这些已存在的token的打分因此在这里可以把最后一层的线性层变成576-1的超级简单的线性层目的就是输出一个最终score。2、更改网络最后一层from torch import nn # define model class class RewardModel(nn.Module): def __init__( self, base_model, ): super().__init__() # replace final linear layer self.base_model base_model # 把base_model的lm_head替换为一个新的线性层 self.base_model.__setattr__( lm_head, nn.Linear(576, 1, biasFalse).to(device)) def forward(self, input_ids, attention_mask): output self.base_model( input_idsinput_ids, attention_maskattention_mask, ).logits # .logits是因为只改了模型层没有改参数名这里其实就是把原来输出词表大小的logits改成输出一个数值reward score了。 # need only final output in sequence # input_ids.shape: torch.Size([3, 23]) batch_size input_ids.shape[0] # token_indices.shape: torch.Size([23]) token_indices torch.arange(input_ids.shape[-1], dtypeint).to(device) # last_nonpad_indices.shape: torch.Size([3]) # 这里为什么还要获得最后一个非padding token的索引 # 事项一下句子1 [A B C D PAD]句子2 [E F G PAD PAD] # 我们打分的时候看到ABCD打分就可以了PAD不应该参与打分所以需要找到最后一个非PAD token的位置。 # 因此才需要last_nonpad_indices为[3, 2]表示每个序列中最后一个非pad token的索引位置。 last_nonpad_indices (token_indices * attention_mask).argmax(-1) # reward_score.shape: torch.Size([3]) reward_score output[torch.arange(batch_size).to(device), last_nonpad_indices] return reward_score # generate model instance rm RewardModel(base_model).to(device)3、数据过滤# 1. add chosen_len and rejected_len column # (which indicates the sequence length in chosen and rejected) def add_seq_len(example): # 计算文本的tokenized长度并把长度添加到example中 def get_tokenized_length(text): tokenized tokenizer(text) return len(tokenized[input_ids]) chosen_len get_tokenized_length(example[chosen]) reject_len get_tokenized_length(example[rejected]) return { chosen_len: chosen_len, rejected_len: reject_len } train_data train_data.map(add_seq_len) # 2. remove rows which exceed the maximum sequence length # 为了后续训练我们需要移除那些超过最大序列长度的样本。 train_data train_data.filter(lambda example: example[chosen_len] max_seq_len and example[rejected_len] max_seq_len) train_data train_data.remove_columns([chosen_len, rejected_len]) # show total number of filtered rows train_data4、开始训练奖励模型batch_size 4 gradient_accumulation_steps 8 # 梯度累加步数 # 为了避免内存不足我们可以使用梯度累加步数。 # 即每次只计算一部分样本的梯度然后累加起来再更新模型参数。 def collate_batch(batch): # tokenize (convert to token ids and attention mask) and convert to tensor chosen_list [item[chosen] for item in batch] reject_list [item[rejected] for item in batch] chosen_tensor tokenizer( chosen_list, paddingTrue, padding_sideleft, # see above description ! return_tensorspt).to(device) reject_tensor tokenizer( reject_list, paddingTrue, padding_sideleft, # see above description ! return_tensorspt).to(device) return chosen_tensor, reject_tensor dataloader DataLoader( train_data, batch_sizebatch_size, shuffleTrue, collate_fncollate_batch )正常Tesla T4(16G)的batch size为4够用在这里我用的是2080Ti12G所以把batchsize改为2可以正常训练。num_epochs 1 num_steps math.ceil(len(dataloader) / gradient_accumulation_steps) torch.set_default_dtype(torch.bfloat16) optimizer torch.optim.AdamW( paramsrm.parameters(), lr3.0e-5, betas(0.9, 0.999), eps1e-08, ) def _get_cosine_schedule( current_step: int, num_training_steps: int, num_warmup_steps: int0, linear_warmup: boolFalse, min_value: float0.0, ): if current_step num_warmup_steps: if linear_warmup: return min(1.0, (current_step 1) / (num_warmup_steps 1)) # see https://arxiv.org/abs/2410.11020 else: return 1.0 progress float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps)) scale 0.5 * (1.0 math.cos(math.pi * progress)) return (1.0 - min_value) * scale min_value scheduler LambdaLR(optimizer, lr_lambdafunctools.partial( _get_cosine_schedule, num_training_stepsnum_epochs*num_steps, num_warmup_stepsmath.ceil(num_epochs*num_steps*0.1))) # remove log file if exists log_file loss_rm.log if os.path.exists(log_file): os.remove(log_file) # iterate epoch for epoch in range(num_epochs): rm.train() optimizer.zero_grad() record_loss [] # iterate batch for i, (chosen, reject) in enumerate(dataloader): with torch.set_grad_enabled(True): # get reward score (chosen) rewards_chosen rm( input_idschosen[input_ids], attention_maskchosen[attention_mask], ) # get reward score (rejected) rewards_reject rm( input_idsreject[input_ids], attention_maskreject[attention_mask], ) # compute loss loss -F.logsigmoid(rewards_chosen - rewards_reject).mean() # 损失函数计算为 -log(sigmoid(reward_chosen - reward_reject)) # 即最大化 chosen 样本的 reward最小化 reject 样本的 reward。 loss.backward() # optimization by accumulation if ((i 1) % gradient_accumulation_steps 0) or \ (i 1 len(dataloader)): optimizer.step() scheduler.step() optimizer.zero_grad() # print log record_loss.append(loss.item()) print(fEpoch {epoch1} (iter{i1}) {math.ceil((i 1) / gradient_accumulation_steps)}/{num_steps} - loss {loss :5.4f}, end\r) # save logging epoch_average_loss sum(record_loss)/len(record_loss) print(fEpoch {epoch1} (iter{i1}) {math.ceil((i 1) / gradient_accumulation_steps)}/{num_steps} - loss {epoch_average_loss :5.4f}) with open(log_file, a) as f: for l in record_loss: f.write(%s\n %l) # save checkpoint torch.save(rm.state_dict(), rm.pt) print(Done)5、测试reward modelimport pandas as pd # # uncomment when you load RM from the trained checkpoint # rm.load_state_dict(torch.load(rm.pt, weights_onlyTrue)) rm.eval() test_list [ |im_start|user\nWhat do you most want to do right now?|im_end|\n|im_start|assistant\nRight now, I most want to assist you and provide helpful, respectful, and engaging interactions. If you have any questions, need information, or just want to chat, Im here for you!|im_end|, |im_start|user\nWhat do you most want to do right now?|im_end|\n|im_start|assistant\nId love to go for a hike in the woods! Its such a beautiful day and I really need to get some fresh air. How about you? |im_end|, |im_start|user\nWhat is the best gift to give a friend who loves the outdoors?|im_end|\n|im_start|assistant\nThats a thoughtful question! Here are a few gift ideas for a friend who loves the outdoors.: High-quality Multi-tool, Reusable Water Bottle with Filter, or Portable Hammock|im_end|, |im_start|user\nWhat is the best gift to give a friend who loves the outdoors?|im_end|\n|im_start|assistant\nOoh, thats a fun question!! If youre looking for some gift ideas for a friend who loves the outdoors, I suggest National Parks Pass, Hammock, or Portable Camping Chair! |im_end|, ] test_batch tokenizer( test_list, paddingTrue, padding_sideleft, return_tensorspt).to(device) test_rewards rm( input_idstest_batch[input_ids], attention_masktest_batch[attention_mask], ) df pd.DataFrame({ text: test_list, score: test_rewards.squeeze(-1).tolist() }) dftextscore0|im_start|user\nWhat do you most want to do ...-2.6406251|im_start|user\nWhat do you most want to do ...5.4062502|im_start|user\nWhat is the best gift to giv...3.5156253|im_start|user\nWhat is the best gift to giv...5.437500这样的话价值模型就训练好了。

相关新闻

Unity 小白必看:Event Trigger 组件全解析!对比 Button / 射线检测,一文搞懂

Unity 小白必看:Event Trigger 组件全解析!对比 Button / 射线检测,一文搞懂

刚学 Unity 的小伙伴大概率会遇到这些困惑: 想给 Image、Text 这类非 Button 的 UI 加点击效果,却不知道咋弄? 给 3D 立方体、2D 精灵加点击交互,试了 Button 没用,纯手写射线检测又看不懂? 分不清 Event Trigger、Button 的 Click、射线检测到底有啥区别,该啥时候用? …

2026/7/12 0:50:43 阅读更多 →
ChatGPT秒回的秘密?Transformer架构深度解析,不看后悔!

ChatGPT秒回的秘密?Transformer架构深度解析,不看后悔!

本文以通俗易懂的方式解释了Transformer架构的核心原理,包括注意力机制、词向量与位置编码、多头注意力等关键概念。文章通过图书馆借书的类比,详细阐述了Transformer如何理解文本信息,并说明了为何ChatGPT等AI应用能高效处理语言任务。Trans…

2026/7/13 15:35:30 阅读更多 →
2026服装门店收银系统选购指南:五款主流软件深度对比

2026服装门店收银系统选购指南:五款主流软件深度对比

当Z世代消费者习惯了“线上下单、门店试穿、跨店退换”的无缝购物体验,传统收银软件正在成为服装零售进化的瓶颈。一套优秀的POS系统,早已超越了扫码收银的范畴,它既是门店的“智慧大脑”,也是连接品牌全渠道资源的“神经末梢”。…

2026/7/12 8:57:59 阅读更多 →

最新新闻

主流PC同步软件深度横评:从WebDAV实战到多协议支持

主流PC同步软件深度横评:从WebDAV实战到多协议支持

1. 为什么我们需要专业的文件同步软件?在日常工作和生活中,我们经常需要在不同设备之间同步文件。你可能遇到过这样的场景:在办公室电脑上修改了一个文档,回家后想在笔记本上继续工作,却发现文件版本不对。这时候&…

2026/7/15 18:02:02 阅读更多 →
从0到1:使用zram-generator构建Linux内存优化方案

从0到1:使用zram-generator构建Linux内存优化方案

从0到1:使用zram-generator构建Linux内存优化方案 【免费下载链接】zram-generator Systemd unit generator for zram devices 项目地址: https://gitcode.com/gh_mirrors/zr/zram-generator zram-generator是一款强大的Systemd单元生成器,专为创…

2026/7/15 18:02:02 阅读更多 →
CPU/GPU/NPU/TPU选型实战指南:按场景匹配AI算力芯片

CPU/GPU/NPU/TPU选型实战指南:按场景匹配AI算力芯片

1. 这不是芯片参数表,而是一份AI算力演进的实战地图你打开任何一家大厂的AI产品页,页面上总在跳动着几个缩写字母:CPU、GPU、NPU、TPU。它们被并列放在“硬件加速支持”一栏里,像四块不同颜色的积木,拼出“高性能AI推理…

2026/7/15 17:59:59 阅读更多 →
Pie语言类型检查器原理解析:如何保证程序的数学正确性

Pie语言类型检查器原理解析:如何保证程序的数学正确性

Pie语言类型检查器原理解析:如何保证程序的数学正确性 【免费下载链接】pie The Pie language, which accompanies The Little Typer by Friedman and Christiansen 项目地址: https://gitcode.com/gh_mirrors/pie2/pie Pie语言作为《The Little Typer》一书…

2026/7/15 17:57:59 阅读更多 →
终极指南:如何使用TradingView Webhooks Bot构建自动化交易系统

终极指南:如何使用TradingView Webhooks Bot构建自动化交易系统

终极指南:如何使用TradingView Webhooks Bot构建自动化交易系统 【免费下载链接】tradingview-webhooks-bot a framework 🏗 for trading with tradingview webhooks! 项目地址: https://gitcode.com/gh_mirrors/tr/tradingview-webhooks-bot 在当…

2026/7/15 17:53:56 阅读更多 →
RC舵机蓝牙无线调参系统:从PID控制到多舵机协同应用

RC舵机蓝牙无线调参系统:从PID控制到多舵机协同应用

这次我们来看一个特别实用的开源项目——RC舵机蓝牙调参系统。对于玩RC漂移车、舵机云台的朋友来说,传统的调参方式需要反复连接电脑或使用专用调试器,而这个项目通过蓝牙模块实现了无线调参,让调试过程更加便捷高效。这个项目的核心价值在于…

2026/7/15 17:53:56 阅读更多 →

日新闻

YOLO11 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

YOLO11 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

前言 本文介绍了面向红外小目标检测的时空特征融合模块——STFFM,用于增强复杂背景下目标与噪声、杂波的区分能力。该方法通过拼接空间特征与时间/运动特征,并结合通道注意力、空间注意力和残差增强机制,实现对关键语义通道与疑似目标区域的…

2026/7/15 0:01:00 阅读更多 →
YOLO26 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

YOLO26 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

前言 本文介绍了面向复杂背景小目标检测的时空特征融合模块——STFFM。该模块通过空间分支与时间/运动分支的特征拼接,引入通道注意力和空间注意力对融合特征进行自适应筛选,并结合残差增强与通道压缩,突出目标区域、抑制背景噪声。我们将 S…

2026/7/15 0:01:00 阅读更多 →
行星减速机为什么能提高扭矩?从功率守恒到输出扭矩校核

行星减速机为什么能提高扭矩?从功率守恒到输出扭矩校核

一、为什么减速以后扭矩会增大 旋转机械的功率、转速和扭矩之间存在以下关系: T 9550 P n 其中: T为扭矩,单位Nm; P为功率,单位kW; n为转速,单位r/min。 在功率基本不变的情况下:…

2026/7/15 0:03:00 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/14 16:53:23 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/14 14:00:13 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/15 17:52:08 阅读更多 →

月新闻