【学习笔记】Pytorch深度学习—正则化之Dropout

本节主要内容主要分为两大部分,(1)Dropout概念;(2)Dropout注意事项

Dropout概念

Dropout指随机失活:
1、随机:dropout probability, 指有一定的概率使得神经元失去活性;
2、失活:weight=0,神经元权重为0,相当于该神经元不存在。

在这里插入图片描述
如上图所示的(a)为标准神经网络结构,也就是全连接网络,其结构特点是:每1个神经元都会与前1层的所有神经元进行连接,故为全连接;(b)为带有dropout的神经网络,一些神经元失去活性,权值为0,与前一层的神经元没有联系。
Dropout操作、实现简单,依据一定的概率让一部分神经元失活,这就可以让神经元学习到更鲁棒的特征,减轻过度的依赖性从而缓解了过拟合,降低方差达到正则化效果;此外,这一dropout失活操作使得模型更加多样化,因为每1次进行前向传播,这些神经元都是随机失活,所训练得到的模型都是不同的。

为什么这一失活操作就可以达到良好的正则化效果呢?
(1)如下图所示,从对特征依赖性角度看,Dropout操作解除了神经元对某一特征的过度依赖性,提高了特征的鲁棒性,实现了正则化:
在这里插入图片描述
(2)如下图所示,从数值角度看,假如某个神经元所有权重之和为5,对前一层神经元输出值的关注度可能为均分,即对前一层神经元输出值的关注度为5个1,因此不会对某个特征值过度依赖,就像考试还有10天考试,画了10道题,平均到1天复习1道题…平均的分散下去,类似L2正则化对权重数值尺度进行约束


Dropout注意事项

数据尺度变化
神经网络模型在训练过程中,存在训练和测试:
1)在训练阶段,选择每一层的神经元进行失活,每个神经元被选中的概率为drop_prob;
2)但在测试时,数据恢复正常规模,需要对所有权重乘以1-drop_prob,
drop_prob=0.3,1-drop_prob=0.7

解释:
在这里插入图片描述

1)没有随机失活时的全连接网络中神经元的数据尺度(即数据规模恢复正常、测试集情况):
假如神经元a的上一层有100个神经元,相当于有100个w乘以100个x,假设1个w乘以1个x为1,那么尺度为100;

2)在训练时,存在随机失活时神经元的数据尺度:
如果以drop_prob=0.3进行drop,说明有30%的神经元会被失活、权值为0,仅剩下70项wx,那么尺度为70;

3)问题产生
在训练时,都有30%神经元会被舍弃,神经元数值的尺度为70,尺度被缩小。但测试时,数据恢复、所有神经元都会存在,尺度变为100,这就导致模型存在精度差异,所以测试时,权值都需乘以1-drop_pro,从而保证数据尺度在训练和测试时保持一致。

Pytorch中提供的nn.Dropout
torch.nn.Dropout(p=0.5,inplace=False)
功能:Dropout层
参数:p被舍弃概率,失活概率

实验

代码来自余老师

// 一元线性回归模型,主要代码架构与L2正则化相同,共分为5步:
//(1)gen_data进行数据构造;
# =========== step 1/5 数据 ==========
def gen_data(num_data=10, x_range=(-1, 1)):

    w = 1.5
    train_x = torch.linspace(*x_range, num_data).unsqueeze_(1)
    train_y = w*train_x + torch.normal(0, 0.5, size=train_x.size())
    test_x = torch.linspace(*x_range, num_data).unsqueeze_(1)
    test_y = w*test_x + torch.normal(0, 0.3, size=test_x.size())

    return train_x, train_y, test_x, test_y


train_x, train_y, test_x, test_y = gen_data(x_range=(-1, 1))


# =========== step 2/5 模型 =========
// 模型_init_中由 Sequential 组建模型
class MLP(nn.Module):
    def __init__(self, neural_num, d_prob=0.5):
        super(MLP, self).__init__()
        self.linears = nn.Sequential(

            nn.Linear(1, neural_num),
            nn.ReLU(inplace=True),
//放置Dropout的位置:应当在需要 Dropout的网络层的前一行
            nn.Dropout(d_prob),//前一行
            nn.Linear(neural_num, neural_num), //需要失活
            nn.ReLU(inplace=True),

            nn.Dropout(d_prob),
            nn.Linear(neural_num, neural_num),
            nn.ReLU(inplace=True),
// 通常,输出层是不加 Dropout的,这里由于一元线性模型比较简单,
// 所以添加了,可以观察:AlexNet模型、VGG模型在输出层之前都是
// 没有添加Dropout的

            nn.Dropout(d_prob),
            nn.Linear(neural_num, 1),
        )
//由于使用sequential,所以可以一步实现forward
    def forward(self, x):
        return self.linears(x)
// 定义后 MLP 这一个类后,构建 2个模型:(1)失活概率为0,不带Dropout(2)失活概率为0.5
net_prob_0 = MLP(neural_num=n_hidden, d_prob=0.)
net_prob_05 = MLP(neural_num=n_hidden, d_prob=0.5)

# ========== step 3/5 优化器 =========
optim_normal = torch.optim.SGD(net_prob_0.parameters(), lr=lr_init, momentum=0.9)
optim_reglar = torch.optim.SGD(net_prob_05.parameters(), lr=lr_init, momentum=0.9)

# ======== step 4/5 损失函数 ======
loss_func = torch.nn.MSELoss()

# ======= step 5/5 迭代训练 =======

// 注意:由于Dropout在训练、测试阶段操作的功能有所不同,
//因为训练阶段每1个神经元会以一定的概率失活,而在测试阶
//段每1个神经元都会保持存在,所以需要对网络设置状态(net.eval函数)

writer = SummaryWriter(comment='_test_tensorboard', filename_suffix="12345678")
for epoch in range(max_iter):

    pred_normal, pred_wdecay = net_prob_0(train_x), net_prob_05(train_x)
    loss_normal, loss_wdecay = loss_func(pred_normal, train_y), loss_func(pred_wdecay, train_y)

    optim_normal.zero_grad()
    optim_reglar.zero_grad()

    loss_normal.backward()
    loss_wdecay.backward()

    optim_normal.step()
    optim_reglar.step()

    if (epoch+1) % disp_interval == 0:
//需要对网络实行 net_x.eval函数,该函数表示设置当前网络
//即将采用测试状态,
        net_prob_0.eval()
        net_prob_05.eval()

        # 可视化
        for name, layer in net_prob_0.named_parameters():
            writer.add_histogram(name + '_grad_normal', layer.grad, epoch)
            writer.add_histogram(name + '_data_normal', layer, epoch)

        for name, layer in net_prob_05.named_parameters():
            writer.add_histogram(name + '_grad_regularization', layer.grad, epoch)
            writer.add_histogram(name + '_data_regularization', layer, epoch)

        test_pred_prob_0, test_pred_prob_05 = net_prob_0(test_x), net_prob_05(test_x)

        # 绘图
        plt.scatter(train_x.data.numpy(), train_y.data.numpy(), c='blue', s=50, alpha=0.3, label='train')
        plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='red', s=50, alpha=0.3, label='test')
        plt.plot(test_x.data.numpy(), test_pred_prob_0.data.numpy(), 'r-', lw=3, label='d_prob_0')
        plt.plot(test_x.data.numpy(), test_pred_prob_05.data.numpy(), 'b--', lw=3, label='d_prob_05')
        plt.text(-0.25, -1.5, 'd_prob_0 loss={:.8f}'.format(loss_normal.item()), fontdict={'size': 15, 'color': 'red'})
        plt.text(-0.25, -2, 'd_prob_05 loss={:.6f}'.format(loss_wdecay.item()), fontdict={'size': 15, 'color': 'red'})

        plt.ylim((-2.5, 2.5))
        plt.legend(loc='upper left')
        plt.title("Epoch: {}".format(epoch+1))
        plt.show()
        plt.close()
//使用完测试,即将训练时一定把网络状态设置回 net.train
        net_prob_0.train()
        net_prob_05.train()

结果:
(1)功能1:Dropout可以降低方差


(2)功能2:类似L2,控制权重尺度,通过tensorboard观察fc层权重的histogram。
在这里插入图片描述

问题1:
设置net.eval和net.train如何能使得迭代过程分别进入测试和训练状态?

eval函数

// A code block
 def eval(self):

       return self.train(False)

train函数

 def train(self, mode=True):
      self.training = mode
      for module in self.children():
            module.train(mode)
      return self

train、eval函数其实质是对 Module的1个属性 “.training” 进行设置、管理:
如果是.traning 的mode设置为True,表示模型即将进入训练状态
如果是.traning 的mode设置为False,表示模型即将进入测试状态

问题2:
Pytorch中对于控制数据尺度保持一致的实现细节
Pytorch在训练时就对权重均除以1-drop_prob,测试时不再作权值放大调整操作,从而降低了测试复杂度、加快测试速度。


  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

又青。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值