Schéma d'architecture + code adapté aux novices pour construire un réseau résiduel ResNet50 (le plus complet)
La plupart des tutoriels sur Internet sont complexes et difficiles à comprendre et ne conviennent pas aux novices. Les réseaux de neurones sont intrinsèquement difficiles. Ces tutoriels eux-mêmes sont plus difficiles et extrêmement peu conviviaux pour les novices. Par conséquent, le diagramme d'architecture et le code que j'ai créé sont destinés destiné aux novices et doit être évité par les experts.
from torch import nn
import torch
from torchviz import make_dot
class box(nn.Module):
def __init__(self, in_channels, index=999, stride=1, downsample=False):
super(box, self).__init__()
last_stride = 2 # 虚残差中卷积核的步距
if downsample: # 虚残差结构
f_out_channnels = in_channels * 2
out_channels = int(in_channels / 2)
if index == 0: # here is first core
in_channels = int(in_channels / 2) # 第一层设置为128,是方便了后面的统一处理
out_channels = in_channels
f_out_channnels = in_channels * 4
last_stride = 1
stride = 1
else: # 实残差
f_out_channnels = in_channels * 1
out_channels = int(in_channels / 4)
self.downsample = downsample
self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, bias=False)
self.relu = nn.ReLU(inplace=True)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(in_channels=out_channels, out_channels=out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
self.relu = nn.ReLU(inplace=True)
self.bn2 = nn.BatchNorm2d(out_channels)
self.conv3 = nn.Conv2d(in_channels=out_channels, out_channels=f_out_channnels, kernel_size=1, stride=1, padding=0)
self.bn3 = nn.BatchNorm2d(f_out_channnels)
self.fe = nn.Sequential(
nn.Conv2d(in_channels=in_channels, out_channels=f_out_channnels, kernel_size=1, stride=last_stride, padding=0, bias=False),
nn.BatchNorm2d(f_out_channnels),
)
def forward(self, x):
identity = x
if self.downsample:
identity = self.fe(x)
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu(x)
x = self.conv3(x)
x = self.bn3(x)
out = x + identity
out = self.relu(out)
return out
class New50(nn.Module):
def __init__(self,in_out, num_classes=4):
super(New50, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2,padding=3, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # output size = (1, 1)
self.fc = nn.Linear(512 * 4 , num_classes)
layers = []
for index, z in enumerate(in_out):
in_ch = z[0] # 这里通道/2
layers.append(box(in_channels=in_ch, stride=2, downsample=z[2], index=index)) # 这里处理第一层
for i in range(1, z[1]):
layers.append(box(in_channels=z[3])) # 这里处理其他两层
# print(layers)
self.fes = nn.Sequential(*layers)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.fes(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.fc(x)
return x
in_out = [(128, 3, True, 256), (256, 4, True, 512), (512, 6, True, 1024), (1024, 3, True, 2048)]
s = New50(in_out=in_out)
def resnet500():
return New50(in_out=in_out)
'''每层的第一层输入
每层重复的次数
是否走虚残差
每层的第二个卷积核的输入'''
ResNet30, FCN, UNet et d'autres diagrammes et codes d'architecture seront téléchargés à l'avenir.