跟着李沐老师学习深度学习(七)

devtools/2025/2/13 20:56:08/

权重衰退 + 丢弃法

权重衰退(Weight Decay)

回忆:如何控制一个模型的容量(方法1:把模型变得比较小;方法2:使得模型参数的选择范围比较小)
是一种正则化模型的技术;

使用均方范数作为硬性限制

  • 通过限制参数值的选择范围来控制模型的容量
    在这里插入图片描述
    (最小化损失的时候,限制权重向量 w 的范数平方不能超过 θ)
    • 通常不限制偏移b(限不限制都差不多)
    • 小的 θ 意味着更强的正则项
    • 直观解释理解: θ 确实是把w限制在一个范围里面,但实际上使用以下的柔性限制。

使用均方范数作为柔性限制

  • 对每个 θ ,都可以找到 λ 使得之前的目标函数等价于下面:
    在这里插入图片描述
    • 可以通过拉格朗日乘子来证明
  • 超参数λ控制了正则项的重要程度
    • λ = 0:无作用
    • λ → ∞,w* → 0

对最优解的影响

在这里插入图片描述
理解:橙色是惩罚项:lamda/2*||w||平方的图像,绿色是原来损失函数的图像;曲线代表损失函数,有几个圈就是对不同的w来说,一个圈对应一个参数,最中间的点是参数的最优解。
大概应该就是:新的损失函数由两项组成,此时求导后,梯度有两项了,一项将w向绿线中心拉,一项将w向原点拉进,最后将在w*点达到一个平衡

  • 参数更新法则

  • 计算梯度
    在这里插入图片描述

  • 时间 t 更新参数
    在这里插入图片描述

    • 通常 nλ<1,在深度学习中通常叫做权重衰退
    • 主要变化:先把当前的值 缩小再 沿着负梯度方向学习

总结

  • 权重衰退通过L2 正则项使得模型参数不会过大,从而控制模型复杂度
  • 正则项权重是控制模型复杂度的超参数。

代码实现- 从零实现

# 权重衰退# 像之前一样 导入相关包
import torch
from torch import nn
from d2l import torch as d2l# 像以前一样生成一些数据:
# ![image.png](attachment:image.png)# 将训练数据设置的很小(当训练数据比较少的时候容易 过拟合)
n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
# 生成一个数据集
train_data = d2l.synthetic_data(true_w, true_b, n_train)
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False)# 从零开始实现#下面我们将从头开始实现权重衰减,只需将 𝐿2 的平方惩罚添加到原始目标函数中def init_params():w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)b = torch.zeros(1, requires_grad=True)return [w, b]# 定义L2范数惩罚
# 实现这一惩罚最方便的方法是对所有项求平方后并将它们求和
def l2_penalty(w):return torch.sum(w.pow(2)) / 2# 定义训练代码实现:
def train(lambd):w,b = init_params()# 定义了一个线性回归模型,net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_lossnum_epochs, lr = 100, 0.003animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',xlim=[5, num_epochs], legend=['train', 'test'])for epoch in range(num_epochs):for X, y in train_iter:# 增加了L2范数惩罚项# 广播机制使 l2_penalty(w) 成为了长度为batch_size的向量l = loss(net(X), y) + lambd * l2_penalty(w) # 唯一的区别l.sum().backward()d2l.sgd([w, b], lr, batch_size)if (epoch + 1) % 5 == 0:animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),d2l.evaluate_loss(net, test_iter, loss)))print('w的L2范数是:', torch.norm(w).item())# 忽略正则化进行训练
train(lambd = 0)
# 这里训练误差有了减少,但测试误差没有减少, 这意味着出现了严重的过拟合。# 使用权重衰退进行 训练
train(lambd=3)
# 这里 训练误差增大,但测试误差减小;

忽略正则化得到的结果:
在这里插入图片描述
当没有进行正则化的时候,训练误差有了减少,但测试误差没有减少, 这意味着出现了严重的过拟合

使用权重衰退得到的结果:
在这里插入图片描述
可以看出:过拟合有一定的缓解;可能经过多次迭代会得到更好的效果;
也可以进行将lambd调整更大一些,效果会更好;(或者增加迭代次数)
在这里插入图片描述

代码- 简洁实现

# 简洁实现
def train_concise(wd):net = nn.Sequential(nn.Linear(num_inputs, 1))for param in net.parameters():param.data.normal_()loss = nn.MSELoss(reduction='none')num_epochs, lr = 100, 0.003# 偏置参数没有衰减trainer = torch.optim.SGD([{"params": net[0].weight, 'weight_decay': wd},{"params": net[0].bias}], lr=lr)animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',xlim=[5, num_epochs], legend=['train', 'test'])for epoch in range(num_epochs):for X, y in train_iter:trainer.zero_grad()l = loss(net(X), y)l.mean().backward()trainer.step()if (epoch + 1) % 5 == 0:animator.add(epoch + 1,(d2l.evaluate_loss(net, train_iter, loss),(d2l.evaluate_loss(net, test_iter, loss))))print('w的L2范数是:', net[0].weight.norm().item())
  • 训练:不加权重衰退 train_concise(0)
    在这里插入图片描述

  • 加权重衰退 train_concise(3)

在这里插入图片描述
由以上结果可以看到结果和之前是差不多的。

丢弃法(dropout)

动机

  • 一个好的模型需要对输入数据的扰动鲁棒
    • 使用噪音的数据等价于Tikhonov 正则
    • 丢弃法:在层之间加入噪音
      (输入数据加入随机扰动可以防止过拟合,泛化性更好,等价于一种正则方法。现在对噪音的添加方式从输入位置放到了层间位置)

无偏差的加入噪音

  • 对x加入噪音得到x’, 我们希望(不改变期望):
    在这里插入图片描述

  • 丢弃法对每个元素进行如下扰动:(给定一个概率p)
    在这里插入图片描述

为什么要出一个1-p: 对向量的每个元素操作,每个元素都有p的概率变为0,又有1-p的概率变成它的1/(1-p),这样才能保持期望不变

使用丢弃法

  • 通常将丢弃法作用在隐藏全连接层的输出上
    在这里插入图片描述

推理中的丢弃法

  • 正则项只在训练中使用:他们影响模型参数的更新
  • 在推理中,丢弃法直接返回输入:
    在这里插入图片描述
    • 这样保证确定性的输出

比较正则化的实验结果,因此丢弃法可看作是正则化方法;

总结

  • 丢弃法将一些输出项随机置0控制模型复杂度
  • 常作用在多层感知机的隐藏层输出
  • 丢弃概率是控制模型复杂度的超参数

代码实现

# Dropoutimport torch 
from torch import nn
from d2l import torch as d2ldef dropout_layer(X, dropout):assert 0 <= dropout <= 1# 在本情况中,所有元素都被丢弃if dropout == 1:return torch.zeros_like(X)# 在本情况中,所有元素都被保留if dropout == 0:return Xmask = (torch.randn(X.shape) > dropout).float()# mask 是一个与输入张量 X 形状相同的浮点类型张量,其中元素的值要么是 1.0,要么是 0.0return mask * X / (1.0 - dropout)# 测试dropout_layer函数
X= torch.arange(16, dtype = torch.float32).reshape((2, 8))
print(X)
print(dropout_layer(X, 0.))
print(dropout_layer(X, 0.5))
print(dropout_layer(X, 1.))# 定义模型参数num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256# 将暂退法应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率:
# 常见的技巧是在靠近输入层的地方设置较低的暂退概率。 dropout1, dropout2 = 0.2, 0.5class Net(nn.Module):def __init__(self, num_inputs, num_outputs, num_hiddend1, num_hiddens2,is_training=True):super(Net, self).__init__()self.num_inputs = num_inputsself.training = is_trainingself.lin1 = nn.Linear(num_inputs, num_hiddens1)self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)self.lin3 = nn.Linear(num_hiddens2, num_outputs)self.relu = nn.ReLU()def forward(self, X):H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))# 只有在训练模型的时候才使用dropoutif self.training == True:# 在第一个全连接层之后添加一个dropout层H1 = dropout_layer(H1, dropout1)H2 = self.relu(self.lin2(H1))if self.training == True:# 在第二个全连接层之后添加一个dropout层H2 = dropout_layer(H2, dropout2)out = self.lin3(H2)return outnet = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)# 训练和测试
# 相当于之前的多层感知机的训练:
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss(reduction='none')
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
  • 结果:
    在这里插入图片描述

  • 使用 dropout 都是0 的情况:
    在这里插入图片描述

代码-简洁实现


# 简洁实现
# 只需在每个全连接层之后添加一个Dropout层, 将暂退概率作为唯一的参数传递给它的构造函数。net = nn.Sequential(nn.Flatten(),nn.Linear(784, 256),nn.ReLU(),# 在第一个全连接层之后添加一个dropout层nn.Dropout(dropout1),nn.Linear(256, 256),nn.ReLU(),# 在第二个全连接层之后添加一个dropout层nn.Dropout(dropout2),nn.Linear(256, 10))def init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)net.apply(init_weights);# 训练和测试
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

总结:dropout主要是针对过拟合问题的,这个模型没有过拟合所以没必要简化模型。


http://www.ppmy.cn/devtools/158586.html

相关文章

【注意】sql语句where条件中的数据类型不一致,不仅存在性能问题,还会有数据准确性方面的bug......

隐式类型转换规则 MySQL 在进行比较操作时&#xff0c;如果比较双方的数据类型不一致&#xff0c;通常会尝试将其中一个数据类型转换为另一个数据类型&#xff0c;以便进行比较。 对于 select * from t_order where order_no 1538808276987285507 &#xff0c;当 order_no 为 …

自学人工智能大模型,满足7B模型的训练和微调以及推理,预算3万,如何选购电脑

如果你的预算是 3万元人民币&#xff0c;希望训练和微调 7B 参数规模的人工智能大模型&#xff08;如 LLaMA、Mistral 等&#xff09;&#xff0c;你需要一台高性能的深度学习工作站。在这个预算范围内&#xff0c;以下是推荐的配置&#xff1a; 1. 关键硬件配置 (1) GPU (显卡…

124 巨坑uni-app踩坑事件 uniCloud本地调试服务启动失败

1.事情是这样的 事情是这样的&#xff0c;我上午在运行项目的时候还是好好的&#xff0c;我什么都没干&#xff0c;没动代码&#xff0c;没更新&#xff0c;就啥也没干&#xff0c;代码我也还原成好好的之前的样子&#xff0c;就报这个错&#xff0c;但是我之前没用过这个服务呀…

C++STL容器之map的使用及复现

map 1. 关联式容器 vector、list、deque、forward_list(C11) 等STL容器&#xff0c;其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身&#xff0c;这样的容器被统称为序列式容器。而 map、set 是一种关联式容器&#xff0c;关联式容器也是用来存储数据的&#xf…

ES6 Proxy 用法总结以及 Object.defineProperty用法区别

Proxy 是 ES6 引入的一种强大的拦截机制&#xff0c;用于定义对象的基本操作&#xff08;如读取、赋值、删除等&#xff09;的自定义行为。相较于 Object.defineProperty&#xff0c;Proxy 提供了更灵活、全面的拦截能力。 1. Proxy 语法 const proxy new Proxy(target, hand…

DeepSeek开源多模态大模型Janus-Pro部署

DeepSeek多模态大模型部署 请自行根据电脑配置选择合适环境配置安装conda以及gitJanus 项目以及依赖安装运行cpu运行gpu运行 进入ui界面 请自行根据电脑配置选择合适 本人家用电脑为1060&#xff0c;因此部署的7B模型。配置高的可以考虑更大参数的模型。 环境配置 安装conda…

【CubeMX-HAL库】STM32F407—无刷电机学习笔记

目录 简介&#xff1a; 学习资料&#xff1a; 跳转目录&#xff1a; 一、工程创建 二、板载LED 三、用户按键 四、蜂鸣器 1.完整IO控制代码 五、TFT彩屏驱动 六、ADC多通道 1.通道确认 2.CubeMX配置 ①开启对应的ADC通道 ②选择规则组通道 ③开启DMA ④开启ADC…

docker中mysql修改宿主机挂载文件my.cnf中修改mysql端口号不生效

/usr/sbin/mysqld: ready for connections. Version: ‘8.0.33’ socket: ‘/var/run/mysqld/mysqld.sock’ port: 3306 MySQL Community Server - GPL. 这说明 MySQL 内部仍然使用默认端口 3306&#xff0c;你的 my.cnf 可能没有生效。 解决方案 确保 my.cnf 正确配置了端口…