PyTorch 实现L2正则化以及Dropout的操作


Posted in Python onMay 27, 2021

了解知道Dropout原理

如果要提高神经网络的表达或分类能力,最直接的方法就是采用更深的网络和更多的神经元,复杂的网络也意味着更加容易过拟合。

于是就有了Dropout,大部分实验表明其具有一定的防止过拟合的能力。

用代码实现Dropout

PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作

Dropout的numpy实现

PyTorch 实现L2正则化以及Dropout的操作

PyTorch中实现dropout

PyTorch 实现L2正则化以及Dropout的操作

import torch.nn.functional as F
import torch.nn.init as init
import torch
from torch.autograd import Variable
import matplotlib.pyplot as  plt
import numpy as np
import math
%matplotlib inline
#%matplotlib inline 可以在Ipython编译器里直接使用
#功能是可以内嵌绘图,并且可以省略掉plt.show()这一步。
xy=np.loadtxt('./data/diabetes.csv.gz',delimiter=',',dtype=np.float32)
x_data=torch.from_numpy(xy[:,0:-1])#取除了最后一列的数据
y_data=torch.from_numpy(xy[:,[-1]])#取最后一列的数据,[-1]加中括号是为了keepdim
print(x_data.size(),y_data.size())
#print(x_data.shape,y_data.shape)
#建立网络模型
class Model(torch.nn.Module):
    
    def __init__(self):
        super(Model,self).__init__()
        self.l1=torch.nn.Linear(8,60)
        self.l2=torch.nn.Linear(60,4)
        self.l3=torch.nn.Linear(4,1)
        self.sigmoid=torch.nn.Sigmoid()
        self.dropout=torch.nn.Dropout(p=0.5)
        
    def forward(self,x):
        out1=self.sigmoid(self.l1(x))
        out2=self.dropout(out1)
        out3=self.sigmoid(self.l2(out2))
        out4=self.dropout(out3)
        y_pred=self.sigmoid(self.l3(out4))
        return y_pred
    
#our model
model=Model()
criterion=torch.nn.BCELoss(size_average=True)
#optimizer=torch.optim.SGD(model.parameters(),lr=0.1)
optimizer=torch.optim.Adam(model.parameters(),lr=0.1,weight_decay=0.1)
#weight_decay是L2正则
#training loop
Loss=[]
for epoch in range(2000):
    y_pred=model(x_data)
    loss=criterion(y_pred,y_data)
    if epoch%20 == 0:
        print("epoch = ",epoch," loss = ",loss.data)
        
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
        
hour_var = Variable(torch.randn(1,8))
print("predict",model(hour_var).data[0]>0.5)

L2正则化

optimizer=torch.optim.SGD(model.parameters(),lr=0.01,weight_decay=0.001)

补充:PyTorch1.0实现L1,L2正则化以及Dropout (附dropout原理的python实现以及改进)

看代码吧~

# 包
import torch
import torch.nn as nn
import torch.nn.functional as F
# torchvision 包收录了若干重要的公开数据集、网络模型和计算机视觉中的常用图像变换
import torchvision
import torchvision.transforms as transforms  
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

1. 什么是dropout(随机失活)?

1.1 一种Regularization的方法

与L1、L2正则化和最大范式约束等方法互为补充。在训练的时候,dropout的实现方法是让神经元以超参数 p 的概率被激活或者被设置为0。

1.2 在训练过程中

随机失活可以被认为是对完整的神经网络抽样出一些子集,每次基于输入数据只更新子网络的参数(然而,数量巨大的子网络们并不是相互独立的,因为它们都共享参数)。

1.3 在测试过程中不使用随机失活

所有的神经元都激活,**但是对于隐层的输出都要乘以 p **。可以理解为是对数量巨大的子网络们做了模型集成(model ensemble),以此来计算出一个平均的预测。详见:http://cs231n.github.io/neural-networks-2/

1.4 一般在全连接层把神经元置为0

在卷积层中可能把某个通道置为0!

2. 用代码实现regularization(L1、L2、Dropout)

注意:PyTorch中的regularization是在optimizer中实现的,所以无论怎么改变weight_decay的大小,loss会跟之前没有加正则项的大小差不多。这是因为loss_fun损失函数没有把权重W的损失加上!

2.1 L1 regularization

对于每个 ω 我们都向目标函数增加一个λ|ω| 。

L1正则化有一个有趣的性质,它会让权重向量在最优化的过程中变得稀疏(即非常接近0)。也就是说,使用L1正则化的神经元最后使用的是它们最重要的输入数据的稀疏子集,同时对于噪音输入则几乎是不变的了。

相较L1正则化,L2正则化中的权重向量大多是分散的小数字。在实践中,如果不是特别关注某些明确的特征选择,一般说来L2正则化都会比L1正则化效果好。

PyTorch里的optimizer只能实现L2正则化,L1正则化只能手动实现:

regularization_loss = 0
for param in model.parameters():
    regularization_loss += torch.sum(abs(param))
    
calssify_loss = criterion(pred,target)
loss = classify_loss + lamda * regularization_loss
optimizer.zero_grad()
loss.backward()
optimizer.step()

2.2 L2 regularization

对于网络中的每个权重 ω ,向目标函数中增加一个 PyTorch 实现L2正则化以及Dropout的操作其中 λ 是正则化强度。这样该式子关于梯度就是 λω 了。

L2正则化可以直观理解为它对于大数值的权重向量进行严厉惩罚,倾向于更加分散的权重向量。

最后需要注意在梯度下降和参数更新的时候,使用L2正则化意味着所有的权重都以 w += -lambda * W向着0线性下降。

选择一个合适的权重衰减系数λ非常重要,这个需要根据具体的情况去尝试,初步尝试可以使用 1e-4 或者 1e-3

在PyTorch中某些optimizer优化器的参数weight_decay (float, optional)就是 L2 正则项,它的默认值为0。

optimizer = torch.optim.SGD(model.parameters(),lr=0.01,weight_decay=0.001)

2.3 PyTorch1.0 实现 dropout

数据少, 才能凸显过拟合问题, 所以我们就做10个数据点.

torch.manual_seed(1)    # Sets the seed for generating random numbers.reproducible
N_SAMPLES = 20
N_HIDDEN = 300
# training data
x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)
print('x.size()',x.size())
# torch.normal(mean, std, out=None) → Tensor
y = x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))
# test data
test_x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)
test_y = test_x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))
# show data
plt.scatter(x.data.numpy(), y.data.numpy(), c='magenta', s=50, alpha=0.5, label='train')
plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='cyan', s=50, alpha=0.5, label='test')
plt.legend(loc='upper left')
plt.ylim((-2.5, 2.5))
plt.show()
x.size() torch.Size([20, 1])

PyTorch 实现L2正则化以及Dropout的操作

我们现在搭建两个神经网络, 一个没有 dropout, 一个有 dropout. 没有 dropout 的容易出现 过拟合, 那我们就命名为 net_overfitting, 另一个就是 net_dropped.

net_overfitting = torch.nn.Sequential(
    torch.nn.Linear(1,N_HIDDEN),
    torch.nn.ReLU(),
    torch.nn.Linear(N_HIDDEN,N_HIDDEN),
    torch.nn.ReLU(),
    torch.nn.Linear(N_HIDDEN,1),
)
net_dropped = torch.nn.Sequential(
    torch.nn.Linear(1,N_HIDDEN),
    torch.nn.Dropout(0.5), # 0.5的概率失活
    torch.nn.ReLU(),
    torch.nn.Linear(N_HIDDEN,N_HIDDEN),
    torch.nn.Dropout(0.5),
    torch.nn.ReLU(),
    torch.nn.Linear(N_HIDDEN,1),
)

训练模型并测试2个模型的performance

optimizer_ofit = torch.optim.Adam(net_overfitting.parameters(),lr=0.001)
optimizer_drop = torch.optim.Adam(net_dropped.parameters(),lr=0.01)
loss = torch.nn.MSELoss()
for epoch in range(500):
    pred_ofit= net_overfitting(x)
    pred_drop= net_dropped(x)
    
    loss_ofit = loss(pred_ofit,y)
    loss_drop = loss(pred_drop,y)
    
    optimizer_ofit.zero_grad()
    optimizer_drop.zero_grad()
    
    loss_ofit.backward()
    loss_drop.backward()
    
    optimizer_ofit.step()
    optimizer_drop.step()
    
    if epoch%50 ==0 :
        net_overfitting.eval() # 将神经网络转换成测试形式,此时不会对神经网络dropout
        net_dropped.eval() # 此时不会对神经网络dropout
        
        test_pred_ofit = net_overfitting(test_x)
        test_pred_drop = net_dropped(test_x)
        
        # show data
        plt.scatter(x.data.numpy(), y.data.numpy(), c='magenta', s=50, alpha=0.5, label='train')
        plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='cyan', s=50, alpha=0.5, label='test')
        plt.plot(test_x.data.numpy(), test_pred_ofit.data.numpy(), 'r-', lw=3, label='overfitting')
        plt.plot(test_x.data.numpy(), test_pred_drop.data.numpy(), 'b--', lw=3, label='dropout(50%)')
        plt.text(0, -1.2, 'overfitting loss=%.4f' % loss(test_pred_ofit, test_y).data.numpy(), fontdict={'size': 20, 'color':  'red'})
        plt.text(0, -1.5, 'dropout loss=%.4f' % loss(test_pred_drop, test_y).data.numpy(), fontdict={'size': 20, 'color': 'blue'})
        plt.legend(loc='upper left')
        plt.ylim((-2.5, 2.5))
        plt.pause(0.1)
        
        
        net_overfitting.train()
        net_dropped.train()
        
plt.ioff()
plt.show()

一共10张图片就不一一放上来了,取1,4,7,10张吧:

PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作PyTorch 实现L2正则化以及Dropout的操作

3. Dropout的numpy实现(参考斯坦福大学CS231n课程笔记

网上对于为什么dropout后要进行rescale缩放的讨论很多,这里给出斯坦福cs231n课上的解释,个人觉得比较有道理,这里是对普通dropout的改进,使得无论是否使用随机失活,预测方法的代码可以保持不变。

一个3层神经网络的普通版dropout可以用下面代码实现:

""" 普通版随机失活: 不推荐实现  """
p = 0.5 # 激活神经元激活神经元激活神经元(重要的事情说三遍)的概率.   p值更高 = 随机失活更弱
def train_step(X):
    """ X中是输入数据 """
    # 3层neural network的前向传播
    H1 = np.maximum(0, np.dot(W1, X) + b1)
    U1 = np.random.rand(*H1.shape) < p # 第一个dropout mask
    H1 *= U1 # drop!
    H2 = np.maximum(0, np.dot(W2, H1) + b2)
    U2 = np.random.rand(*H2.shape) < p # 第二个dropout mask
    H2 *= U2 # drop!
    out = np.dot(W3, H2) + b3
    # 反向传播:计算梯度... (略)
    # 进行参数更新... (略)
    
def predict(X):
# 前向传播时模型集成
H1 = np.maximum(0, np.dot(W1, X) + b1) * p # 注意:激活数据要乘以p
H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # 注意:激活数据要乘以p
out = np.dot(W3, H2) + b3

上述操作不好的性质是必须在测试时对激活数据要按照 p 进行数值范围调整,我们可以使其在训练时就进行数值范围调整,从而让前向传播在测试时保持不变。

这样做还有一个好处,无论你决定是否使用随机失活,预测方法的代码可以保持不变。这就是反向随机失活(inverted dropout):

"""
inverted dropout(反向随机失活): 推荐实现方式.
在训练的时候drop和调整数值范围,测试时不用任何改变.
"""
p = 0.5 # 激活神经元的概率. p值更高 = 随机失活更弱
def train_step(X):
    # 3层neural network的前向传播
    H1 = np.maximum(0, np.dot(W1, X) + b1)
    U1 = (np.random.rand(*H1.shape) < p) / p # 第一个dropout mask. 注意/p!
    H1 *= U1 # drop!
    H2 = np.maximum(0, np.dot(W2, H1) + b2)
    U2 = (np.random.rand(*H2.shape) < p) / p # 第二个dropout mask. 注意/p!
    H2 *= U2 # drop!
    out = np.dot(W3, H2) + b3
    # 反向传播:计算梯度... (略)
    # 进行参数更新... (略)
    
def predict(X):
# 前向传播时模型集成
H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用数值范围调整了
H2 = np.maximum(0, np.dot(W2, H1) + b2)
out = np.dot(W3, H2) + b3

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用BeautifulSoup爬虫程序获取百度搜索结果的标题和url示例
Jan 19 Python
Python和Ruby中each循环引用变量问题(一个隐秘BUG?)
Jun 04 Python
简单的编程0基础下Python入门指引
Apr 01 Python
Python中为什么要用self探讨
Apr 14 Python
Python环境下安装使用异步任务队列包Celery的基础教程
May 07 Python
基于python的字节编译详解
Sep 20 Python
python使用fork实现守护进程的方法
Nov 16 Python
TensorFlow 模型载入方法汇总(小结)
Jun 19 Python
python文件操作之批量修改文件后缀名的方法
Aug 10 Python
python 实现得到当前时间偏移day天后的日期方法
Dec 31 Python
如何基于python生成list的所有的子集
Nov 11 Python
python opencv图片编码为h264文件的实例
Dec 12 Python
Python开发之QT解决无边框界面拖动卡屏问题(附带源码)
pytorch 实现在测试的时候启用dropout
使用Python脚本对GiteePages进行一键部署的使用说明
教你使用Python pypinyin库实现汉字转拼音
基于tensorflow权重文件的解读
May 26 #Python
解决Python字典查找报Keyerror的问题
浅谈tf.train.Saver()与tf.train.import_meta_graph的要点
You might like
mac下使用brew配置环境的步骤分享
2011/05/23 PHP
PHP中集成PayPal标准支付的实现方法分享
2012/02/06 PHP
使用PHP Socket写的POP3类
2013/10/30 PHP
PHP 用session与gd库实现简单验证码生成与验证的类方法
2016/11/15 PHP
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
2020/04/26 PHP
JAVASCRIPT HashTable
2007/01/22 Javascript
JavaScript 入门·JavaScript 具有全范围的运算符
2007/10/01 Javascript
用jQuery技术实现Tab页界面之二
2009/09/21 Javascript
url 特殊字符 传递参数解决方法
2010/01/01 Javascript
Exjs 入门篇
2010/04/07 Javascript
firefox下frameset取不到值的解决方法
2010/09/06 Javascript
jQuery判断元素上是否绑定了指定事件的方法
2015/03/17 Javascript
js 获取元素所有兄弟节点的实现方法
2016/09/06 Javascript
关于Function中的bind()示例详解
2016/12/02 Javascript
AngularJS日期格式化常见操作实例分析
2018/05/17 Javascript
原生JS实现的轮播图功能详解
2018/08/06 Javascript
微信小程序使用map组件实现路线规划功能示例
2019/01/22 Javascript
JS实现随机点名器
2020/04/12 Javascript
[01:19:11]Ti4 循环赛第二日 NaVi.us vs iG
2014/07/11 DOTA
Python的Django框架中的数据过滤功能
2015/07/17 Python
python 线程的暂停, 恢复, 退出详解及实例
2016/12/06 Python
python实现应用程序在右键菜单中添加打开方式功能
2017/01/09 Python
Python动刷新抢12306火车票的代码(附源码)
2018/01/24 Python
Win7 64位下python3.6.5安装配置图文教程
2020/10/27 Python
anaconda3安装及jupyter环境配置全教程
2020/08/24 Python
python开发一款翻译工具
2020/10/10 Python
京东奢侈品:全球奢侈品牌
2018/03/17 全球购物
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
北卡罗来纳州豪华家具和家居装饰店:Carolina Rustica
2018/10/30 全球购物
Cecil Mode法国在线商店:女性时尚
2021/01/08 全球购物
实习评语
2013/12/16 职场文书
公司优秀员工获奖感言
2014/08/14 职场文书
预备党员转正材料
2014/12/19 职场文书
财务工作失误检讨书
2015/02/19 职场文书
2015年度班主任自我评价
2015/03/11 职场文书
SpringBoot整合阿里云视频点播的过程详解
2021/12/06 Java/Android