机器学习模型调试学习总结

1.学习内容

模型调试方法:冻结部分层,训练剩余层

实践:在一个预训练的 BERT 模型上冻结部分层,并训练剩余的层

模型调试方法:线性探测(Linear Probe)

实践:在一个预训练的 BERT 模型上冻结全部层,只训练最后一层

模型调试方法:适配模块

实践:在BERT模型中添加适配模块

模型调试方法: 软提示

实践:使用软提示来指导生成对话文本

2.总结

冻结部分层,只训练其他层。这有助于降低训练过程中的显存消耗,并能专注于某些特定层的优化。

以这次的实践项目为例,全程只用到了6g多的内存,完全在可以接受的范围内。

具体的实践部分代码,首先我们加载了预训练的模型,之后我们需要进行冻结某些层的操作,调用model.named_parameters()获取模型中的所有参数(weights)及其名称。这个函数返回一个迭代器,它会遍历模型的所有参数及其名称。

对于BERT模型,它有很多层,每一层都有自己的参数(比如权重和偏差)。想要冻结前n层,也就是不更新这些层的参数。通过遍历所有参数,并且通过检查参数的名称来判断它们属于哪一层,可以实现这个目的。最后将模型移动到可用的计算设备上,通常是 GPU,当然我们目前并没有,所以用的还是cpu。

这段代码的作用是在加载预训练的 BERT 模型之后,通过冻结部分参数,只训练模型的后几层,以加速微调过程并提高效果。

下面是模型的其他部分

这段代码是用于设置优化器和计算总步数的。

optimizer = AdamW(model.parameters(), lr=2e-5)

这一行代码创建了一个AdamW优化器对象,用于更新神经网络模型中的参数。在这里,model.parameters() 返回模型中的所有可学习参数,然后将其传递给AdamW优化器。lr=2e-5 指定了学习率(learning rate)为2e-5,这是优化器在更新参数时使用的步长(即每一步更新时参数变化的程度)。这里也可以进行微调。

优化器是一种算法,它根据定义的损失函数和一些超参数(如学习率),来调整网络中每个参数的值,使得损失函数达到最小值,从而让网络的预测结果尽可能接近真实的标签。

AdamW优化器是一种常用的优化器之一。它结合了两个重要的思想:梯度下降和动量。在每一步更新中,AdamW根据当前参数的梯度(即损失函数对参数的变化率)来调整参数的值。同时,它也考虑了之前步骤中参数的移动情况,以便更加高效地更新参数。

学习率是优化器中的一个重要超参数,它决定了每次参数更新的步长。如果学习率设置得太大,可能会导致参数在更新时跳过最优解;而如果学习率设置得太小,收敛速度可能会很慢。

这部分代码主要是设置了学习率调度器(scheduler)和损失函数(loss function)。

scheduler = get_linear_schedule_with_warmup(optimizer,num_warmup_steps=0, num_training_steps=total_steps)这行代码创建了一个学习率调度器,采用了线性学习率调度和预热(warm-up)策略。optimizer 是之前创建的优化器,num_warmup_steps=0 表示预热步数为 0,num_training_steps=total_steps 表示总的训练步数。这个调度器会在训练过程中线性地增加学习率,并在一开始的一部分步数进行预热,有助于训练的稳定和收敛。(这里也可以进行微调。

loss_fn = torch.nn.CrossEntropyLoss().to(device)这行代码创建了一个交叉熵损失函数,用于计算模型预测值和真实标签之间的损失。.to(device) 将损失函数移动到可用的计算设备上。交叉熵损失函数是多分类任务常用的损失函数,适用于我们的文本分类任务。

预热是指在训练初期逐渐增加学习率的过程,有助于训练的稳定和加快收敛速度。

学习率调度器就像是告诉小狗在学习过程中什么时候应该跑得快一点,什么时候应该慢下来。这样可以让它更好地掌握技能,就像你的神奇机器在学习时能够以合适的速度更新它的“知识”。

而预热就像是在小狗开始学习前先稍微热身一下,这样它就能更好地适应学习的环境。在训练开始时给模型一个小小的“预热”,能够让它更快地开始学习。

总的训练步数就像是告诉小狗要学习多久一样。就像告诉小狗学习新技能需要多长时间一样,我们告诉神奇的机器,它需要经过多少次“学习步骤”才能变得更聪明。

这一部分则是训练模型的代码,model = model.train(): 将模型设置为训练模式。这会启用训练模式下的特定功能,例如启用 Dropout 层。

losses = []: 用于存储每个批次的损失值。

correct_predictions = 0: 记录预测正确的样本数量。

for batch in data_loader:: 遍历数据加载器中的每个批次。

input_ids = batch['input_ids'].to(device): 将输入张量移动到指定的设备(例如 GPU)上。

attention_mask = batch['attention_mask'].to(device): 将注意力掩码张量移动到指定的设备上。

labels = batch['label'].to(device): 将标签张量移动到指定的设备上。

outputs = model(input_ids=input_ids, attention_mask=attention_mask): 使用模型进行前向传播,得到预测结果。

_, preds = torch.max(outputs.logits, dim=1): 根据模型的输出,选择概率最大的类别作为预测结果。

loss = loss_fn(outputs.logits, labels): 计算模型预测结果与真实标签之间的损失值。

correct_predictions += torch.sum(preds == labels): 统计预测正确的样本数量。

losses.append(loss.item()): 将本批次的损失值添加到列表中。

loss.backward(): 反向传播计算梯度。

optimizer.step(): 更新模型参数。

scheduler.step(): 更新学习率。

optimizer.zero_grad(): 清空梯度。

return correct_predictions.double() / len(data_loader.dataset), np.mean(losses): 返回每个样本的平均损失和准确率。损失值的平均值表示整个 epoch 的平均损失,准确率表示模型在整个 epoch 中预测正确的样本比例。

前向传播:就像是告诉模型“看这些数据,试着预测一下”。在前向传播过程中,你将数据输入到模型中,让模型通过它的网络结构进行计算,得到预测结果。

反向传播:当模型做出了预测后,我们需要知道它做得有多好,以及如何更新模型的参数来改进预测结果。这就是反向传播的作用。在反向传播中,我们计算模型预测值与真实标签之间的差距(损失值),然后沿着网络逆向传播这个差距,以便调整每个参数,使得损失值最小化。

optimizer.step():更新模型参数:一旦我们通过反向传播计算出了每个参数的梯度(即参数变化的方向),我们就可以使用优化器来更新模型的参数。优化器根据梯度的方向和设定的学习率来更新参数,使得损失值逐渐减小,模型性能逐渐提高。

scheduler.step():更新学习率:学习率是决定模型参数更新步长的重要因素。在训练过程中,我们可能希望随着训练的进行逐渐降低学习率,以便更加精细地调整参数。调度器的作用就是根据预先设定的调度策略来更新学习率。

optimizer.zero_grad():清空梯度:在每次参数更新之前,我们需要清空之前计算的梯度值,以免梯度累积导致更新不准确。这个步骤就是清空模型参数的梯度,以便进行下一轮的梯度计算和更新。

什么是线性探测?

想象一下,你有一个装满了很多层积木的积木塔。每一层积木都有点不同,有的积木是红色的,有的是蓝色的,还有的上面有不同的图案。这个积木塔就像一个训练好的模型,每一层积木就像这个模型的一层。

为什么要用线性探测?

现在,我们想知道这个积木塔的每一层对我们玩一个特别的游戏有多大的帮助。这个游戏可以是猜动物、颜色,或者其他有趣的事情。我们用一种叫做线性探测的方法来看看哪些层对这个游戏最有帮助。

怎么做线性探测?

保持积木塔不变:我们不动积木塔,只是看它的每一层。

提取每一层的信息:我们从积木塔的每一层拿一点信息出来。

用这些信息玩游戏:我们用每一层的信息来玩游戏,看看我们能不能用这些信息做出正确的猜测。

评估效果:我们看看每一层的信息能不能帮助我们在游戏中表现得更好。

一个小例子

假设我们有一个关于动物的游戏,我们的积木塔可以帮我们识别动物。

保持积木塔不变:积木塔已经建好了,我们不动它。

提取信息:我们从积木塔的第一层拿信息出来,看看它能告诉我们什么。然后从第二层拿信息出来,依此类推。

用信息玩游戏:我们用这些信息来猜图片上的动物是什么,比如一只猫或一只狗。

评估效果:我们看看每一层的信息能不能帮助我们正确地猜出动物是什么。

通过这种方法,我们可以知道积木塔的哪一层最聪明,能帮我们最准确地猜出动物。这样,我们就能了解积木塔的每一层对我们玩游戏的帮助有多大。

所以,线性探测就像我们通过每一层积木的信息来玩游戏,看看哪一层的信息最有用。这帮助我们更好地了解积木塔,也就是我们的模型,知道它的每一层都能做些什么。

首先是冻结模型的所有层,

for param in model.parameters():

    param.requires_grad = False

这部分代码将模型中的所有参数设置为不可训练状态。param.requires_grad = False 表示在反向传播时不会计算这些参数的梯度,因此这些参数在训练过程中保持不变。冻结模型的所有层有助于保持预训练模型学到的知识。由于预训练模型已经在大规模数据集上进行了训练,它已经具备了丰富的语言学特征。冻结这些层可以防止在训练过程中丢失这些有用的特征。

model.classifier = nn.Linear(model.config.hidden_size, 2)

model.classifier.weight.requires_grad = True

model.classifier.bias.requires_grad = True

这部分代码将模型的分类器层重新定义为一个新的线性层,并设置为可训练状态。nn.Linear(model.config.hidden_size, 2) 创建一个线性层,输入大小为 model.config.hidden_size(BERT模型的隐藏层大小),输出大小为2(表示二分类任务)。这个线性层将作为模型的新的分类器层,用于预测输入文本的分类标签。通过设置 model.classifier.weight.requires_grad = True 和 model.classifier.bias.requires_grad = True,确保分类器层的权重和偏置参数在训练过程中是可训练的。仅训练分类器层的策略使得模型能够在保持预训练特征的同时,专注于目标任务的特定特征。

criterion = nn.CrossEntropyLoss()

optimizer = optim.AdamW(model.classifier.parameters(), lr=1e-3)

nn.CrossEntropyLoss() 是 PyTorch 提供的交叉熵损失函数,通常用于分类任务,特别是多类分类任务。交叉熵损失函数结合了 softmax 激活函数和负对数似然损失,适用于模型的输出是非归一化的对数几率(logits)。在二分类或多分类任务中,交叉熵损失函数会计算预测的概率分布与真实标签分布之间的差异。

假设有三个类别,模型的输出 logits 为 [2.0, 1.0, 0.1],对应的真实标签为 0(即第一个类别),则交叉熵损失函数会先将 logits 通过 softmax 转换为概率分布 [0.71, 0.26, 0.03],然后计算损失值。

optim.AdamW 是 PyTorch 提供的 AdamW 优化器,这是一种基于 Adam 优化器的变体,具有权重衰减(weight decay)正则化的特点,有助于防止过拟合。

model.classifier.parameters() 表示仅对模型的分类器层的参数进行优化。

lr=1e-3 设置优化器的学习率为 0.001。

权重衰减(Weight Decay):

权重衰减是一种正则化技术,通过在每次参数更新时对权重施加 L2 惩罚,从而防止模型过拟合。AdamW 优化器相比于传统的 Adam 优化器,能够更好地控制权重衰减,从而提高模型的泛化能力。

假设分类器层的参数为 [w1, w2, ..., wn],AdamW 优化器会在每次更新这些

参数时,根据损失函数的梯度和权重衰减项调整参数值,以最小化损失函数。

适配模块是什么?

当你在玩积木,拼图或者搭建模型的时候,你可能会发现有些部分不太合适,需要进行调整,这就像在调试模型一样。适配模块就像是一个特殊的积木块,它可以帮助你把不同的部分连接在一起,使它们更好地适应并协同工作。就像在搭积木时一样,调试模型时的适配模块可以帮助我们解决各种问题,确保整个模型能够正常运行。

class Adapter(nn.Module):

    def __init__(self, input_dim, hidden_dim):

        super(Adapter, self).__init__()

        self.down_project = nn.Linear(input_dim, hidden_dim)

        self.activation = nn.ReLU()

        self.up_project = nn.Linear(hidden_dim, input_dim)

    def forward(self, x):

        x = self.down_project(x)

        x = self.activation(x)

        x = self.up_project(x)

        return x

这段代码定义了一个名为 Adapter 的类,它继承自 nn.Module,这是 PyTorch 中定义神经网络模型的标准方式。Adapter 有两个主要组件:

下投影层 (down_project): 这是一个线性层 (nn.Linear),它将输入的特征维度从 input_dim 缩减到 hidden_dim。这一步可以看作是将输入特征映射到一个更低维度的空间。

激活函数 (activation): 这里使用的是 ReLU 激活函数 (nn.ReLU),它将线性变换后的特征进行非线性映射,增加模型的表达能力。

上投影层 (up_project): 这是另一个线性层,它将特征从 hidden_dim 恢复到 input_dim 的维度。这一步可以看作是对特征进行重建,将低维特征映射回原始特征空间。

在 forward 方法中,输入 x 首先通过下投影层,然后经过激活函数,最后再通过上投影层。最终输出的特征维度与输入相同,但经过了非线性变换。

这个 Adapter 类的作用是将输入的特征进行降维,然后通过非线性映射,最后再恢复到原始的特征空间。

class BertWithAdapters(nn.Module):

    def __init__(self, model_name, adapter_hidden_dim):

        super(BertWithAdapters, self).__init__()

        self.bert = BertModel.from_pretrained(model_name)

        self.adapters = nn.ModuleList([Adapter(self.bert.config.hidden_size, adapter_hidden_dim) for _ in range(self.bert.config.num_hidden_layers)])

       

    def forward(self, input_ids, attention_mask):

        outputs = self.bert(input_ids, attention_mask=attention_mask, output_hidden_states=True)

        hidden_states = outputs.hidden_states

       

        for i, adapter in enumerate(self.adapters):

            hidden_states[i] = hidden_states[i] + adapter(hidden_states[i])

       

        return hidden_states[-1]

这个函数定义了一个新的神经网络模型 BertWithAdapters,它基于预训练的 BERT 模型,但添加了适配器模块。__init__ 方法:这是类的构造方法,在创建 BertWithAdapters 类的实例时调用。在这个方法中,首先调用了 super().__init__() 来初始化父类的构造方法。然后,通过 BertModel.from_pretrained(model_name) 创建了预训练的 BERT 模型,并将其保存在 self.bert 属性中。接着,使用 nn.ModuleList 创建了一个列表 self.adapters,其中包含了多个适配器模块,其数量等于 BERT 模型的隐藏层数量。

forward 方法:这是模型的前向传播方法,定义了数据从输入到输出的流程。在这个方法中,首先调用了 BERT 模型 (self.bert) 对输入数据进行处理,并将输出保存在 outputs 中。然后,从 outputs 中提取出所有隐藏状态,即 hidden_states。接下来,通过遍历所有隐藏状态并分别应用相应的适配器模块,对隐藏状态进行调整。具体地,对每一层的隐藏状态应用对应的适配器模块,得到调整后的隐藏状态。最后,返回调整后的最后一个隐藏状态,作为整个模型的输出。

这个函数的主要作用是创建一个基于预训练的 BERT 模型的新模型,该新模型在每一层都添加了一个适配器模块,用于对隐藏状态进行调整。

软提示是什么?

在模型调试中,软提示是指向模型提供的一种提示或指导,以帮助模型生成更加准确或符合预期的输出。软提示通常是一种文本形式,向模型提供了一些上下文或指示,以便模型在生成文本、回答问题或执行其他任务时更好地理解用户的意图或期望。

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

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

相关文章

crossover软件安装显示程序错误 crossover中文字体下载失败 运行exe乱码 crossover怎么运行软件

虽然Mac用户一直在不断的增加,但是很多人因为习惯了使用Windows系统上的软件,让他们在使用Mac时,也想照常使用Windows上的软件。借助系统兼容工具CrossOver,则可以便捷地在Mac中跨系统使用Windows系统下的应用和文件。 CrossOver…

深度学习入门

文章目录 深度学习基础前言深度学习应用计算机视觉 神经网络基础得分函数 f(x,W)损失函数Softmax分类器前向传播反向传播神经网络整体架构过拟合的解决办法激活函数 深度学习基础 前言 机器学习流程: 数据获取特征工程建立模型评估与应用 特征工程的作用&#x…

高考试卷押运车视频监控解决方案

一、引言 高考作为我国教育领域的重要事件,其公正、公平和安全性一直备受社会关注。试卷押运作为高考的重要环节,其安全性直接关系到高考的顺利进行和考生的切身利益。因此,对高考试卷押运车实施视频监控解决方案,对于确保试卷安…

蓝桥杯练习系统(算法训练)ALGO-935 互质数个数

资源限制 内存限制:256.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 互质数个数 问题描述 已知正整数x,求1~x-1中,有多少与x互质的数。(互质是指两个数最大公约数为1&…

PieCloudDB Database Flink Connector:让数据流动起来

面对客户环境中长期运行的各种类型的传统数据库,如何优雅地设计数据迁移的方案,既能灵活地应对各种数据导入场景和多源异构数据库,又能满足客户对数据导入结果的准确性、一致性、实时性的要求,让客户平滑地迁移到 PieCloudDB 数据…

arco design表单label和输入框的空间分布

表单空间分布 arco利用的栅格系统来实现label、input的大小分布 <a-form :model"formData.form" :label-col-props"{ span: 6 }" :wrapper-col-props"{ span: 18 }" >// 其它...... </a-form>栅格系统中&#xff0c;默认空间总量2…

FreeRtos进阶——通用链表的实现方式

通用链表实现方式&#xff08;一&#xff09; struct node_t {struct node_t *next; };struct person {struct node_t node;char *name;int age; };struct dog {struct node_t node;char *name;int age;char *class; };在此链表中&#xff0c;node结构体被放在了最前面&#x…

【一百零一】【算法分析与设计】差分,1109. 航班预订统计,P4231 三步必杀,P5026 Lycanthropy

1109. 航班预订统计 这里有 n 个航班&#xff0c;它们分别从 1 到 n 进行编号。 有一份航班预订表 bookings &#xff0c;表中第 i 条预订记录 bookings[i] [first(i), last(i), seats(i)] 意味着在从 first(i) 到 last(i) &#xff08;包含 first(i) 和 last(i) &#xff09;…

瑞吉外卖项目学习笔记(一)

项目展示&#xff1a; 一、软件开发整体介绍 1.1 软件开发流程 作为软件开发人员&#xff0c;我们的主要工作是在 编码阶段 1.2 角色分工 1.3 软件环境 二、瑞吉外面项目介绍 2.1 项目介绍 系统管理后台页面&#xff1a; 移动端页面&#xff1a; 2.2 产品原型展示 产品原型是…

STM32学习问题总结(1)—CubeMX生成后下载无反应

在CubeMX生成项目后&#xff0c;写好代码&#xff0c;测试LED时发现怎么都不行&#xff0c;然后发现时Keil工程配置的问题 第一步&#xff1a; 打开Keil魔术棒的Debug下的Settings 第二步&#xff1a; 勾选Flash Download下的Reset and Run即可 被卡了两个小时&#xff0c;…

洗地机什么牌子好?洗地机前十名排行榜

现代吸拖扫一体洗地机不仅高效&#xff0c;还具有智能化设计&#xff0c;使清洁变得轻松。它强大的吸尘功能能够轻松应对灰尘和碎屑&#xff0c;不论是硬质地面还是地毯&#xff0c;都能提供理想的清洁效果。配合拖地功能&#xff0c;通过内置水箱和智能拖布&#xff0c;能彻底…

国产飞腾/龙芯/瑞芯微芯片在信创行业应用:金融行业、教育行业、党政机关

党政机构 方案背景&#xff1a; 在国家提出信息技术应用创新发展战略的大环境下&#xff0c;政务大厅需要基于国家科技自主技术深入推进“互联网政务服务”。加快建设全国一体化在线政务服务平台&#xff0c;进一步落实创新驱动发展战略&#xff0c;提升政务网络安全保障能力…

NATS-研究学习

NATS-研究学习 文章目录 NATS-研究学习[toc]介绍说明提供的服务内容各模式介绍测试使用发布订阅&#xff08;Publish Subscribe&#xff09;请求响应&#xff08;Request Reply&#xff09;队列订阅&分享工作&#xff08;Queue Subscribers & Sharing Work&#xff09;…

运放的自激振荡问题

运放的自激振荡指的是当运算放大器加电后&#xff0c;在没有外部信号输入的情况下&#xff0c;输出端会出现高频类似于正弦波的波形。 运算放大器产生自激的原因以及解决办法-CSDN博客 a)当振荡由分布电容、电感等引起时&#xff0c;可通过反馈端并联电容&#xff0c;抵消影响…

【开源】课程管理平台 JAVA+Vue.js+SpringBoot+MySQL

目录 一、项目介绍 课程管理模块 作业题目模块 考试阅卷模块 教师评价模块 部门角色菜单模块 二、项目截图 三、核心代码 一、项目介绍 Vue.jsSpringBoot前后端分离新手入门项目《课程管理平台》&#xff0c;包括课程管理模块、作业题目模块、考试阅卷模块、教师评价模…

spoon工具的安装与配置

spoon对应的jdk包下载资源地址 spoon软件下载资源地址 首先需要安装jdk&#xff0c;配置java环境&#xff0c;安装好后&#xff0c;cmd一下&#xff0c;查看java -version&#xff0c;看看是否成功安装&#xff0c;如果失败&#xff0c;查看系统环境变量&#xff0c;去配置jdk…

Java | Leetcode Java题解之第122题买卖股票的最佳时机II

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProfit(int[] prices) {int ans 0;int n prices.length;for (int i 1; i < n; i) {ans Math.max(0, prices[i] - prices[i - 1]);}return ans;} }

Python保存为json中文Unicode乱码解决json.dump()

保存为json中文Unicode乱码&#xff1a; 可以看到&#xff0c;中文字符没有乱码&#xff0c;只是出现了反斜杠&#xff0c;此时解决方法应考虑是否进行了二次序列化。 一、原因1 在dump时加入ensure_asciiFalse 即可解决&#xff0c;即json.dump(json_data, f, indent4, en…

阿里云布置net core 项目

一、 创建镜像 给镜像添加触发器&#xff0c;编译的时候会触发k8s集群里的taget链接&#xff0c;从而更新项目 二&#xff0c;创建k8s集群 使用镜像创建 添加基本信息 镜像名称&#xff1a;镜像仓库》基本信息公网地址镜像Tag:创建镜像时的镜像版本镜像配置为&#xff1a;总…

opencv笔记(13)—— 停车场车位识别

一、所需数据介绍 car1.h5 是训练后保存的模型 class_directionary 是0&#xff0c;1的分类 二、图像数据预处理 对输入图片进行过滤&#xff1a; def select_rgb_white_yellow(self,image): #过滤掉背景lower np.uint8([120, 120, 120])upper np.uint8([255, 255, 255])#…