一文搞懂 卷积神经网络 批归一化 丢弃法

简介: 这篇文章详细介绍了卷积神经网络中的批归一化(Batch Normalization)和丢弃法(Dropout),包括它们的计算过程、作用、优势以及如何在飞桨框架中应用这些技术来提高模型的稳定性和泛化能力,并提供了网络结构定义和参数计算的示例。

批归一化(Batch Normalization)

批归一化方法(Batch Normalization,BatchNorm)是由Ioffe和Szegedy于2015年提出的,已被广泛应用在深度学习中,其目的是对神经网络中间层的输出进行标准化处理,使得中间层的输出更加稳定

通常我们会对神经网络的数据进行标准化处理,处理后的样本数据集满足均值为0,方差为1的统计分布,这是因为当输入数据的分布比较固定时,有利于算法的稳定和收敛。对于深度神经网络来说,由于参数是不断更新的,即使输入数据已经做过标准化处理,但是对于比较靠后的那些层,其接收到的输入仍然是剧烈变化的,通常会导致数值不稳定,模型很难收敛。BatchNorm能够使神经网络中间层的输出变得更加稳定,并有如下三个优点:

  • 使学习快速进行(能够使用较大的学习率
  • 降低模型对初始值的敏感
  • 从一定程度上抑制过拟合

BatchNorm主要思路是在训练时以mini-batch为单位,对神经元的数值进行归一化,使数据的分布满足均值为0,方差为1。具体计算过程(有点像计算标准正态分布)如下:

1. 计算mini-batch内样本的均值

2. 计算mini-batch内样本的方差

3. 计算标准化之后的输出

  • 读者可以自行验证由 x ^ ( 1 ) , x ^ ( 2 ) , x ^ ( 3 ) 构成的mini-batch,是否满足均值为0,方差为1的分布。

如果强行限制输出层的分布是标准化的,可能会导致某些特征模式的丢失,所以在标准化之后,BatchNorm会紧接着对数据做缩放和平移

上面列出的是BatchNorm方法的计算逻辑,下面针对两种类型的输入数据格式分别进行举例。飞桨支持输入数据的维度大小为2、3、4、5四种情况,这里给出的是维度大小为2和4的示例。

  • 示例一: 当输入数据形状是 [ N , K ]时,一般对应全连接层的输出,示例代码如下所示。

这种情况下会分别对K的每一个分量计算N个样本的均值和方差,数据和参数对应如下:

  • 输入 x, [N, K]
  • 输出 y, [N, K]
  • 均值 μ B,[K, ]
  • 方差 σ B ², [K, ]
  • 缩放参数 γ, [K, ]
  • 平移参数 β, [K, ]

In [ ]

# 输入数据形状是 [N, K]时的示例
import numpy as np
import paddle
from paddle.nn import BatchNorm1D
# 创建数据
data = np.array([[1,2,3], [4,5,6], [7,8,9]]).astype('float32')
# 使用BatchNorm1D计算归一化的输出
# 输入数据维度[N, K],num_features等于K
bn = BatchNorm1D(num_features=3)    
x = paddle.to_tensor(data)
y = bn(x)
print('output of BatchNorm1D Layer: \n {}'.format(y.numpy()))
# 使用Numpy计算均值、方差和归一化的输出
# 这里对第0个特征进行验证
a = np.array([1,4,7])
a_mean = a.mean()
a_std = a.std()
b = (a - a_mean) / a_std
print('std {}, mean {}, \n output {}'.format(a_mean, a_std, b))
# 建议读者对第1和第2个特征进行验证,观察numpy计算结果与paddle计算结果是否一致
  • 示例二: 当输入数据形状是 [ N , C , H , W ]时, 一般对应卷积层的输出,示例代码如下所示

这种情况下会沿着C这一维度进行展开,分别对每一个通道计算N个样本中总共N×H×W个像素点的均值和方差,数据和参数对应如下:

  • 输入 x, [N, C, H, W]
  • 输出 y, [N, C, H, W]
  • 均值 μ B,[C, ]
  • 方差 σ B², [C, ]
  • 缩放参数 γ, [C, ]
  • 平移参数 β, [C, ]

小窍门:

可能有读者会问:“BatchNorm里面不是还要对标准化之后的结果做仿射变换吗,怎么使用Numpy计算的结果与BatchNorm算子一致?” 这是因为BatchNorm算子里面自动设置初始值γ=1,β=0,这时候仿射变换相当于是恒等变换。在训练过程中这两个参数会不断的学习,这时仿射变换就会起作用。


# 输入数据形状是[N, C, H, W]时的batchnorm示例
import numpy as np
import paddle
from paddle.nn import BatchNorm2D
# 设置随机数种子,这样可以保证每次运行结果一致
np.random.seed(100)
# 创建数据
data = np.random.rand(2,3,3,3).astype('float32')
# 使用BatchNorm2D计算归一化的输出
# 输入数据维度[N, C, H, W],num_features等于C
bn = BatchNorm2D(num_features=3)
x = paddle.to_tensor(data)
y = bn(x)
print('input of BatchNorm2D Layer: \n {}'.format(x.numpy()))
print('output of BatchNorm2D Layer: \n {}'.format(y.numpy()))
# 取出data中第0通道的数据,
# 使用numpy计算均值、方差及归一化的输出
a = data[:, 0, :, :]
a_mean = a.mean()
a_std = a.std()
b = (a - a_mean) / a_std
print('channel 0 of input data: \n {}'.format(a))
print('std {}, mean {}, \n output: \n {}'.format(a_mean, a_std, b))
# 提示:这里通过numpy计算出来的输出
# 与BatchNorm2D算子的结果略有差别,
# 因为在BatchNorm2D算子为了保证数值的稳定性,
# 在分母里面加上了一个比较小的浮点数epsilon=1e-05

- 预测时使用BatchNorm

上面介绍了在训练过程中使用BatchNorm对一批样本进行归一化的方法,但如果使用同样的方法对需要预测的一批样本进行归一化,则预测结果会出现不确定性

例如样本A、样本B作为一批样本计算均值和方差,与样本A、样本C和样本D作为一批样本计算均值和方差,得到的结果一般来说是不同的。那么样本A的预测结果就会变得不确定,这对预测过程来说是不合理的。

解决方法是在训练过程中将大量样本的均值和方差保存下来,预测时直接使用保存好的值而不再重新计算

实际上,在BatchNorm的具体实现中,训练时会计算均值和方差的移动平均值。在飞桨中,默认是采用如下方式计算:

BatchNorm的变体包括:层归一化(Layer Normalization, LN)、组归一化(Group Normalization, GN)、实例归一化(Instance Normalization, IN),通过下图进行比较,

其中N知batch size、H和W分别表示特征图的高度和宽度、C表示特征图的通道数,蓝色像素表示使用相同的均值和方差进行归一化:

图14:归一化方法

  • LN:对[C,W,H]维度求均值方差进行归一化,即在通道方向做归一化,与batch size大小无关,在小batch size上效果可能更好
  • GN:先对通道方向进行分组,然后每个组内对[ C i C_{i} ,W,H]维度进行归一化,也与batch size大小无关
  • IN:只对[H,W]维度进行归一化,图像风格化任务适合使用IN算法

图14来源于Yuxin Wu, Kaiming He,Group Normalization

丢弃法(Dropout)

丢弃法(Dropout)是深度学习中一种常用的抑制过拟合的方法,其做法是在神经网络学习过程中,随机删除一部分神经元。训练时,随机选出一部分神经元,将其输出设置为0,这些神经元将不对外传递信号

图15是Dropout示意图,左边是完整的神经网络,右边是应用了Dropout之后的网络结构。应用Dropout之后,会将标了×的神经元从网络中删除,让它们不向后面的层传递信号。在学习过程中,丢弃哪些神经元是随机决定,因此模型不会过度依赖某些神经元,能一定程度上抑制过拟合。

图15 Dropout示意图

在预测场景时,会向前传递所有神经元的信号,可能会引出一个新的问题:训练时由于部分神经元被随机丢弃了,输出数据的总大小会变小。比如:计算其L1范数会比不使用Dropout时变小,但是预测时却没有丢弃神经元,这将导致训练和预测时数据的分布不一样。为了解决这个问题,飞桨支持如下两种方法:

  • downscale_in_infer

训练时以比例r随机丢弃一部分神经元,不向后传递它们的信号;预测时向后传递所有神经元的信号,但是将每个神经元上的数值乘以(1- r)

  • upscale_in_train

训练时以比例p随机丢弃一部分神经元,不向后传递它们的信号,但是将那些被保留的神经元上的数值除以(1−p);预测时向后传递所有神经元的信号,不做任何处理。

在飞桨Dropout API中,通过mode参数来指定用哪种方式对神经元进行操作,

paddle.nn.Dropout(p=0.5, axis=None, mode="upscale_in_train”, name=None)

主要参数如下:

  • p (float) :将输入节点置为0的概率,即丢弃概率,默认值:0.5。该参数对元素的丢弃概率是针对于每一个元素而言,而不是对所有的元素而言。举例说,假设矩阵内有12个数字,经过概率为0.5的dropout未必一定有6个零。
  • mode(str) :丢弃法的实现方式,有'downscale_in_infer'和'upscale_in_train'两种,默认是'upscale_in_train'。

说明:

不同框架对于Dropout的默认处理方式可能不同,读者可以查看API详细了解。


下面这段程序展示了经过Dropout之后输出数据的形式。

从上述代码的输出可以发现,经过dropout之后,tensor中的某些元素变为了0,这个就是dropout实现的功能,通过随机将输入数据的元素置0,消除减弱了神经元节点间的联合适应性,增强模型的泛化能力。

Dropout的变体有很多,如:DropConnect、Standout、Gaussian Dropout、Spatial Dropout、Cutout、Max-Drop、RNNDrop、循环Drop等,下面简单介绍其中几种算法:

  • DropConnect是由L. Wan等人提出,没有直接在神经元上应用dropout,而是在连接神经元的权重和偏置上应用,只能应用在全连接层
  • Standout是由L. J. Ba和B. Frey提出,第 i i 层丢弃一部分神经元的概率 p p 不是恒定的,根据权重的值,是自适应的,权重越大被丢弃的概率也越大
  • Spatial Dropout是由 J. Tompson等人提出,考虑相邻像素之间的高度相关性,不再进行单个像素进行dropout,而是在特征图上进行dropout
  • Cutout是由T. DeVries和G. W. Taylor提出,通过对图像的隐藏区域进行泛化从而防止过拟合,提高神经网络的鲁棒性(指系统或者器件在不同的环境或者条件下,能够保持其功能或者性能的特性******)******和整体性能

小结

学习完这些概念,您就具备了搭建卷积神经网络的基础。下一节,我们将应用这些基础模块,一起完成图像分类中的典型应用 — 医疗图像中的眼疾筛查任务的模型搭建。

作业

1 计算卷积中一共有多少次乘法和加法操作

输入数据形状是[10,3,224,224],卷积核k_h = k_w = 3,输出通道数为6464,步幅stride=1,填充p_h = p_w = 1。

则完成这样一个卷积,一共需要做多少次乘法和加法操作?

  • 提示

先看输出一个像素点需要做多少次乘法和加法操作,然后再计算总共需要的操作次数。

  • 提交方式

请回复乘法和加法操作的次数,例如:乘法1000,加法1000

2 计算网络层的输出数据和参数的形状

网络结构定义如下面的代码所示,输入数据形状是[10,3,224,224],

请分别计算每一层的输出数据形状,以及各层包含的参数形状

In [ ]

# 定义 SimpleNet 网络结构
import paddle
from paddle.nn import Conv2D, MaxPool2D, Linear
import paddle.nn.functional as F
class SimpleNet(paddle.nn.Layer):
    def __init__(self, num_classes=1):
        #super(SimpleNet, self).__init__(name_scope)
        self.conv1 = Conv2D(in_channels=3, out_channels=6, kernel_size=5, stride=1, padding=2)
        self.max_pool1 = MaxPool2D(kernel_size=2, tride=2)
        self.conv2 = Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=2)
        self.max_pool2 = MaxPool2D(kernel_size=2, tride=2)
        self.fc1 = Linear(in_features=50176, out_features=64)
        self.fc2 = Linear(in_features=64, out_features=num_classes)        
    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.max_pool1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.max_pool2(x)
        x = paddle.reshape(x, [x.shape[0], -1])
        x = self.fc1(x)
        x = F.sigmoid(x)
        x = self.fc2(x)
        return x
  • 提示,第一层卷积 c o n v 1 conv1 ,各项参数如下:

输出特征图的形状是[N,Cout,Hout,Wout]=[10,6,224,224]

请将下面的表格补充完整:

名称

w形状

w参数个数

b形状

b参数个数

输出形状

conv1

[6,3,5,5]

450

[6]

6

[10, 6, 224, 224]

pool1

[10, 6, 112, 112]

conv2

pool2

fc1

fc2

  • 提交方式:将表格截图发到讨论区

靠《填充》那章下面的公式:Hout=H+ph1+ph2−kh+1、Wout=W+pw1+pw2−kw+1

pool和fc都不会做

本节以上一节介绍的ResNet来完成眼疾识别任务为例,介绍一个基本的计算机视觉任务研发全流程,主要涵盖如下内容:

  • 基本的计算机视觉任务研发全流程:介绍基本的计算机视觉任务研发全流程。
  • 眼疾数据集:介绍数据集结构及数据预处理方法。
  • ResNet网络:如何应用眼疾数据集进行模型训练和测试。
相关文章
|
18天前
|
机器学习/深度学习 计算机视觉 Python
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力本文提出了一种简单且高效的卷积神经网络(ConvNets)注意力模块——SimAM。与现有模块不同,SimAM通过优化能量函数推断特征图的3D注意力权重,无需添加额外参数。SimAM基于空间抑制理论设计,通过简单的解决方案实现高效计算,提升卷积神经网络的表征能力。代码已在Pytorch-SimAM开源。
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络:从理论到实践
【10月更文挑战第35天】在人工智能的浪潮中,深度学习技术以其强大的数据处理能力成为科技界的宠儿。其中,卷积神经网络(CNN)作为深度学习的一个重要分支,在图像识别和视频分析等领域展现出了惊人的潜力。本文将深入浅出地介绍CNN的工作原理,并结合实际代码示例,带领读者从零开始构建一个简单的CNN模型,探索其在图像分类任务中的应用。通过本文,读者不仅能够理解CNN背后的数学原理,还能学会如何利用现代深度学习框架实现自己的CNN模型。
|
10天前
|
机器学习/深度学习 人工智能 算法框架/工具
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第36天】探索卷积神经网络(CNN)的神秘面纱,揭示其在图像识别领域的威力。本文将带你了解CNN的核心概念,并通过实际代码示例,展示如何构建和训练一个简单的CNN模型。无论你是深度学习的初学者还是希望深化理解,这篇文章都将为你提供有价值的见解。
|
21天前
|
机器学习/深度学习 监控 自动驾驶
卷积神经网络有什么应用场景
【10月更文挑战第23天】卷积神经网络有什么应用场景
28 2
|
21天前
|
机器学习/深度学习 自然语言处理 算法
什么是卷积神经网络
【10月更文挑战第23天】什么是卷积神经网络
28 1
|
24天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
71 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
11天前
|
机器学习/深度学习 人工智能 自动驾驶
深入解析深度学习中的卷积神经网络(CNN)
深入解析深度学习中的卷积神经网络(CNN)
27 0
|
14天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第32天】本文将介绍深度学习中的一个重要分支——卷积神经网络(CNN),以及其在图像识别领域的应用。我们将通过一个简单的代码示例,展示如何使用Python和TensorFlow库构建一个基本的CNN模型,并对其进行训练和测试。
|
20天前
|
机器学习/深度学习 自然语言处理 TensorFlow
深度学习中的卷积神经网络(CNN)及其应用
【10月更文挑战第26天】在这篇文章中,我们将深入探讨卷积神经网络(CNN)的基本原理、结构和应用。CNN是深度学习领域的一个重要分支,广泛应用于图像识别、语音处理等领域。我们将通过代码示例和实际应用案例,帮助读者更好地理解CNN的概念和应用。
|
22天前
|
机器学习/深度学习 算法 计算机视觉
深度学习与生活:如何利用卷积神经网络识别日常物品
【10月更文挑战第24天】在这篇文章中,我们将探索深度学习如何从理论走向实践,特别是卷积神经网络(CNN)在图像识别中的应用。通过一个简单的示例,我们将了解如何使用CNN来识别日常生活中的物体,如水果和家具。这不仅是对深度学习概念的一次直观体验,也是对技术如何融入日常生活的一次深刻反思。文章将引导读者思考技术背后的哲理,以及它如何影响我们的生活和思维方式。

热门文章

最新文章