《python深度学习》笔记(二十一):VGG16网络模型的原理与实现
4.VGG创新点1。使用3x3卷积核替代7x7卷积核的好处?2 个 3x3 的卷积核叠加,它们的感受野等同于 1 个 5x5 的卷积核,3 个叠加后,它们的感受野等同于 1 个 7x7 的效果。由于感受野相同,3个3x3的卷积,使用了3个非线性激活函数,增加了非线性表达能力,从而可以提供更复杂的模式学习。
目录
VGG 最大的特点就是通过比较彻底地采用 3x3 尺寸的卷积核来堆叠神经网络,这样也加深整个神经网络的深度。这两个重要的改变对于人们重新定义卷积神经网络模型架构也有不小的帮助,至少证明使用更小的卷积核并且增加卷积神经网络的深度,可以更有效地提升模型的性能。
1.VGG16结构图
2.VGG16总参数
VGG16总参数量是138M,具体如下:
第1层:1792 = 3*3*3*64+64
第2层:36928 = 3*3*64*64+64
第3层:73856 = 3*3*64*128+128
第4层:147584 = 3*3*128*128+128
第5层:295168 = 3*3*128*256+256
第6层:590080 = 3*3*256*256+256
第7层:590080 = 3*3*256*256+256
第8层:1180160 = 3*3*256*512+512
第9层:2359808 = 3*3*512*512+512
第10层:2359808 = 3*3*512*512+512
第11层:2359808 = 3*3*512*512+512
第12层:2359808 = 3*3*512*512+512
第13层:2359808 = 3*3*512*512+512
第14层:102764544 = 7*7*512*4096+4096
第15层:16781312 = 4096*4096+4096
第16层:4097000 = 4096*1000+1000
3.VGG特点总结
1、VGG16相比AlexNet的一个改进是采用连续的3x3的卷积核代替AlexNet中的较大卷积核(11x11,7x7,5x5)
2、加深结构都使用ReLU激活函数:提升非线性变化的能力
3、VGG16 全部采用3*3卷积核,步长统一为1,Padding统一为1,和2*2最大池化核,步长为2,Padding统一为0
4、VGG19比VGG16的区别在于多了3个卷积层,其它完全一样
5、VGG16基本是AlexNet(AlexNet是8层,包括5个卷积层和3个全连接层)的加强版,深度上是其2倍,参数量大小也是两倍多。
4.VGG创新点
1。使用3x3卷积核替代7x7卷积核的好处?
2 个 3x3 的卷积核叠加,它们的感受野等同于 1 个 5x5 的卷积核,3 个叠加后,它们的感受野等同于 1 个 7x7 的效果。
由于感受野相同,3个3x3的卷积,使用了3个非线性激活函数,增加了非线性表达能力,从而可以提供更复杂的模式学习。
使用3x3卷积核可以减少参数,假设现在有 3 层 3x3 卷积核堆叠的卷积层,输出和输出通道数都是C,那么它的参数总数是 3x(3x3xCxC)=27xCxC 。同样和它感受野大小一样的一个卷积层,卷积核是 7x7 的尺寸,假如输出和输出通道数都是C,那么它的参数总数就是 7x7xCxC=49xCxC。而且通过上述方法网络层数还加深了。三层3x3的卷积核堆叠参数量比一层7x7的卷积核参数链还要少。总的来说,使用3x3卷积核堆叠的形式,既增加了网络层数又减少了参数量。
2。多少个3x3的卷积核可以替代原来11x11的卷积核?
(11-1)/2=5,故5个3x3的卷积核可以替代原来11x11的卷积核,即n-11+1=n+(-3+1)*5
3。VGG的C网络结构使用了1x1卷积核,1x1卷积核的主要好处?
使用多个1x1卷积核,在保持feature map 尺寸不变(即不损失分辨率)的前提下,可以大幅增加非线性表达能力,把网络做得很deep。
进行卷积核通道数的降维和升维。
1x1卷积相当于线性变换,非线性激活函数起到非线性作用。
总结就是:1x1 卷积核的好处是不改变感受野的情况下,进行升维和降维,同时也加深了网络的深度
5.代码(PyTorch版)
import torch
import torch.nn as nn
class VGG16(nn.Module):
def __init__(self, num_classes=10):
super(VGG16, self).__init__()
self.features = nn.Sequential(
#1
nn.Conv2d(3,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
#2
nn.Conv2d(64,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#3
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
#4
nn.Conv2d(128,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#5
nn.Conv2d(128,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#6
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#7
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#8
nn.Conv2d(256,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#9
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#10
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#11
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#12
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#13
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
nn.AvgPool2d(kernel_size=1,stride=1),
)
self.classifier = nn.Sequential(
#14
nn.Linear(512*7*7,4096),
nn.ReLU(True),
nn.Dropout(),
#15
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
#16
nn.Linear(4096,num_classes),
)
#self.classifier = nn.Linear(512, 10)
def forward(self, x):
out = self.features(x)
# print(out.shape)
out = out.view(out.size(0), -1)
# print(out.shape)
out = self.classifier(out)
# print(out.shape)
return out
6.代码(TensorFlow版)
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
def VGG16(input_shape=(224, 224, 3), num_classes=1000):
model = tf.keras.Sequential([
Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=input_shape),
Conv2D(64, (3, 3), activation='relu', padding='same'),
MaxPooling2D((2, 2), strides=(2, 2)),
Conv2D(128, (3, 3), activation='relu', padding='same'),
Conv2D(128, (3, 3), activation='relu', padding='same'),
MaxPooling2D((2, 2), strides=(2, 2)),
Conv2D(256, (3, 3), activation='relu', padding='same'),
Conv2D(256, (3, 3), activation='relu', padding='same'),
Conv2D(256, (3, 3), activation='relu', padding='same'),
MaxPooling2D((2, 2), strides=(2, 2)),
Conv2D(512, (3, 3), activation='relu', padding='same'),
Conv2D(512, (3, 3), activation='relu', padding='same'),
Conv2D(512, (3, 3), activation='relu', padding='same'),
MaxPooling2D((2, 2), strides=(2, 2)),
Conv2D(512, (3, 3), activation='relu', padding='same'),
Conv2D(512, (3, 3), activation='relu', padding='same'),
Conv2D(512, (3, 3), activation='relu', padding='same'),
MaxPooling2D((2, 2), strides=(2, 2)),
Flatten(),
Dense(4096, activation='relu'),
Dense(4096, activation='relu'),
Dense(num_classes, activation='softmax')
])
return model
# 创建一个VGG16模型实例
vgg16 = VGG16()
# 打印模型结构
print(vgg16.summary())
7.两种框架代码的区别
①模块导入
PyTorch:使用 torch.nn 来导入模型的各种层(如 Conv2d、MaxPool2d、Linear 等),然后创建模型实例并定义模型的前向传播过程。
TensorFlow:使用 tf.keras.layers 来导入模型的各种层(如 Conv2D、MaxPooling2D、Dense 等),通过创建 Sequential 或自定义模型类来定义模型。
②展平操作
PyTorch:需要使用 .view() 或 .reshape() 方法手动进行展平操作,如 x.view(-1, 64 * 12 * 12)。
TensorFlow:可以使用 Flatten() 层来自动将多维数据展平。
③结构可视化
PyTorch:通常需要使用额外的库(如 torchsummary)来实现模型结构的可视化。
TensorFlow:model.summary() 可以直接打印出模型结构。
④层的参数格式
PyTorch:通常使用 (通道数, 高度, 宽度) 的参数顺序,如 nn.Conv2d(in_channels, out_channels, kernel_size),
TensorFlow:通常使用 (高度, 宽度, 通道数) 的参数顺序,如 Conv2D(kernel_size, (height, width), ...),
更多推荐
所有评论(0)