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 相关文章推荐
举例介绍Python中的25个隐藏特性
Mar 30 Python
python如何对实例属性进行类型检查
Mar 20 Python
PyQt5每天必学之像素图控件QPixmap
Apr 19 Python
Python中偏函数用法示例
Jun 07 Python
Python爬虫包BeautifulSoup简介与安装(一)
Jun 17 Python
Python魔法方法详解
Feb 13 Python
pandas 时间格式转换的实现
Jul 06 Python
关于pytorch处理类别不平衡的问题
Dec 31 Python
在Tensorflow中查看权重的实现
Jan 24 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
Apr 01 Python
Pytorch 使用不同版本的cuda的方法步骤
Apr 02 Python
python 实现Requests发送带cookies的请求
Feb 08 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
动画 《Pokemon Sword·Shield》系列WEB动画《薄明之翼》第2话声优阵容公开!
2020/03/06 日漫
PHP.MVC的模板标签系统(一)
2006/09/05 PHP
php使用curl访问https示例分享
2014/01/17 PHP
PHP中key和current,next的联合运用实例分析
2016/03/29 PHP
[原创]PHPCMS遭遇会员投稿审核无效的解决方法
2017/01/11 PHP
修改file按钮的默认样式实现代码
2013/04/23 Javascript
使用jQuery不判断浏览器高度解决iframe自适应高度问题
2014/12/16 Javascript
javascript实现淡蓝色的鼠标拖动选择框实例
2015/05/09 Javascript
基于JavaScript实现Json数据根据某个字段进行排序
2015/11/24 Javascript
js获取鼠标位置实例详解
2015/12/09 Javascript
jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载)
2016/02/25 Javascript
js图片加载效果实例代码(延迟加载+瀑布流加载)
2017/05/12 Javascript
jQuery实现左右滑动的toggle方法
2018/03/03 jQuery
微信小程序实现换肤功能
2018/03/14 Javascript
Angularjs中date过滤器失效的问题及解决方法
2018/07/06 Javascript
vue-cli3全面配置详解
2018/11/14 Javascript
微信小程序实现的点击按钮 弹出底部上拉菜单功能示例
2018/12/20 Javascript
高效jQuery选择器的5个技巧实例分析
2019/11/26 jQuery
[00:34]TI7不朽珍藏III——纯金地穴编织者饰品展示
2017/07/15 DOTA
Python 第一步 hello world
2009/09/25 Python
Python中针对函数处理的特殊方法
2014/03/06 Python
python复制文件的方法实例详解
2015/05/22 Python
Python采集代理ip并判断是否可用和定时更新的方法
2018/05/07 Python
浅述python2与python3的简单区别
2018/09/19 Python
基于Python3.6中的OpenCV实现图片色彩空间的转换
2020/02/03 Python
python GUI库图形界面开发之PyQt5中QWebEngineView内嵌网页与Python的数据交互传参详细方法实例
2020/02/26 Python
利用python生成照片墙的示例代码
2020/04/09 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
Python Http请求json解析库用法解析
2020/11/28 Python
SKECHERS官方旗舰店:美国舒适运动休闲品牌
2017/12/22 全球购物
联想韩国官网:Lenovo Korea
2018/05/10 全球购物
七一表彰活动方案
2014/01/18 职场文书
2014年征兵标语
2014/06/20 职场文书
公司开业主持词
2015/07/02 职场文书
MySQL之select、distinct、limit的使用
2021/11/11 MySQL
Java 超详细讲解IO操作字节流与字符流
2022/03/25 Java/Android