0
点赞
收藏
分享

微信扫一扫

opencv-图像基础变换

前行的跋涉者 2024-08-04 阅读 34

目录

在这里插入图片描述

动机

一个好的模型需要对你输入数据的扰动 鲁棒

    使用有噪音的数据等价于Tikhnov正则
    丢弃法:在层之间加入噪音




无偏差的加入噪音

假设x是一层到下一层的输入的话
对x加入噪音得到 x ′ x^{'} x。我们希望
在这里插入图片描述
(即:虽然我们加入了噪音,但不要改变我们的期望,即这个值还是对的)


丢弃法对每个元素进行如下扰动
在这里插入图片描述
也可以这样表示
在这里插入图片描述

一部分概率变成0,一部分数据变大(其中p∈(0,1))

期望没有变化
在这里插入图片描述


使用丢弃法

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

在这里插入图片描述

h 2 h_2 h2 h 5 h_5 h5被换成0了。


推理中的丢弃法

正则项只在训练中使用(这是因为dropout是一个正则项,它只会对权重有影响,当进行预测的时候权重不需要发生变化情况,是不需要正则的):它们影响模型参数的更新。
在推理过程中,丢弃法直接返回输入

在这里插入图片描述
这样也能保证确定性的输出




总结

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




从零开始实现

Dropout

    要实现单层的暂退法函数, 我们从均匀分布 𝑈[0,1] 中抽取样本,样本数与这层神经网络的维度一致。 然后我们保留那些对应样本大于 𝑝 的节点,把剩下的丢弃
    在下面的代码中,(我们实现 dropout_layer 函数, 该函数以dropout的概率丢弃张量输入X中的元素), 如上所述重新缩放剩余部分:将剩余部分(h)除以1.0-dropout。

在这里插入图片描述

import torch
from torch import nn
from d2l import torch as d2l
 
 
def dropout_layer(X, dropout):
	# 断言检查
    assert 0 <= dropout <= 1
    # 在本情况中,所有元素都被丢弃
    if dropout == 1:
        return torch.zeros_like(X)
    # 在本情况中,所有元素都被保留
    if dropout == 0: 
        return X
    # 生成一个与输入张量形状相同的掩码 mask
    # 对于掩码中的每个元素:都是基于随机数生成的
    # 随机数> dropout 概率,对应的掩码元素为 1;随机数≤ dropout 概率,对应的掩码元素为 0。
    mask = (torch.rand(X.shape) > dropout).float()
    # 将mask与x进行元素级乘法,只保留x中被掩码标记为1的元素,然后除以1-dropout以抵消由于丢弃部分元素而引起的整体缩放效果。
    # 确保训练过程中神经元的期望输出都保持不变。
    return mask * X / (1.0 - dropout)

我们可以通过下面几个例子来测试dropout_layer函数。 我们将输入X通过暂退法操作,暂退概率分别为0、0.5和1。

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.))

输出:
在这里插入图片描述




定义模型参数

引入Fashion-MNIST数据集,定义具有两个隐藏层的多层感知机,每个隐藏层包含256个单元。

num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256



定义模型

    可以将暂退法应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率
    常见的技巧是在靠近输入层的地方设置较低的暂退概率。 下面的模型将第一个和第二个隐藏层的暂退概率分别设置为0.2和0.5, 并且暂退法只在训练期间有效

dropout1, dropout2 = 0.2, 0.5
 
class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,is_training = True):
        # super()调用父类的一个方法,确保了nn.Module的初始化方法被执行
        super(Net, self).__init__()
        self.num_inputs = num_inputs
        self.training = is_training
        # 用于输入层到第一个隐藏层的连接
        self.lin1 = nn.Linear(num_inputs, num_hiddens1)
        self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.lin3 = nn.Linear(num_hiddens2, num_outputs)
        # 将负值置为0,保留正值不变
        self.relu = nn.ReLU()
 	# 前向传播
    def forward(self, X):
    	# -1表示自动计算,这里指batch_size大小
        H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
        # 只有在训练模型时才使用dropout
        if self.training == True:
            # 在第一个全连接层之后添加一个dropout层
            H1 = dropout_layer(H1, dropout1)
        # H2是经过线性变换和非线性激活处理后的特征表示,它被用作后续层的输入。
        H2 = self.relu(self.lin2(H1))
        if self.training == True:
            # 在第二个全连接层之后添加一个dropout层
            H2 = dropout_layer(H2, dropout2)
        # 计算神经网络中最后一个线性层的输出
        out = self.lin3(H2)
        return out
 
 
net = 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)



代码实现

import torch
from torch import nn
from d2l import torch as d2l


class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True):
        # super()调用父类的一个方法,确保了nn.Module的初始化方法被执行
        super(Net, self).__init__()
        self.num_inputs = num_inputs
        self.training = is_training
        # 用于输入层到第一个隐藏层的连接
        self.lin1 = nn.Linear(num_inputs, num_hiddens1)
        self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.lin3 = nn.Linear(num_hiddens2, num_outputs)
        # 将负值置为0,保留正值不变
        self.relu = nn.ReLU()

    # 前向传播
    def forward(self, X):
        # -1表示自动计算,这里指batch_size大小
        H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
        # 只有在训练模型时才使用dropout
        if self.training == True:
            # 在第一个全连接层之后添加一个dropout层
            H1 = dropout_layer(H1, dropout1)
        # H2是经过线性变换和非线性激活处理后的特征表示,它被用作后续层的输入。
        H2 = self.relu(self.lin2(H1))
        if self.training == True:
            # 在第二个全连接层之后添加一个dropout层
            H2 = dropout_layer(H2, dropout2)
        # 计算神经网络中最后一个线性层的输出
        out = self.lin3(H2)
        return out


def dropout_layer(X, dropout):
    # 断言检查
    assert 0 <= dropout <= 1
    # 在本情况中,所有元素都被丢弃
    if dropout == 1:
        return torch.zeros_like(X)
    # 在本情况中,所有元素都被保留
    if dropout == 0:
        return X
    # 生成一个与输入张量形状相同的掩码 mask
    # 对于掩码中的每个元素:都是基于随机数生成的
    # 随机数> dropout 概率,对应的掩码元素为 1;随机数≤ dropout 概率,对应的掩码元素为 0。
    mask = (torch.rand(X.shape) > dropout).float()
    # 将mask与x进行元素级乘法,只保留x中被掩码标记为1的元素,然后除以1-dropout以抵消由于丢弃部分元素而引起的整体缩放效果。
    # 确保训练过程中神经元的期望输出都保持不变。
    return mask * X / (1.0 - dropout)


num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
net = 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)
d2l.plt.show()

在这里插入图片描述

这里不使用丢弃法,即将参数置为0.

dropout1, dropout2 = 0.2, 0.5

在这里插入图片描述

dropout是正则用来防止过拟合的,这里不用dropout之后损失更小,说明过拟合程度加深了

简洁代码实现

对于深度学习框架的高级API,我们只需在每个全连接层之后添加一个Dropout层, 将暂退概率作为唯一的参数传递给它的构造函数。 在训练时,Dropout层将根据指定的暂退概率随机丢弃上一层的输出(相当于下一层的输入)。 在测试时,Dropout层仅传递数据。

import torch
from torch import nn
from d2l import torch as d2l


def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)


num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
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)

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))

net.apply(init_weights)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
d2l.plt.show()

在这里插入图片描述




问题

①dropout随机置0对求梯度和反向传播的影响是什么?
梯度也是0

②丢弃法的丢弃依据是什么?如果丢弃不合理对输出的结果影响会很大?
丢弃不合理是指丢弃率没设置好,要么太小了,对模型的正则效果不大,还是过拟合,要么就是过大(欠拟合)

③丢弃法是在训练中把神经元丢弃后训练,在与测试时网络中的神经元没有丢弃是这样吗?
是的

④丢弃法是每次迭代一次,随机丢弃一次吗?
是的,每一层调用前向运算时随机丢一次。

⑤⭐推理中dropout是直接返回输入吗?
是的,在做预测的时候(不对权重进行更新的时候)不用dropout。因为dropout是一个正则项,正则项唯一的作用是更新权重的时候让你的模型复杂度变得低一点点。在做推理的时候,不会更新模型的复杂度,不更新模型,所以不需要dropout。

⑥dropout函数返回值的表达式return X*mask/(1.0-p)没被丢弃的输入部分的值会因为表达式分母(1-p)的存在而改变,而训练数据的标签还是原来的值。

⑦训练时用dropout,推理时不用,那会不会导致推理时输出结果翻倍了?
不假设在训练的时候dropout=0.5,就是把一半的神经元设成0,剩下的要除以0.5(1-p,这里的p为0.5)也就是乘以2.所以在训练的过程中期望是不会发生变化的,

举报

相关推荐

0 条评论