卷积神经网络(加强)
0. 1*1的卷积有什么用呢?
- 降低运算量
- 信息融合
- 改变通道数量
1. GoogLeNet
Inception Block
沿着通道的维度进行拼接
完整代码
"""
2021.08.10
author:alian
11 基于pytorch的卷积神经网络(GoogleNet)
"""
import torch
import torch.nn.functional as F
# GoogleNet
class InceptionA(torch.nn.Module):
def __init__(self,in_channels):
super(InceptionA,self).__init__()
self.branch1x1 = torch.nn.Conv2d(in_channels,16, kernel_size=1)
self.branch5x5_1 = torch.nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch5x5_2 = torch.nn.Conv2d(16, 24, kernel_size=5, padding=2)
self.branch3x3_1 = torch.nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch3x3_2 = torch.nn.Conv2d(16, 24, kernel_size=3, padding=1)
self.branch3x3_3 = torch.nn.Conv2d(24, 24, kernel_size=3, padding=1)
self.branch_pool = torch.nn.Conv2d(in_channels, 24, kernel_size=1)
def forward(self,x):
branch1x1 = self.branch1x1(x)
branch5x5 = self.branch5x5_1(x)
branch5x5 = self.branch5x5_2(branch5x5)
branch3x3 = self.branch3x3_1(x)
branch3x3 = self.branch3x3_2(branch3x3)
branch3x3 = self.branch3x3_3(branch3x3)
branch_pool = F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)
branch_pool = self.branch_pool(branch_pool)
outputs = [branch1x1,branch5x5,branch3x3,branch_pool]
return torch.cat(outputs,dim=1)
class googleNet(torch.nn.Module):
def __init__(self):
super(googleNet,self).__init__()
self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5)
self.conv2 = torch.nn.Conv2d(88,20,kernel_size=5)
self.incep1 = InceptionA(in_channels=10)
self.incep2 = InceptionA(in_channels=20)
self.mp = torch.nn.MaxPool2d(2)
self.fc = torch.nn.Linear(1408,10) # 全连接层(线性层)
def forward(self,x):
in_size = x.size(0)
x = F.relu(self.mp(self.conv1(x)))
x = self.incep1(x)
x = F.relu(self.mp(self.conv2(x)))
x = self.incep2(x)
x = x.view(in_size,-1)
x = self.fc(x)
return x
2. ResNet
梯度消失:
反向传播,链式法则求梯度(一连串地将梯度乘起来),假如每一处的梯度都是<1,则一连串地相乘会导致梯度趋近于0,当梯度趋近于0时,根据权重更新公式:
w
=
w
−
α
g
w=w-\alpha g
w=w−αg (
g
g
g为梯度),权重将得不到更新,无法得到充分训练。
上述的残差单元,在输出加上一个输入x,将来反向传播回传的梯度(即使非常小)也趋近于1,链式法则梯度相乘不会造成梯度消失问题,开始的网络层能得到很好的训练。要求:残差单元输出和输入的张量维度必须一致
完整代码
# ResNet
class ResidualBlock(torch.nn.Module):
def __init__(self,channels):
super(ResidualBlock,self).__init__()
self.channels = channels
self.conv1 = torch.nn.Conv2d(channels,channels,kernel_size=3,padding=1)
self.conv2 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1)
def forward(self,x):
y = F.relu(self.conv1(x))
y = self.conv2(y)
return F.relu(x+y)
class ResNet(torch.nn.Module):
def __init__(self):
super(ResNet,self).__init__()
self.conv1 = torch.nn.Conv2d(1,16,kernel_size=5)
self.conv2 = torch.nn.Conv2d(16,32,kernel_size=5)
self.res1 = ResidualBlock(16)
self.res2 = ResidualBlock(32)
self.pool = torch.nn.MaxPool2d(2)
self.fc = torch.nn.Linear(512,10)
def forward(self,x): # 输入张量
in_size = x.size(0)
x = self.pool(F.relu(self.conv1(x)))
x = self.res1(x)
x = self.pool(F.relu(self.conv2(x)))
x = self.res2(x)
x.view(in_size,-1) # Flatten data from(batch_size,32,4,4) to (batch_size,512)
x = self.fc(x)
return x