目录
一.分解层构建模型部分
1)在__init__中把所有层以self.xxx的形式写出来
2)在forward函数中以x=池化(激活(层(x))),的形式传递下去。
3)如果池化层后面有接全连接,需要把神经元拉平的函数,num_flat_features。
4)最后使用的时候定义一下,输入和输出通道就好,输入一般是通道数,输出一般是分类数。
#构建模型
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F
class LeNet5(nn.Module):
def __init__(self, in_dim, n_class):
super(LeNet5, self).__init__()
# 从结构图中可以看出,第一层:卷积层输入是1 channel, 输出是 6 channel, kennel_size = (5,5)
self.conv1 = nn.Conv2d(in_dim, 6, 5, padding=2)
# 第二层:依旧是 卷积层, 输入 6 channel 输出 6 channel , kennel_size = (5,5)
self.conv2 = nn.Conv2d(6, 16, 5)
# 第三层:全连接层(线性表示)
self.fc1 = nn.Linear(16*5*5, 120)
# 第四层:全连接层
self.fc2 = nn.Linear(120, 84)
# 第五层:输出层
self.fc3 = nn.Linear(84, n_class)
# 向前传播
def forward(self, x):
# Subsampling 1 process
x = F.max_pool2d(F.relu(self.conv1(x)), 2)
# Subsampling 2 process
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
# -1的话,意味着最后的相乘为维数
x = x.view(-1, self.num_flat_features(x))
# full connect 1
x = F.relu(self.fc1(x))
# full connect 2
x = F.relu(self.fc2(x))
# full connect 3
x = self.fc3(x)
return x
# 6 channel 卷积层 转全连接层的处理
def num_flat_features(self, x):
# 得到 channel * iW * iH 的值
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
leNet = LeNet5(1, 10)
print(leNet)
二.用Sequential来打包层构建网络部分
class AlextNet(nn.Module):
def __init__(self, in_channel, n_class):
super(AlextNet, self).__init__()
# 第一阶段
self.conv1 = nn.Sequential(
nn.Conv2d(in_channel, 96, kernel_size=11, stride=4),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2)
)
# 第二阶段
self.conv2 = nn.Sequential(
nn.Conv2d(96, 256, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2)
)
# 第三阶段
self.conv3 = nn.Sequential(
nn.Conv2d(256, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2)
)
# 第四阶段 全连接层
self.fc = nn.Sequential(
nn.Linear(1*1*256, 4096),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(4096, n_class) # AlexNet上面是1000 ...如果测试的话用MNIST则可以使用10
)
# 向前传播
def forward(self, x):
con1_x = self.conv1(x)
con2_x = self.conv2(con1_x)
con3_x = self.conv3(con2_x)
lin_x = con3_x.view(con3_x.size(0), -1)
y_hat = self.fc(lin_x)
return y_hat
三.使用自己写的层列表,一次性导入到Sequential
class VGG(nn.Module):
'''
VGG model
'''
def __init__(self, conv_features):
super(VGG, self).__init__()
self.conv_features = conv_features
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(4608, 512),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(512, 512),
nn.ReLU(True),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.conv_features(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
# 构建 循环的 conv层
def make_layers(struct, in_channels=1, batch_norm=False):
layers = []
for out_channels in struct:
if out_channels == 'pooling':
layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
else:
conv2d = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
if batch_norm:
layers += [conv2d, nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True)]
else:
layers += [conv2d, nn.ReLU(inplace=True)]
in_channels = out_channels
return nn.Sequential(*layers)
# 模型初始化
vgg_conv_layers = [64, 64, 'pooling', 128, 128, 'pooling', 256, 256, 256, 'pooling', 512, 512, 512, 'pooling', 512, 512, 512, 'pooling']
# 初始通道—— 三通道
vgg16 = VGG(make_layers(vgg_conv_layers, in_channels=3))
四.使用方法三,写出适合的卷积结构
卷积,卷积,池化,卷积,卷积,池化类型
# 构建 循环的 conv层
def make_layers(struct, in_channels=1, batch_norm=False):
layers = []
for out_channels in struct:
if out_channels == 'pooling':
layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
else:
conv2d = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
if batch_norm:
layers += [conv2d, nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True)]
else:
layers += [conv2d, nn.ReLU(inplace=True)]
in_channels = out_channels
return nn.Sequential(*layers)
MLP卷积----PS:卷积加两层共享的全连接层
# NiN提出只对通道层做全连接并且像素之间共享权重来解决上述两个问题
# 这种“一卷卷到底”最后加一个平均池化层的做法也成为了深度卷积神经网络的常用设计。
def mlpconv(in_chanels, out_chanels, kernel_size, padding, strides=1, max_pooling=True):
layers = []
layers += [nn.Conv2d(in_chanels, out_chanels, kernel_size=kernel_size, padding=padding, stride=strides), nn.ReLU(inplace=True)]
layers += [nn.Conv2d(out_chanels, out_chanels, kernel_size=1, padding=0, stride=1), nn.ReLU(inplace=True)]
layers += [nn.Conv2d(out_chanels, out_chanels, kernel_size=1, padding=0, stride=1), nn.ReLU(inplace=True)]
if max_pooling:
layers += [nn.MaxPool2d(kernel_size=3, stride=2)]
return nn.Sequential(*layers)
残差网络块