文章目录
- 5、卷积神经网络
- 5.10、⭐批量归一化
- 5.10.1、理论部分
- 5.10.2、代码部分
- 5.11、⭐残差网络(`ResNet`)
- 5.11.1、理论部分
- 5.11.2、代码部分
- 话题闲谈
5、卷积神经网络
5.10、⭐批量归一化
5.10.1、理论部分
批量归一化可以解决深层网络中梯度消失和收敛慢的问题,通过固定每个批次的均值和方差来加速收敛,一般不改变模型精度。批量规范化已经被证明是一种不可或缺的方法,它适用于几乎所有图像分类器。
批量规划是一个线性变换,把参数的均值方差给拉的比较好。让你变化不那么剧烈。
批量规范化应用于单个可选层(也可以应用到所有层),其原理如下:在每次训练迭代中,我们首先规范化输入,即通过减去其均值并除以其标准差,其中两者均基于当前小批量处理。 接下来,我们应用比例系数和比例偏移。 正是由于这个基于批量统计的标准化,才有了批量规范化的名称。
B N ( x ) = γ ⊚ x − μ ^ B σ ^ B + β BN(x) = γ⊚\frac{x-\hat{μ}_B}{\hat{σ}_B}+β BN(x)=γ⊚σ^Bx−μ^B+β
其中,x∈B,x是一个小批量B的输入,比例系数γ,比例偏移β。 μ ^ β B \hat{μ}β_B μ^βB小批量B的均值, σ ^ B \hat{σ}_B σ^B小批量B的标准差。
μ ^ B = 1 ∣ B ∣ ∑ x ∈ B x \hat{μ}_B = \frac{1}{|B|}\sum_{x∈B}{x} μ^B=∣B∣1x∈B∑x
σ ^ B 2 = 1 ∣ B ∣ ∑ x ∈ B ( x − μ ^ B ) 2 + c {\hat{σ}_B}^2 = \frac{1}{|B|}\sum_{x∈B}{(x-\hat{μ}_B)^2 + c} σ^B2=∣B∣1x∈B∑(x−μ^B)2+c
差估计值中添加一个小的常量c>0,以确保永远不会尝试除以零【BN(x)分母】。通过使用平均值和方差的噪声(noise)估计来抵消缩放问题,噪声这里是有益的。
-
可学习的参数:比例系数γ,比例偏移β;
-
作用在全连接层和卷积层输出,激活函数前;
-
作用在全连接层和卷积层输入。
作用于全连接层的特征维
作用于卷积层的通道维
5.10.2、代码部分
直接使用深度学习框架中定义的BatchNorm
定义Sequential
块
import torch
from torch import nn
from d2l import torch as d2lnet = nn.Sequential(# nn.BatchNorm2d(6) 二维卷积操作的批归一化层,6通道nn.Conv2d(1, 6, kernel_size=5), nn.BatchNorm2d(6), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2),nn.Conv2d(6, 16, kernel_size=5), nn.BatchNorm2d(16), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),# # nn.BatchNorm1d(120) 一维卷积操作的批归一化层,120通道nn.Linear(256, 120), nn.BatchNorm1d(120), nn.Sigmoid(),nn.Linear(120, 84), nn.BatchNorm1d(84), nn.Sigmoid(),nn.Linear(84, 10))
lr, num_epochs, batch_size = 1.0, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
批量规范化应用于LeNet
net = nn.Sequential(# BatchNorm(6, num_dims=4) num_dims 参数用来根据输入数据的维度选择适当的批归一化操作,输入6通道,输入4维,这里会选择nn.BatchNorm2d进行归一化。这里和 nn.BatchNorm2d(6) 一样的。nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2),nn.Conv2d(6, 16, kernel_size=5), BatchNorm(16, num_dims=4), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),nn.Linear(16*4*4, 120), BatchNorm(120, num_dims=2), nn.Sigmoid(),nn.Linear(120, 84), BatchNorm(84, num_dims=2), nn.Sigmoid(),nn.Linear(84, 10))
5.11、⭐残差网络(ResNet
)
5.11.1、理论部分
核心思想:保证加更多的层效果较之前不会变差。
设计越来越深的网络,网络表现不一定会更好。
实现原理-残差块(residual blocks
)
每个附加层都应该更容易地包含原始函数作为其元素之一。
如下图:
正常块中,输出直接作为理想映射 f ( x ) f(x) f(x);
残差块中,输出为 f ( x ) − x f(x)-x f(x)−x和 x x x两部分
x经过残差映射 f ( x ) − x f(x)-x f(x)−x输出
x作为原始数据恒等映射到输出
两者共同组成 f ( x ) f(x) f(x)。
5.11.2、代码部分
实现残差块
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2lclass Residual(nn.Module): #@savedef __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels,kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels,kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):Y = F.relu(self.bn1(self.conv1(X)))Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += Xreturn F.relu(Y)
生成两种类型的网络:
验证输入输出情况一致blk = Residual(3,3) #X batch_size=4,input_channel=3,shape=6*6 X = torch.rand(4, 3, 6, 6) Y = blk(X) Y.shape
torch.Size([4, 3, 6, 6])
验证增加输出通道数,同时减半输出的高和宽
blk = Residual(3,6, use_1x1conv=True, strides=2) blk(X).shape
torch.Size([4, 6, 3, 3])
定义ResNet
第一个Sequential
块
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
定义残差块
def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []for i in range(num_residuals):if i == 0 and not first_block:blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))return blk
定义其他(含残差块)Sequential
块
每个模块使用2个残差块
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))
在ResNet
中加入全局平均汇聚层,以及全连接层输出
每个模块【b2-b5】有4个卷积层(不包括恒等映射的1×1卷积层)。 加上第一个7×7卷积层和最后一个全连接层,共有18层。 因此,这种模型通常被称为
ResNet-18
。
net = nn.Sequential(b1, b2, b3, b4, b5,nn.AdaptiveAvgPool2d((1,1)),nn.Flatten(), nn.Linear(512, 10))
验证每模块输出形状变化
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t', X.shape)
Sequential output shape: torch.Size([1, 64, 56, 56]) Sequential output shape: torch.Size([1, 64, 56, 56]) Sequential output shape: torch.Size([1, 128, 28, 28]) Sequential output shape: torch.Size([1, 256, 14, 14]) Sequential output shape: torch.Size([1, 512, 7, 7]) AdaptiveAvgPool2d output shape: torch.Size([1, 512, 1, 1]) Flatten output shape: torch.Size([1, 512]) Linear output shape: torch.Size([1, 10])
训练模型
lr, num_epochs, batch_size = 0.05, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
话题闲谈
怎么维护自己的电脑?
对于深度学习工作者而言,电脑是最为重要的工作工具之一,因此维护电脑的健康状态对工作、学习和生活都至关重要。
首先,定期进行系统和软件的更新,保持操作系统和应用程序在最新版本,以获得更好的性能和安全性。其次,保持电脑的清洁,定期清理灰尘和污垢,确保散热良好,避免过热对硬件的损害。此外,备份重要数据是必不可少的,以防止意外数据丢失。
在学习方面,合理规划学习时间,避免长时间的连续使用电脑,适时休息,保护眼睛和身体健康。
生活娱乐方面,多参与户外活动,保持身体锻炼,减轻长时间坐在电脑前带来的压力。总之,深度学习工作者应关注电脑的硬件和软件健康,平衡工作、学习和生活,保持身心健康。