在正文开始之前,先给大家带来一个超值福利!
为了方便同学们快速开启人工智能学习计划,在学习过程中少走弯路用最快的效率入门Ai并开始实战项目。
我们整理了近200个Ai实战案例和项目,这些并不是网上搜集来的,而是我们这五年线上线下教学所开发和积累的案例。-* 可以说都是反复迭代更新出来的,适合同学们来进行循序渐进的学习与练手。需要的扫码
VGG
简介
VGG(Visual Geometry Group)是由牛津大学视觉几何组提出的深度卷积神经网络,它在 2014 年的 ImageNet 大规模视觉识别挑战赛(ILSVRC)中取得了优异的成绩。VGG 的主要贡献在于证明了增加网络的深度可以显著提高模型的性能,其网络结构简单且规整,具有很强的可扩展性。
VGG 网络结构
VGG 网络有多个版本,常见的有 VGG11、VGG13、VGG16 和 VGG19,其中数字代表网络中卷积层和全连接层的总数。以 VGG16 为例,其网络结构如下:
-
输入层:接收固定大小的图像(如 224x224x3)。
-
卷积层:采用多个 3x3 的小卷积核进行卷积操作,通过堆叠多个卷积层来增加网络的深度。每个卷积层后都跟有 ReLU 激活函数。
-
池化层:在部分卷积层后使用最大池化(Max Pooling),池化窗口大小为 2x2,步长为 2,用于降低特征图的分辨率。
-
全连接层:共有 3 个全连接层,前两个全连接层各有 4096 个神经元,最后一个全连接层有 1000 个神经元,对应 ImageNet 数据集的 1000 个类别。最后一个全连接层的输出通过 softmax 函数转换为概率分布,用于分类。
这也太全了吧!AlexNet、ResNet、VGG、GoogleNet、模型微调、图像增强方法一次性学会计算机视觉之图像分类入门到实战课程!
代码实现
import torch
from torch import nn
# VGG16 网络结构
def vgg_block(num_convs, in_channels, out_channels):
layers = []
for _ in range(num_convs):
layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
layers.append(nn.ReLU())
in_channels = out_channels
layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
return nn.Sequential(*layers)
conv_arch = ((2, 3, 64), (2, 64, 128), (3, 128, 256), (3, 256, 512), (3, 512, 512))
def vgg(conv_arch):
conv_blks = []
in_channels = 3
for (num_convs, in_channels, out_channels) in conv_arch:
conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
return nn.Sequential(
*conv_blks,
nn.Flatten(),
nn.Linear(512 * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 1000)
)
net = vgg(conv_arch)
VGG 特点
-
小卷积核:使用多个 3x3 的小卷积核代替大卷积核,在减少参数数量的同时增加了网络的非线性,提高了模型的表达能力。
-
深度结构:通过堆叠多个卷积层和全连接层,增加了网络的深度,从而能够学习到更复杂的特征。
-
简单规整:网络结构简单且规整,易于实现和理解。
GoogleNet
简介
GoogleNet(也称为 Inception 网络)是由 Google 团队在 2014 年提出的深度卷积神经网络,它在 ImageNet 挑战赛中夺冠。GoogleNet 的主要创新点在于引入了 Inception 模块,通过在一个模块中并行使用不同大小的卷积核和池化操作,能够同时捕捉不同尺度的特征,提高了模型的性能和计算效率。
GoogleNet 网络结构
GoogleNet 主要由多个 Inception 模块和少量的卷积层、池化层、全连接层组成。其整体结构如下:
-
输入层:接收固定大小的图像(如 224x224x3)。
-
初始卷积层和池化层:使用 7x7 和 3x3 的卷积核进行卷积操作,然后使用最大池化降低特征图的分辨率。
-
Inception 模块:多个 Inception 模块堆叠在一起,每个 Inception 模块包含多个并行的分支,分别使用不同大小的卷积核和池化操作,最后将各个分支的输出在通道维度上拼接起来。
-
全局平均池化层:在网络的最后部分使用全局平均池化层,将特征图的每个通道的平均值作为该通道的输出,减少了全连接层的参数数量。
-
输出层:最后一个全连接层的输出通过 softmax 函数转换为概率分布,用于分类。
Inception 模块
Inception 模块的结构如下:
-
1x1 卷积:用于降低输入特征图的通道数,减少计算量。
-
3x3 卷积:捕捉局部特征。
-
5x5 卷积:捕捉更大尺度的特征。
-
3x3 最大池化:提供不同尺度的信息。
代码实现
import torch
from torch import nn
# Inception 模块
class Inception(nn.Module):
def __init__(self, in_channels, c1, c2, c3, c4):
super(Inception, self).__init__()
# 线路1,单1x1卷积层
self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
# 线路2,1x1卷积层后接3x3卷积层
self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
# 线路3,1x1卷积层后接5x5卷积层
self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
# 线路4,3x3最大池化层后接1x1卷积层
self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)
def forward(self, x):
p1 = nn.functional.relu(self.p1_1(x))
p2 = nn.functional.relu(self.p2_2(nn.functional.relu(self.p2_1(x))))
p3 = nn.functional.relu(self.p3_2(nn.functional.relu(self.p3_1(x))))
p4 = nn.functional.relu(self.p4_2(self.p4_1(x)))
# 在通道维度上连结输出
return torch.cat((p1, p2, p3, p4), dim=1)
# GoogleNet 网络结构
b1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.MaxPool2d(kernel_size=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)
)
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)
)
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)
)
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()
)
net = nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 1000))
GoogleNet 特点
-
Inception 模块:通过并行使用不同大小的卷积核和池化操作,能够同时捕捉不同尺度的特征,提高了模型的性能和计算效率。
-
全局平均池化:使用全局平均池化层代替全连接层,减少了参数数量,降低了过拟合的风险。
-
深度结构:网络深度较大,能够学习到更复杂的特征。
ResNet
简介
ResNet(Residual Network)是由微软研究院的何恺明等人在 2015 年提出的深度卷积神经网络,它在 ImageNet 挑战赛中取得了优异的成绩。ResNet 的主要创新点在于引入了残差块(Residual Block),通过跳跃连接(Skip Connection)解决了深度神经网络中的梯度消失和梯度爆炸问题,使得网络可以训练更深的模型。
ResNet 网络结构
ResNet 主要由多个残差块和少量的卷积层、池化层、全连接层组成。以 ResNet18 为例,其网络结构如下:
-
输入层:接收固定大小的图像(如 224x224x3)。
-
初始卷积层和池化层:使用 7x7 的卷积核进行卷积操作,然后使用最大池化降低特征图的分辨率。
-
残差块:多个残差块堆叠在一起,每个残差块包含两个 3x3 的卷积层和一个跳跃连接。跳跃连接将输入直接加到卷积层的输出上,使得网络可以学习到残差映射。
-
全局平均池化层:在网络的最后部分使用全局平均池化层,将特征图的每个通道的平均值作为该通道的输出,减少了全连接层的参数数量。
-
输出层:最后一个全连接层的输出通过 softmax 函数转换为概率分布,用于分类。
残差块
残差块的结构如下:
-
卷积层:包含两个 3x3 的卷积层,每个卷积层后都跟有 ReLU 激活函数。
-
跳跃连接:将输入直接加到卷积层的输出上,使得网络可以学习到残差映射。
代码实现
import torch
from torch import nn
# 残差块
class Residual(nn.Module):
def __init__(self, in_channels, out_channels, use_1x1conv=False, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1, stride=stride)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)
if use_1x1conv:
self.conv3 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride)
else:
self.conv3 = None
self.bn1 = nn.BatchNorm2d(out_channels)
self.bn2 = nn.BatchNorm2d(out_channels)
def forward(self, X):
Y = nn.functional.relu(self.bn1(self.conv1(X)))
Y = self.bn2(self.conv2(Y))
if self.conv3:
X = self.conv3(X)
Y += X
return nn.functional.relu(Y)
# ResNet18 网络结构
b1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
def resnet_block(in_channels, out_channels, num_residuals, first_block=False):
blk = []
for i in range(num_residuals):
if i == 0 and not first_block:
blk.append(Residual(in_channels, out_channels, use_1x1conv=True, stride=2))
else:
blk.append(Residual(out_channels, out_channels))
return blk
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, 1000)
)
ResNet 特点
-
残差块:通过跳跃连接解决了深度神经网络中的梯度消失和梯度爆炸问题,使得网络可以训练更深的模型。
-
深度结构:网络深度较大,能够学习到更复杂的特征。
-
高效性:残差块的设计使得网络在增加深度的同时,计算量并没有显著增加。
想要完整可运行代码?我们为大家准备了近200个AI实战代码,打开即可运行!机智的小伙伴已经开始点赞扫码啦!
小结
本期深入探讨了经典 CNN 架构及计算机视觉相关的多个方面:
-
经典 CNN 架构剖析:
-
VGG:以简单规整的结构,通过堆叠小卷积核和全连接层增加深度,证明了深度对模型性能的提升作用。
-
GoogleNet:引入 Inception 模块,并行使用不同卷积核和池化操作,结合全局平均池化,提升了性能与计算效率。
-
ResNet:凭借残差块和跳跃连接,解决了深度网络的梯度问题,使网络可训练更深。
-
有以下论文写作问题的可以扫下方名片详聊
前沿顶会、期刊论文、综述文献浩如烟海,不知道学习路径,无从下手?
没时间读、不敢读、不愿读、读得少、读不懂、读不下去、读不透彻一篇完整的论文?
CVPR、ICCV、ECCV、ICLR、NeurlPS、AAAI……想发表顶会论文,找不到创新点?
读完论文,仍旧无法用代码复现……
然而,导师时常无法抽出时间指导,想写论文却无人指点…