如图左所示,假设输入为x,然后来了一个‘并联’,假设x经过虚线框操作后输出的结果为x1,在汇合的地方输出结果为out,那么out=x+x1。为了使x和x1能够相加,其两者维度需相同,也就是x1的维度要与x相同。
解决VGG由于层数过多,网络过深产生的梯度爆炸、过拟合问题
下面实现上图左边的Residule block。
import torch import torch.nn as nn import torch.nn.functional as F class ResNet_basic_block(nn.Module): def __init__(self, in_channels, out_channels): super().__init__() self.conv1 = nn.Conv2d(in_channels = in_channels, out_channels = out_channels, kernel_size = 3, #3*3卷积 padding = 1, #通过padding操作使x维度不变 bias = False) self.bn1 = nn.BatchNorm2d(num_features = out_channels) self.conv2 = nn.Conv2d(in_channels = out_channels, out_channels = out_channels, kernel_size = 3, #3*3卷积 padding = 1, #通过padding操作使x维度不变 bias = False) self.bn2 = nn.BatchNorm2d(num_features = out_channels) def forward(self, x): residual = x, out = self.conv1(x) out = self.bn1(out) out = F.relu(self.bn1(out), inplace = True) out = self.conv2(out) out = self.bn2(out) return out
net = ResNet_basic_block(in_channels=3, out_channels=3) x = torch.rand((1,3,128,128), requires_grad=True) ## 试验用的输入数据 ## 不加requires_grad=True,那样会报错的 print(x)
>>> tensor([[[[0.1748, 0.7122, 0.5482, ..., 0.3072, 0.5013, 0.3448], [0.9843, 0.9961, 0.2204, ..., 0.7938, 0.0166, 0.4661], [0.0247, 0.0084, 0.0705, ..., 0.2160, 0.4828, 0.5090], ..., [0.9613, 0.8825, 0.5579, ..., 0.0887, 0.8651, 0.5624], [0.9226, 0.5717, 0.7671, ..., 0.9176, 0.2652, 0.0017], [0.3222, 0.0448, 0.1637, ..., 0.4346, 0.4602, 0.1887]], [[0.6197, 0.8704, 0.3110, ..., 0.9539, 0.3757, 0.4366], [0.8575, 0.0412, 0.8464, ..., 0.5786, 0.8352, 0.1744], [0.0278, 0.0901, 0.1685, ..., 0.1698, 0.1893, 0.8004], ..., [0.9396, 0.6551, 0.0380, ..., 0.8259, 0.5549, 0.8349], [0.2380, 0.9816, 0.4802, ..., 0.0942, 0.5014, 0.6619], [0.2772, 0.9087, 0.0889, ..., 0.3405, 0.0918, 0.7940]]]], requires_grad=True)
a = net(x) print(a)
tensor([[[[ 2.6107e+00, 4.9241e+00, 4.4753e+00, ..., 3.0504e+00, 2.5287e+00, 1.6026e+00], [ 4.4550e-01, -1.5947e+00, -1.3323e+00, ..., -2.5174e+00, -2.5517e+00, -1.4408e+00], [ 3.1338e-01, 3.2004e-01, 5.9879e-01, ..., -1.4324e+00, 1.4006e+00, -1.9084e-01], ..., [ 4.8046e-01, 1.2165e+00, 1.5494e+00, ..., 1.1277e+00, -1.0431e+00, -8.0495e-01], [-1.9110e+00, -1.5171e+00, 3.0137e-03, ..., 4.9892e-01, 1.4297e+00, 1.3426e-02], [-1.1890e+00, -4.4962e-01, -1.2672e+00, ..., -1.8782e+00, -1.7202e+00, -2.0879e+00]]]], grad_fn=<NativeBatchNormBackward>)
## 定义一个建立了一个卷积--池化--卷积--池化-- ## 卷积--池化--全连接--全连接--全连接(4分类) class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3) self.pool = nn.MaxPool2d(2, 2) self.bn1 = nn.BatchNorm2d(32) self.conv2 = nn.Conv2d(32, 64, 3) self.pool = nn.MaxPool2d(2, 2) self.bn2 = nn.BatchNorm2d(64) self.conv3 = nn.Conv2d(64, 64, 3) self.pool = nn.MaxPool2d(2, 2) self.bn3 = nn.BatchNorm2d(64) self.conv3 = nn.Conv2d(64, 64, 3) self.drop1d = nn.Dropout(0.2) self.bn4 = nn.BatchNorm2d(64) self.fc1 = nn.Linear(64 * 14 * 14, 1024) self.fc2 = nn.Linear(1024, 256) self.fc3 = nn.Linear(256, 4) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.bn1(x) x = self.pool(F.relu(self.conv2(x))) x = self.bn2(x) x = self.pool(F.relu(self.conv3(x))) x = self.bn3(x) x = x.view(-1, x.size(1) * x.size(2) * x.size(3)) x = F.relu(self.fc1(x)) x = self.drop1d(x) x = F.relu(self.fc2(x)) x = self.drop1d(x) x = self.fc3(x) return x
建立了一个卷积–池化–卷积–池化–卷积–池化–全连接–全连接–全连接(输出为4分类)
##测试模型 Model = Net() x = torch.randn(32, 3, 128, 128) model(x)
>>> tensor([[ 2.4648, -0.1044, -0.0207, ..., -1.5143, -0.0301, 0.4112], [-1.1457, 1.1705, -1.1644, ..., -0.6782, 1.5006, 0.6034], [ 1.8320, 2.3075, 0.9986, ..., -0.7777, -0.5291, 0.7829], ..., [-0.4622, -0.6317, 0.4479, ..., 2.8768, -0.5076, 2.9432], [-0.9910, -0.6667, 0.5861, ..., -0.1901, -2.6266, 0.2797], [-1.4598, -0.4183, -1.2018, ..., -2.0129, 1.1534, 1.2424]], grad_fn=<AddmmBackward>)
现在问题是如何在普通的CNN网络中添加Residule block
## 定义网络模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3) self.pool = nn.MaxPool2d(2, 2) self.bn1 = nn.BatchNorm2d(32) ## 此处添加Residule block,记得写in_channels和out_channels两个参数 self.res = ResNet_basic_block(in_channels=32, out_channels=32) self.conv2 = nn.Conv2d(32, 64, 3) self.pool = nn.MaxPool2d(2, 2) self.bn2 = nn.BatchNorm2d(64) self.conv3 = nn.Conv2d(64, 64, 3) self.pool = nn.MaxPool2d(2, 2) self.bn3 = nn.BatchNorm2d(64) self.conv3 = nn.Conv2d(64, 64, 3) self.drop1d = nn.Dropout(0.2) self.bn4 = nn.BatchNorm2d(64) self.fc1 = nn.Linear(64 * 14 * 14, 1024) self.fc2 = nn.Linear(1024, 256) self.fc3 = nn.Linear(256, 4) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.bn1(x) x = self.res(x) ## 使用residule block x = self.pool(F.relu(self.conv2(x))) x = self.bn2(x) x = self.pool(F.relu(self.conv3(x))) x = self.bn3(x) x = x.view(-1, x.size(1) * x.size(2) * x.size(3)) x = F.relu(self.fc1(x)) x = self.drop1d(x) x = F.relu(self.fc2(x)) x = self.drop1d(x) x = self.fc3(x) return x
Model = Net() x = torch.randn(32, 3, 128, 128) model(x)
>>> tensor([[ 1.5100e+00, -7.4613e-01, 8.7256e-01, ..., 3.0170e+00, -3.0221e-01, -1.8396e+00], [-6.5097e-01, -9.8755e-03, -1.5788e-01, ..., 1.6645e+00, 9.5299e-01, 8.2736e-01], [-1.8710e+00, 2.0923e-01, 4.7972e-01, ..., 1.8698e-01, 1.8506e-01, 1.6153e-04], ..., [ 5.4644e+00, 1.8698e+00, -7.3383e-01, ..., 6.9908e-01, -1.3000e+00, 1.7883e+00], [-6.2972e-02, -2.3328e+00, -2.5254e-01, ..., 1.5666e+00, 8.7195e-01, -2.8013e-01], [-1.5590e+00, -2.7793e+00, -1.5177e+00, ..., -1.2423e+00, -4.3381e-01, -6.5499e-01]], grad_fn=<AddmmBackward>)
模型输出结果了,大工完成
欢迎关注gzh:故障诊断与python学习