深度学习(七)一些神经网络的构架
- 多层感知器
前馈神经网络,也可以叫多层感知器(multi-layer perceptron, MLP),是由多个感知器组成的神经网络。与单个感知器不同的是,MLP能够学习到非线性的特征,因此在回归和分类里都有很多应用。
MLP一般由一层输入层,几层隐藏层和一个输出层,就像下图。
隐藏层和输出层里都是有激活函数的,每一层的神经元与同一层的其他神经元没有关联,与上一层的所有神经元都有联系(全连接)。
关于前馈神经网络,深度学习笔记(1)--前馈神经网络。
接下来利用pytorch实现上面图里的神经网络。
class NeuralNet(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(NeuralNet, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
model = NeuralNet(input_size=3,
- 卷积神经网络
卷积神经网络适合用于图像处理,卷积操作可以提取出图片的特征。一般的卷积神经网络包括卷积层、池化层和全连接层。卷积层提取信息,池化层降维,全连接层输出结果。卷积层和池化层会多次使用,以达到提出特征的目的,比如LeNet的结构:
LeNet
pytorch 实现一个简单的卷积神经网络:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 1 input image channel, 6 output channels, 3x3 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 3)
self.conv2 = nn.Conv2d(6, 16, 3)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimension
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# Max pooling over a (2, 2) window
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
接下来就是一些经典的CNN模型
- LeNet
结构就是上面那张图,1998年提出来的,包括两个卷积层+池化层,一个flatten层,两个全连接层和一个softmax的分类器。
特点:
- 使用卷积提取空间特征
- 使用average pooling做采样
- 使用tanh作为非线性的激活函数
- S2和C3之间的连接
LeNet 提出的卷积-池化-非线性激活函数的顺序,为以后的许多结构提供了基础。
- AlexNet
特点:
- AlexNet中用到了ReLU,虽然在现在大家都用ReLU,以至于这一条显得平平无奇。
- AlexNet还使用了两个GPU并行训练,也就是上面结构图里的上下两层,每个GPU只用一半的神经元,并且在某些层进行连接。这样做能让训练相对快一点,并且降低了错误率。
- 使用了重叠池化,stride=2,size=3,这个操作也能减少错误率。
- dropout,减少过拟合。神仙一样的方法,以0.5的概率把隐藏层神经元的输出设为0,被设为0的神经元在反向的时候也没有梯度。作者在前两个全连接层上使用了dropout。
- mini-batch SGD+momentum (0.9 )+ weight decay(0.0005)。具体的参数迭代规则是这样的:
update rule for weight
pytorch 可以直接调用 torchvision.models.alexnet(), 在这里放上具体的结构实现:
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(64, 192, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(192, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
-
Network In Network
Network in network结构,包括三个mlpcov层和一个GAP层
特点:
- 1x1卷积核,提供非线性,减少参数
- 全局平均池化,避免过拟合
CNN中的卷积操作可以看作是一种广义的线性操作,对于高度非线性的特征,CNN可能需要许多滤波器来进行特征提取,从而导致模型的参数过多。
Network in network提出使用多层感知器作为通用函数逼近器来对局部的特征进行提取。使用多层感知器的原因是,首先,多层感知器与使用反向传播训练的卷积神经网络结构兼容。 其次,多层感知器本身可以是一个深层模型,这符合特征复用的思想。
使用多个级联的1x1的卷积核对特征图做卷积,可以实现特征图的非线性组合,同时使用1x1卷积核还可以减少或者增加通道数,实现降维或者升维,减少参数。
NIN的另一个进步之处在于使用了全局平均池化(Global Average Pooling, GAP)取代全连接层作为最后一层,具体做法是取每个特征图的平均值,然后将所得的向量直接输入softmax层实现分类,这样做的优点是,在全局平均池中没有要优化的参数,减小了参数规模,避免了过拟合。此外,全局平均池汇总了空间信息,因此对输入的空间转换更加健壮。
class NIN(nn.Module):
def __init__(self, num_classes=1000):
super(NIN, self).__init__()
self.num_classes = num_classes
self.features = nn.Sequential(
nn.Conv2d(3, 192, 5, padding=2),
nn.ReLU(inplace=True),
nn.Conv2d(192, 160, 1),
nn.ReLU(inplace=True),
nn.Conv2d(160, 96, 1),
nn.ReLU(inplace=True),
nn.MaxPool2d(3, stride=2, ceil_mode=True),
nn.Dropout(inplace=True),
nn.Conv2d(96, 192, 5, padding=2),
nn.ReLU(inplace=True),
nn.Conv2d(192, 192, 1),
nn.ReLU(inplace=True),
nn.Conv2d(192, 192, 1),
nn.ReLU(inplace=True),
nn.AvgPool2d(3, stride=2, ceil_mode=True),
nn.Dropout(inplace=True),
nn.Conv2d(192, 192, 3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(192, 192, 1),
nn.ReLU(inplace=True),
nn.Conv2d(192, self.num_classes, 1),
nn.ReLU(inplace=True),
nn.AvgPool2d(8, stride=1)
)
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), self.num_classes)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
m.weight.data.normal_(0, 0.05)
if m.bias is not None:
m.bias.data.zero_()
Network in Network
Network in Network代码
深度学习基础模型NIN(Network in Network)+Pytorch
- VGG
VGG于2014年由牛津大学Visual Geometry Group组提出的,在AlexNet的基础上加深了网络。
特点:
- 使用多个较小的卷积核(3x3)组合以获得更大的感受野,但是所需要的参数更少
- 比较难训练,常被用作预训练
下面是pytorch里vgg11的代码,可以看出来结构与AlexNet很相似,不过层数更多:
class VGG(nn.Module):
def __init__(self, features, num_classes=1000, init_weights=True):
super(VGG, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn.ReLU(inplace=True)
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
nn.Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn.ReLU(inplace=True)
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
nn. Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn. ReLU(inplace=True)
nn. Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn. ReLU(inplace=True)
nn. MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
nn.Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn. ReLU(inplace=True)
nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn. ReLU(inplace=True)
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn. ReLU(inplace=True)
nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
nn.ReLU(inplace=True)
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
self.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, num_classes),
)
if init_weights:
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
- GoogleNet
(Inception-v1)
- bottleneck layer
- ResNet
随着网络结构的加深,人们发现深层的网络的训练和测试误差比浅层的网络还要大,并且这一现象并不是由过拟合造成的。原因就在于在深层的网络中随着层数的加深,特征和梯度传递可能会发生偏移。
Residual Block
9.MobileNet
- EfficientNet