参考了网上的一些代码,对resnet有了更深入的理解。因此做了两个类,一个是ResidualChunk,一个是ResNet18。如果使用了nn.BatchNorm2d,则在conv函数中设置bias是无用的,可以设置为False。
在下面会列出来实践的代码,其中,ResidualChunk学习到的三点内容是:
#ResidualChunk #第一点 # 如果stride=2,则图像的长和宽会降采样一倍 # 如果stride=1,则长和宽是不变的,输出的长和宽是多大,输出的就是多大 #第二点 # in_channel 和 out_channel 如果不一样 则加法 无法加起来 #因此需要 用conv(in_channel,out_channel, kernel_size =1, padding =0, stride =2)来改变通道数和图像长宽 #stride=2则图像降采样一倍,并且out_channel设置号,则通道数也满足了拼接 #第三点 #每一个layer有两层迭代,第一层迭代具有降采样和通道变换,第二层的时候,没有降采样,也没有通道数量的改变
其中,ResNet18的过程是:
#ResNet18 #处理过程,输入3*32*32的层 #conv1 变换得到 64*32*32 #layers1 变换得到 64*32*32 #layers2 变换得到 128* 16*16 #layers3 变换得到 256 * 8 *8 #layers4 变换得到 512 * 4 *4 #avg_pool2d 变换得到 512*1*1 #view(out_x.size(0),-1) 得到512 #nn.Linear(512,numClass) 512*10,最后得到10类,选择最大的一个数字作为目标判别出来的类
代码如下:
import torch
import torch.nn as nn
import torch.nn.functional as Func#注意一点就是如果要使用BatchNormal ,则可以设置bias=False,因为均值和方差和 统一加一个bias无关了#ResNet18
#处理过程,输入3*32*32的层
#conv1 变换得到 64*32*32
#layers1 变换得到 64*32*32
#layers2 变换得到 128* 16*16
#layers3 变换得到 256 * 8 *8
#layers4 变换得到 512 * 4 *4
#avg_pool2d 变换得到 512*1*1
#view(out_x.size(0),-1) 得到512
#nn.Linear(512,numClass) 512*10,最后得到10类,选择最大的一个数字作为目标判别出来的类class ResidualChunk(nn.Module):def __init__(self, inchannel, outchannel, stride = 1):super(ResidualChunk, self).__init__()self.verticalLine = nn.Sequential(nn.Conv2d(inchannel,outchannel,kernel_size=3,stride=stride,padding=1,bias=False),nn.BatchNorm2d(outchannel),nn.ReLU(),nn.Conv2d(outchannel,outchannel,kernel_size=3,stride=1,padding=1,bias=False),nn.BatchNorm2d(outchannel),)self.resLine = nn.Sequential()if stride != 1 or inchannel != outchannel:self.resLine = nn.Sequential(nn.Conv2d(inchannel,outchannel,kernel_size=1,padding=0,stride=stride,bias=False),nn.BatchNorm2d(outchannel))def forward(self,x):vertical_out_x = self.verticalLine(x)vertical_out_x += self.resLine(x)x = Func.relu(vertical_out_x)return xclass ResNet18(nn.Module):def __init__(self,ResidualBlock, numClass):super(ResNet18, self).__init__()self.inChannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3,64,kernel_size=7,stride=1,padding=3,bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layers1 = self.make_layer(ResidualChunk,64,2,stride = 1)self.layers2 = self.make_layer(ResidualBlock,128,2,stride = 2)self.layers3 = self.make_layer(ResidualBlock,256,2,stride= 2)self.layers4 = self.make_layer(ResidualBlock,512,2,stride = 2)self.fc = nn.Linear(512,numClass) #几个分类def make_layer(self,basicNet, channels, num_repeate, stride):strides = [stride] + [1] * (num_repeate - 1)layers = []for stride in strides:layers.append(basicNet(self.inChannel,channels,stride)),self.inChannel = channels #每一次保留下一次的输入通道数量return nn.Sequential(*layers)def forward(self,x):out_x = self.conv1(x)out_x = self.layers1(out_x)out_x = self.layers2(out_x)out_x = self.layers3(out_x)out_x = self.layers4(out_x)out_x = Func.avg_pool2d(out_x,4)out_x = out_x.view(out_x.size(0),-1)out_x = self.fc(out_x)return out_xresnet = ResNet18(ResidualChunk,10)
data = torch.randn(1,3,32,32)
out = resnet(data)
print(resnet)
print(out)
最后的几行代码是测试网络是否执行顺利
resnet = ResNet18(ResidualChunk,10)
data = torch.randn(1,3,32,32)
out = resnet(data)
print(resnet)
print(out)
out是一个长度为10的张量,因此是正确的。