Dropout丢弃法如何实现及其原理

简介: Dropout丢弃法如何实现及其原理

Dropout丢弃法是为了防止模型过拟合,它会每个批次随机的将部分数据置为0,在网络传递的过程不起任何作用,经过多个批次的dropout的作用形成最终的模型参数

失活一定的权重就不会造成过拟合,缺少部分权重的影响导致模型的容量变小,进而本次学习的任务不会过多,不会学习到个别的噪音

我们假设有一个向量为X=[x1,x2,x3,x4,x5]

丢弃法虽然会将一部分数据置为0,但是它不会改变数据的期望

我们假设丢弃的概率为p

现在的期望就变成了E(x1)=0*p+(1-p)*x1/(1-p)=x1

可以看到并不会发生改变

而且有一个地方,经常有的图会标记,dropout就是让每个隐藏层的部分节点失活不发生作用,我感觉应该是不对的,dropout是将部分数据进行置为0,那么说明失活的应该是层与层之间的权重连线,应该是部分权重不起作用了,而不是整个神经元全部失活

因为每次的传播都会选择性失活一定的权重,如果第一次某个权重不起作用,它可能在第二次的传播中进行更新权重,经过多个epoch即不同批次的迭代,每个权重都会被训练到

import torch
import torch.nn as nn
import torchvision
from torchvision import transforms
from torch.utils import data
# 将图片数据转化成张量
data_transform=transforms.ToTensor()
# 加载图片数据集
train_dataset=torchvision.datasets.FashionMNIST(root='./data',train=True,download=False,transform=data_transform)
val_dataset=torchvision.datasets.FashionMNIST(root='./data',train=False,download=False,transform=data_transform)
batch_size=128
# 加载批次数据
train_loader=data.DataLoader(train_dataset,batch_size,shuffle=True)
val_loader=data.DataLoader(val_dataset,batch_size,shuffle=False)

从零实现Dropout

这里定义dropout函数

如果是0,说明不丢弃任何数据,返回原数据

如果为1,则说明全部丢弃,返回同样形状的0矩阵

否则随机生成一个符合标准正态分布的随机张量,然后按位置进行判断和概率p的大小

然后将布尔张量转化成浮点,即1.0或0.0

之后将每个位置的值进行相应的改变,丢弃的就变为0,否则将其放大(除以1-p)

def dropout(x,p):
    if p==0:
        return x
    if p==1:
        return torch.zeors_like(x)
    mask=torch.randn_like(x).gt(p).float()
    return mask*x/(1-p)

定义模型需要指定是否使用dropout,在forward传播函数中进行判断

class Net(nn.Module):
    def __init__(self,is_train):
        super(Net,self).__init__()
        self.is_train=is_train
        self.layer1=nn.Linear(784,256)
        self.layer2=nn.Linear(256,256)
        self.layer3=nn.Linear(256,10)
        self.relu=nn.ReLU()
    def forward(self,x):
        x=x.reshape(-1,784)
        out=self.layer1(x)
        out=self.relu(out)
        if self.is_train:
            out=dropout(out,0.3)
        out=self.layer2(out)
        out=self.relu(out)
        if self.is_train:
            out=dropout(out,0.5)
        out=self.layer3(out)
        return out

定义损失函数为交叉熵

优化器为SGD,且学习率为0.03

然后扫描整个数据集3次

net=Net(True)
loss_function=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),lr=0.03)
epochs=3
for epoch in range(epochs):
    net.train()
    for x,y in train_loader:
        y_hat=net(x)
        loss=loss_function(y_hat,y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    accuracy=0.0
    with torch.no_grad():
        net.eval()
        for x,y in val_loader:
            y_hat=net(x)
            y_pred=torch.argmax(y_hat,dim=1)
            accuracy+=torch.eq(y_pred,y).sum().item()
    accuracy=accuracy/len(val_dataset)
    print('epoch {},accuracy {:.4f},loss {:.4f}'.format(epoch+1,accuracy,loss.item()))
epoch 1,accuracy 0.8254,loss 0.2865
epoch 2,accuracy 0.8447,loss 0.4892
epoch 3,accuracy 0.8438,loss 0.2258

简洁实现

简洁实现较为方便,利用Sequential将各个层与层之间的操作容纳起来

这里在两个隐藏层定义了两个dropout函数

dropout1=0.3
dropout2=0.5
net=nn.Sequential(nn.Flatten(),
                 nn.Linear(784,256),
                 nn.ReLU(),
                 nn.Dropout(dropout1),
                 nn.Linear(256,256),
                 nn.ReLU(),
                 nn.Dropout(dropout2),
                 nn.Linear(256,10))
loss_function=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),lr=0.03)
epochs=3
for epoch in range(epochs):
    net.train()
    for x,y in train_loader:
        y_hat=net(x)
        loss=loss_function(y_hat,y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    accuracy=0.0
    with torch.no_grad():
        net.eval()
        for x,y in val_loader:
            y_hat=net(x)
            y_pred=torch.argmax(y_hat,dim=1)
            accuracy+=torch.eq(y_pred,y).sum().item()
    accuracy=accuracy/len(val_dataset)
    print('epoch {},accuracy {:.4f},loss {:.4f}'.format(epoch+1,accuracy,loss.item()))
epoch 1,accuracy 0.7176,loss 0.7700
epoch 2,accuracy 0.7732,loss 0.6294
epoch 3,accuracy 0.8057,loss 0.5933


目录
相关文章
|
数据采集
PCA与主成分回归(PCR)有何区别?
PCA是降维工具,转化相关变量为线性无关的主成分,保留数据变异。PCR是回归分析方法,利用PCA的主成分预测因变量,应对自变量间的多重共线性,提升模型稳定性。两者协同工作,优化高维数据的建模。
665 0
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
530 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
4月前
|
Java API 开发工具
1688寻原通API接口攻略
1688寻原通API接口攻略涵盖注册申请、开发准备、系统对接、测试调试及上线维护等步骤。开发前需阅读API文档,明确请求参数与响应格式,并选择合适语言(如Python、Java)和工具。对接系统时,注重调用方式与数据格式,确保稳定可靠。其核心功能包括商品采集上传、订单处理及数据同步,助力卖家高效管理跨境电商店铺,实现与1688平台的无缝连接。
|
9月前
|
前端开发 JavaScript UED
React 轮播图组件 Carousel
本文介绍了如何在 React 中实现和优化轮播图组件,涵盖自动播放、手动切换、循环播放和响应式设计等核心功能。通过 `useState` 和 `useEffect` 钩子管理状态和副作用,添加左右箭头和指示器增强交互性。同时,探讨了常见问题如自动播放与手动切换冲突、指示器样式不一致、响应式设计及性能优化,并提供解决方案和代码示例。帮助开发者提升轮播图组件的用户体验。
454 26
|
存储 关系型数据库 MySQL
MySQL 忘记root密码解决方案
【7月更文挑战第19天】
1757 4
|
12月前
|
存储 关系型数据库 MySQL
|
存储 消息中间件 关系型数据库
解密分布式事务:CAP理论、BASE理论、两阶段提交(2PC)、三阶段提交(3PC)、补偿事务(TCC)、MQ事务消息、最大努力通知
解密分布式事务:CAP理论、BASE理论、两阶段提交(2PC)、三阶段提交(3PC)、补偿事务(TCC)、MQ事务消息、最大努力通知
407 0
|
Linux 开发者
关于UOS系统下打包安装使用的问题总结
关于UOS系统下打包安装使用的问题总结
关于UOS系统下打包安装使用的问题总结
|
编译器 C++ Windows
Qt程序运行依赖环境打包方法:windeployqt方法
3分钟学会Qt程序运行依赖环境打包方法:windeployqt方法!
924 0
Qt程序运行依赖环境打包方法:windeployqt方法