一、[Lenet](https://zhuanlan.zhihu.com/p/116181964)
二、[Alexnet](https://zhuanlan.zhihu.com/p/116197079)
三、[VGG](https://zhuanlan.zhihu.com/p/116197079)
前言
2012 年, AlexNet 横空出世。这个模型的名字来源于论⽂第一作者的姓名 Alex Krizhevsky。AlexNet 使⽤了 8 层卷积神经⽹络,并以很⼤的优势赢得了 ImageNet 2012 图像识别挑战赛冠军。
一、Alexnet网络结构
Alexnet模型由5个卷积层和3个池化Pooling 层 ,其中还有3个全连接层构成。AlexNet 跟 LeNet 结构类似,但使⽤了更多的卷积层和更⼤的参数空间来拟合⼤规模数据集 ImageNet。它是浅层神经⽹络和深度神经⽹络的分界线。
特点:
- 1、在每个卷机后面添加了Relu激活函数,解决了Sigmoid的梯度消失问题,使收敛更快。
- 2、使用随机丢弃技术(dropout)选择性地忽略训练中的单个神经元,避免模型的过拟合(也使用数据增强防止过拟合)
- 3、添加了归一化LRN(Local Response Normalization,局部响应归一化)层,使准确率更高。
- 4、重叠最大池化(overlapping max pooling),即池化范围 z 与步长 s 存在关系 z>s 避免平均池化(average pooling)的平均效应
补充
LRN与BN的区别:https://www.jianshu.com/p/ef689144c86e
深入理解Bachnormlization:https://zhuanlan.zhihu.com/p/87117010
简单的理解:BN是数据层面,LRN是通道层面,LRN是作用于卷积的一种优化,一般用于激活函数ReLU函数之后的一层。
二、Alexnet的keras实现
def AlexNet():
model = Sequential()
model.add(Conv2D(96,(11,11),strides=(4,4),input_shape=(227,227,3),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Conv2D(256,(5,5),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Flatten())
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1000,activation='softmax'))
return model
在实际使用过程中,通常会加入BN层,重新定义卷积层::BN应用在深度神经网络中最主要的作用是加速神经网络训练,并使模型训练更加稳定(可以适应大的学习率,对参数初始化不敏感),避免了人工适应调整网络超参数。
def Conv_block(layer, filters, kernerl_size=(3, 3), strides=(1, 1), padding="valid", name=None):
x = Conv2D(filters=filters, kernel_size=kernel_size, strides=strides, padding=padding, name=name)(layer)
x = BatchNormalization()(x)
x = Activation("relu")(x)
return x
三、Alexnet的pytorch实现
import time
import torch
from torch import nn, optim
import torchvision
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
nn.ReLU(),
nn.MaxPool2d(3, 2), # kernel_size, stride
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
# 前两个卷积层后不使用池化层来减小输入的高和宽
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
# 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
self.fc = nn.Sequential(
nn.Linear(256*5*5, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
nn.Linear(4096, 10),
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
Pytorch 源码中实现了LRN的操作,可以看到与Alexnet论文中的方法略有不同,α所乘的项由所有数值的平方和变成了所有数值的均值,但无论是使用均值还是平方和,两者都起到了 lateral inhibition(横向抑制)的作用。
def local_response_norm(input, size, alpha=1e-4, beta=0.75, k=1.):
# type: (Tensor, int, float, float, float) -> Tensor
r"""Applies local response normalization over an input signal composed of
several input planes, where channels occupy the second dimension.
Applies normalization across channels.
See :class:`~torch.nn.LocalResponseNorm` for details.
"""
dim = input.dim()
if dim < 3:
raise ValueError('Expected 3D or higher dimensionality
input (got {} dimensions)'.format(dim))
div = input.mul(input).unsqueeze(1)
if dim == 3:
div = pad(div, (0, 0, size // 2, (size - 1) // 2))
div = avg_pool2d(div, (size, 1), stride=1).squeeze(1)
else:
sizes = input.size()
div = div.view(sizes[0], 1, sizes[1], sizes[2], -1)
div = pad(div, (0, 0, 0, 0, size // 2, (size - 1) // 2))
div = avg_pool3d(div, (size, 1, 1), stride=1).squeeze(1)
div = div.view(sizes)
div = div.mul(alpha).add(k).pow(beta)
return input / div
下面我们用pytorch简单实现以下BN层(仅训练阶段)
import torch
class BatchNorm2d(torch.nn.Module):
def __init__(self, channel, eps=1e-5, affine=True, momentum=0.9):
super().__init__()
# 初始化训练参数
self.gamma = torch.nn.Parameter(torch.ones(1, channel, 1, 1))
self.beta = torch.nn.Parameter(torch.zeros(1, channel, 1, 1))
self.eps = eps
self.affine = affine
self.momentum = momentum
self.register_buffer('running_mean', torch.zeros(channel))
self.register_buffer('running_var', torch.ones(channel))
def forward(self, input):
# input shape must be (n, c, h, w)
if self.training:
means = input.mean((0, 2, 3), keepdim=True)
vars = ((input-means)**2).sum((0, 2, 3), keepdim=True)
self.running_mean = self.momentum * self.running_mean + (1-self.momentum) * means
self.running_var = self.momentum * self.running_var + (1-self.momentum) * vars
else:
means = self.running_mean
vars = self.running_var
output = (input - means) / torch.sqrt(vars + self.eps)
if self.affine:
output = output* self.gamma + self.beta
return output
五、ZF-net
ZFNet是2013ImageNet分类任务的冠军,其网络结构没什么改进,只是调了调参,性能较Alex提升了不少。ZF-Net只是将AlexNet第一层卷积核由11变成7,步长由4变为2,第3,4,5卷积层转变为384,384,256。
ZF-net的keras实现:
def ZF_Net():
model = Sequential()
model.add(Conv2D(96,(7,7),strides=(2,2),input_shape=(224,224,3),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Conv2D(256,(5,5),strides=(2,2),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model.add(Flatten())
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1000,activation='softmax'))
return model
我是尾巴~
每日一句毒鸡汤:
没知觉的开始,猜不到的结局!不能攥在手心的无奈都是源于自己的无能,越是害怕失去的东西往往总是如愿以偿,第一次的自负,第二次的无知,第三次的莫名其妙,或许一切都是自己想太多,表面上的东西过于华丽,根本看不清真相。自己做出的每一个选择都是有代价的,至于回报,要么感觉理所当然,要么感觉自作自受!一念之差,或许结果相同,但心理经历却天差地别。很多事情在经历过之后很长时间才发现原来一切都那么巧合,就像被安排好的一样!
本次推荐:
一款好用的文字OCR识别软件:天若OCR
天若OCR文字识别tianruoocr.cn继续加油~