从零开始的推荐系统学习之路(十五)---- 动手学深度学习系列 卷积神经网络 CNN(GoogLeNet & BatchNorm & ResNet)
·
文章目录
前引
还有三部分 还要继续搞
可以剩一点放在明天上午搞 先这样 我先去把GoogleNet 给复现一遍
这两天早点弄完 明天多花点时间陪一下npy
从零开始的推荐系统学习之路(十五)---- 动手学深度学习系列 卷积神经网络 CNN(GoogLeNet & BatchNorm & ResNet)
1、GoogLeNet
下面即是 GoogleNet Inception的架构图 还有详细的架构图





import torch.nn.functional as F
class Inception(nn.Module):
def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):
super().__init__()
self.c1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
self.c2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
self.c2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
self.c3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
self.c3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
self.c4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
self.c4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)
def forward(self, x):
c1 = F.relu(self.c1_1(x))
c2 = F.relu(self.c2_2(F.relu(self.c2_1(x))))
c3 = F.relu(self.c3_2(F.relu(self.c3_1(x))))
c4 = F.relu(self.c4_2(self.c4_1(x)))
# print(c1.shape, c2.shape, c3.shape, c4.shape, torch.cat([c1, c2, c3, c4], 1).shape)
return torch.cat([c1, c2, c3, c4], 1)
b1b2 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.MaxPool2d(3, stride=2, padding=1),
nn.Conv2d(64, 64, kernel_size=1),
nn.ReLU(),
nn.Conv2d(64, 192, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.MaxPool2d(3, stride=2, padding=1))
b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),
nn.ReLU(),
nn.Conv2d(64, 192, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
X = torch.zeros((1, 1, 224, 224))
for layer in b1b2:
X = layer(X)
print(layer.__class__.__name__, '\t', X.shape)
X = torch.zeros((1, 1, 224, 224))
b1b2net = nn.Sequential(b1, b2)
for layer in b1b2net:
X = layer(X)
print("b1b2net", layer.__class__.__name__, '\t', X.shape)
b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),
Inception(256, 128, (128, 192), (32, 96), 64),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
X = torch.zeros((1, 1, 224, 224))
b1b2b3net = nn.Sequential(b1, b2, b3)
for layer in b1b2b3net:
X = layer(X)
print(layer.__class__.__name__, '\t', X.shape)
b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),
Inception(512, 160, (112, 224), (24, 64), 64),
Inception(512, 128, (128, 256), (24, 64), 64),
Inception(512, 112, (144, 288), (32, 64), 64),
Inception(528, 256, (160, 320), (32, 128), 128),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
X = torch.zeros((1, 1, 224, 224))
b1b2b3b4net = nn.Sequential(b1, b2, b3, b4)
for layer in b1b2b3b4net:
X = layer(X)
print(layer.__class__.__name__, '\t', X.shape)
b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),
Inception(832, 384, (192, 384), (48, 128), 128),
nn.AdaptiveAvgPool2d((1,1)),
nn.Flatten())
X = torch.zeros((1, 1, 94, 94))
net = nn.Sequential(b1, b2, b3, b4, b5, nn.Dropout(p=0.5), nn.Linear(1024, 10))
for layer in net:
X = layer(X)
print(layer.__class__.__name__, '\t', X.shape)
lr, num_epochs, batch_size = 0.1, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size, resize=96)
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu_mps(), "relu")



2、BatchNorm(批量归一化)
原理 站在我的角度来说 可以使参数输出更稳定 作用于特征纬度 然后 可以学习到 新的方差 和 均值
也有说的是 数据 例如减去了新的误差 以及数据去变换了
一般不与dropout同时去用

def batch_norm(X, gamma, beta, moving_mean, moving_var, eps=1e-5, momentum=0.9):
if not torch.is_grad_enabled():
X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
else:
assert len(X.shape) in (2, 4)
mean, var, features = 0.0, 1.0, 0
if len(X.shape) == 2:
mean = X.mean(dim=0, keepdims=True)
var = ((X - mean) ** 2).mean(dim=0, keepdims=True)
else:
mean = X.mean(dim=(0, 2, 3), keepdims=True)
# print(mean.shape)
var = ((X - mean) ** 2).mean(dim=(0, 2, 3), keepdims=True)
X_hat = (X - mean) / torch.sqrt(var + eps)
moving_mean = momentum * moving_mean + (1 - momentum) * mean
moving_var = momentum * moving_var + (1 - momentum) * var
Y = gamma * X_hat + beta
return Y, moving_mean, moving_var
class BatchNorm(nn.Module):
# num_features:完全连接层的输出数量或卷积层的输出通道数。
# num_dims:2表示完全连接层,4表示卷积层
def __init__(self, num_features, num_dims):
super().__init__()
assert num_dims in (2, 4)
shape = ()
if num_dims == 2:
shape = (1, num_features)
else:
shape = (1, num_features, 1, 1)
self.gamma = nn.Parameter(torch.ones(shape))
self.beta = nn.Parameter(torch.zeros(shape))
self.moving_mean = torch.zeros(shape)
self.moving_var = torch.ones(shape)
def forward(self, X):
if self.moving_mean.device != X.device:
self.moving_mean = self.moving_mean.to(X.device)
self.moving_var = self.moving_var.to(X.device)
Y, self.moving_mean, self.moving_var = batch_norm(
X, self.gamma, self.beta, self.moving_mean,
self.moving_var, eps=1e-5, momentum=0.9)
return Y
net = BatchNorm(3, 4)
X = torch.zeros(1, 3, 224, 224)
X.shape, net(X).shape
net = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), BatchNorm(16, num_dims=4), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
nn.Linear(16*4*4, 120), BatchNorm(120, num_dims=2), nn.Sigmoid(),
nn.Linear(120, 84), BatchNorm(84, num_dims=2), nn.Sigmoid(),
nn.Linear(84, 10))
lr, num_epochs, batch_size = 1.0, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu_mps(), 'relu')
net = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5), nn.BatchNorm2d(6), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.BatchNorm2d(16), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
nn.Linear(16*4*4, 120), nn.BatchNorm1d(120), nn.Sigmoid(),
nn.Linear(120, 84), nn.BatchNorm1d(84), nn.Sigmoid(),
nn.Linear(84, 10))
lr, num_epochs, batch_size = 1.0, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu_mps(), 'relu')


3、ResNet
**残参网络架构 我理解本质上有个类似的短路机制 或者说大网络包含着小网络 让网络更稳定一点 **



class Residual(nn.Module):
def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1):
super().__init__()
self.c1 = nn.Conv2d(input_channels, num_channels, kernel_size=3, stride=strides, padding=1)
self.b1 = nn.BatchNorm2d(num_channels)
self.c2 = nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1)
self.b2 = nn.BatchNorm2d(num_channels)
self.c3 = None
if use_1x1conv == True:
self.c3 = nn.Conv2d(input_channels, num_channels, kernel_size=1, stride=strides)
def forward(self, X):
tmp = nn.functional.relu(self.b1(self.c1(X)))
o1 = self.b2(self.c2(tmp))
o2 = torch.zeros_like(o1)
if self.c3 != None:
o2 = self.c3(X)
Y = nn.functional.relu(o1 + o2)
return Y
blk = Residual(3,3)
X = torch.rand(4, 3, 6, 6)
Y = blk(X)
Y.shape
# 下面即为copy
def resnet_block(input_channels, num_channels, num_residuals,
first_block=False):
blk = []
for i in range(num_residuals):
if i == 0 and not first_block:
blk.append(Residual(input_channels, num_channels,
use_1x1conv=True, strides=2))
else:
blk.append(Residual(num_channels, num_channels))
return blk
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))
net = nn.Sequential(b1, b2, b3, b4, b5,
nn.AdaptiveAvgPool2d((1,1)),
nn.Flatten(), nn.Linear(512, 10))
lr, num_epochs, batch_size = 0.1, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu_mps(), 'relu')
显然过拟合了

更多推荐
所有评论(0)