《python深度学习》笔记(二十一):VGG16网络模型的原理与实现

VGG16是深度学习领域的一个经典模型,以其使用连续的3x3卷积核和深层网络架构而闻名。该模型通过减少大尺寸卷积核,增加网络深度,证明了提升模型性能的有效策略。VGG16包含16层,总参数量约138M,主要特点是全部采用3x3卷积,步长1,Padding 1,以及2x2最大池化。此外,它还引入了ReLU激活函数,提升了非线性表达能力。代码示例分别展示了PyTorch和TensorFlow两个框架下的实现。VGG16与AlexNet相比,深度加倍,参数量也相应增加,但使用3x3卷积降低了参数数量,增强了模型表达力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.VGG16结构图 

 2.VGG16总参数

3.VGG特点总结

4.VGG创新点

5.代码(PyTorch版)

6.代码(TensorFlow版)

7.两种框架代码的区别


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), ...),

### VGG16 神经网络结构图及其可视化 VGG16 是一种经典的卷积神经网络架构,在图像分类任务中表现优异。其主要特点是通过堆叠多个小型的 \(3 \times 3\) 卷积核来构建深层网络,同时利用最大池化层逐步降低特征图的空间维度。 #### VGG16 的基本结构 VGG16 主要由 13 个卷积层和 3 个全连接层组成,具体分为以下几个部分: - **输入层**: 接收固定大小的 RGB 图像作为输入(通常是 \(224 \times 224 \times 3\)[^1])。 - **卷积块 (Convolutional Blocks)**: 整体划分为 5 个卷积块,每个块内部包含若干个卷积层以及一个最大池化层。例如 `block1` 中有两个卷积层 (`block1_conv1`, `block1_conv2`) 和一个最大池化层 (`block1_pool`)。 - **全连接层 (Fully Connected Layers)**: 在最后一个卷积块之后,有三个全连接层用于进一步提取高层语义特征并完成分类任务[^2]。 #### 特征图可视化方法 为了更好地理解 VGG16 各层的作用,可以通过 Keras 或 TensorFlow 实现特征图的可视化。以下是实现这一功能的一个典型代码示例: ```python import numpy as np from tensorflow.keras.applications import vgg16 from tensorflow.keras.models import Model import matplotlib.pyplot as plt # 加载预训练模型 base_model = vgg16.VGG16(weights='imagenet', include_top=True) # 提取特定层的输出 layer_name = 'block1_pool' # 替换为你感兴趣的层名 intermediate_layer_model = Model(inputs=base_model.input, outputs=base_model.get_layer(layer_name).output) # 准备测试图片 img_path = 'test_image.jpg' img = vgg16.load_img(img_path, target_size=(224, 224)) x = vgg16.img_to_array(img) x = np.expand_dims(x, axis=0) x = vgg16.preprocess_input(x) # 获取中间层输出 features = intermediate_layer_model.predict(x) # 可视化 feature maps num_features = features.shape[-1] size = features.shape[1] display_grid = np.zeros((size * int(np.sqrt(num_features)), size * int(np.sqrt(num_features)))) for i in range(int(np.sqrt(num_features))): for j in range(int(np.sqrt(num_features))): channel_image = features[0, :, :, i * int(np.sqrt(num_features)) + j] channel_image -= channel_image.mean() channel_image /= channel_image.std() + 1e-5 channel_image *= 64 channel_image += 128 channel_image = np.clip(channel_image, 0, 255).astype('uint8') display_grid[i * size : (i + 1) * size, j * size : (j + 1) * size] = channel_image plt.figure(figsize=(10, 10)) plt.title(f"{layer_name} Feature Maps", fontsize=16) plt.imshow(display_grid, aspect='auto', cmap='viridis') plt.axis('off') plt.show() ``` 上述代码展示了如何加载预训练的 VGG16 模型,并针对某一层(如 `block1_pool`)提取其特征图进行可视化。每张子图代表该层中的某个通道所捕捉到的信息。 #### 关于 Block1 层的具体分析 在 VGG16 架构中,`block1` 被设计用来捕获图像的基础特性,例如边缘、纹理和颜色变化等低级模式。其中: - `block1_conv1`: 初步提取原始像素数据中的简单局部特征; - `block1_conv2`: 基于前一阶段的结果继续深化细节识别过程; - `block1_pool`: 应用 \(2 \times 2\) 最大池化操作减少空间分辨率至原来的四分之一,即从 \(224 \times 224\) 缩减为 \(112 \times 112\),同时保留重要信息。 #### 总结 通过对 VGG16 不同层次上的激活响应进行观察,可以深入了解它如何逐层抽象复杂视觉概念的过程。这种技术不仅有助于调试模型性能瓶颈,还能增强我们对 CNN 工作原理的理解。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序先锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值