经典卷积网络算法-VGG16
目录
前言
TensorFlow 2.x 中的 tf.keras.applications
使用示例
主要参数
迁移学习
TensorFlow 2.x 的优势
VGG16
前置理解:全连接池化层
具体作用
与 1x1 池化的区别
使用场景
示例
与 1x1 池化的对比
总结
VGG16 的原始结构
全局平均池化层在 VGG16 中的应用
1. 替代全连接层
2. 优势
修改后的 VGG16 结构示例
修改后的模型结构
对比原始 VGG16 和修改后的模型
使用场景
总结
前言
tip:学习Keras时可以借助TensorFlow 2.x,通过tensorflow来使用keras会更加实用高效
TensorFlow 2.x 版本中的 Keras 接口(tf.keras)完全继承了 Keras 的功能,并且提供了与独立 Keras 相同的预训练模型和接口。
TensorFlow 2.x 中的 tf.keras.applications
以下是一些常见的预训练模型及其在 TensorFlow 2.x 中的调用方式:
- VGG16 / VGG19:
from tensorflow.keras.applications import VGG16, VGG19
model = VGG16(weights='imagenet', include_top=False)
- ResNet:
from tensorflow.keras.applications import ResNet50
model = ResNet50(weights='imagenet', include_top=False)
- InceptionV3:
from tensorflow.keras.applications import InceptionV3
model = InceptionV3(weights='imagenet', include_top=False)
- MobileNet:
from tensorflow.keras.applications import MobileNet, MobileNetV2
model = MobileNet(weights='imagenet', include_top=False)
- DenseNet:
from tensorflow.keras.applications import DenseNet121
model = DenseNet121(weights='imagenet', include_top=False)
- EfficientNet:
from tensorflow.keras.applications import EfficientNetB0
model = EfficientNetB0(weights='imagenet', include_top=False)
- Xception:
from tensorflow.keras.applications import Xception
model = Xception(weights='imagenet', include_top=False)
使用示例
以下是一个完整的迁移学习示例,使用 TensorFlow 2.x 中的 tf.keras 接口:
import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.models import Model
# 加载预训练的 ResNet50 模型,不包括顶层
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# 冻结预训练模型的权重(可选)
base_model.trainable = False
# 添加自定义顶层
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x) # 假设有 10 个类别
# 构建最终模型
model = Model(inputs=base_model.input, outputs=predictions)
# 编译模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 打印模型结构
model.summary()
主要参数
- weights: 指定是否加载预训练权重(如 'imagenet')。
- include_top: 是否包含顶层的全连接层。
- input_shape: 输入图像的形状(如果不包含顶层,则需要指定)。
- pooling: 如果不包含顶层,可以通过 pooling='avg' 或 pooling='max' 添加全局池化层。
迁移学习
在 TensorFlow 2.x 中,迁移学习的流程与独立 Keras 相同:
- 加载预训练模型并冻结部分或全部层。
- 添加自定义顶层。
- 编译模型并训练。
例如,冻结预训练模型的权重:
base_model.trainable = False
或者在微调时解冻部分层:
for layer in base_model.layers[:100]:
layer.trainable = False
for layer in base_model.layers[100:]:
layer.trainable = True
TensorFlow 2.x 的优势
- 无缝集成: tf.keras 与 TensorFlow 的其他功能(如 tf.data、tf.function、tf.distribute)深度集成。
- 性能优化: TensorFlow 2.x 提供了更好的性能优化(如 XLA 编译、混合精度训练)。
- 生态系统: 可以使用 TensorFlow 的完整生态系统(如 TensorBoard、TFX、TensorFlow Serving)。
VGG16
前置理解:全连接池化层
问题:GlobalAveragePooling2D是全局平均池化层?就是池化核是1*1吗
GlobalAveragePooling2D 是 全局平均池化层,但它并不是使用 1x1 的池化核。它的作用是对输入的每个特征图(channel)进行全局平均池化,将每个特征图的所有值取平均,输出一个单一的值。
`GlobalAveragePooling2D` 是 全局平均池化层,但它并不是使用 1x1 的池化核。它的作用是对输入的每个特征图(channel)进行全局平均池化,将每个特征图的所有值取平均,输出一个单一的值。
具体作用
假设输入的特征图尺寸为 `(height, width, channels)`,`GlobalAveragePooling2D` 会对每个通道(channel)的所有像素值取平均,最终输出的形状为 `(channels,)`。
例如:
- 输入形状:`(batch_size, height, width, channels)`
- 输出形状:`(batch_size, channels)`
与 1x1 池化的区别
- 1x1 池化:使用 1x1 的池化核,对输入的每个局部区域(1x1)进行池化操作。它不会改变特征图的空间维度(height 和 width),只是对每个像素进行操作。
- 全局平均池化:对每个通道的所有像素值取平均,完全消除了空间维度(height 和 width),只保留通道维度。
使用场景
`GlobalAveragePooling2D` 通常用于:
1. 替代全连接层:在一些现代网络架构(如 ResNet、MobileNet)中,全局平均池化层被用来替代全连接层,从而减少参数数量并防止过拟合。
2. 特征聚合:将空间信息聚合为通道维度的全局特征,常用于图像分类任务。
3. 减少计算量:通过消除空间维度,减少后续层的计算量。
示例
以下是一个简单的示例,展示 `GlobalAveragePooling2D` 的作用:
import tensorflow as tf
from tensorflow.keras.layers import Input, GlobalAveragePooling2D
# 假设输入是一个 4x4 的特征图,通道数为 3
input_tensor = Input(shape=(4, 4, 3))
# 添加全局平均池化层
output_tensor = GlobalAveragePooling2D()(input_tensor)
# 构建模型
model = tf.keras.Model(inputs=input_tensor, outputs=output_tensor)
# 打印模型结构
model.summary()
# 创建一个示例输入(batch_size=1, height=4, width=4, channels=3)
example_input = tf.ones((1, 4, 4, 3))
# 获取输出
output = model(example_input)
print("Input shape:", example_input.shape)
print("Output shape:", output.shape)
print("Output values:", output.numpy())
输出结果:
Input shape: (1, 4, 4, 3)
Output shape: (1, 3)
Output values: [[1. 1. 1.]]
解释:
- 输入是一个 4x4 的特征图,通道数为 3。
- 全局平均池化层对每个通道的所有 16 个像素值取平均,得到 3 个平均值(每个通道一个)。
- 输出形状为 `(1, 3)`,表示每个通道的平均值。
与 1x1 池化的对比
以下是一个 1x1 池化的示例:
from tensorflow.keras.layers import MaxPooling2D
# 添加 1x1 池化层
output_tensor_1x1 = MaxPooling2D(pool_size=(1, 1))(input_tensor)
# 构建模型
model_1x1 = tf.keras.Model(inputs=input_tensor, outputs=output_tensor_1x1)
# 获取输出
output_1x1 = model_1x1(example_input)
print("1x1 Pooling output shape:", output_1x1.shape)
输出结果:
1x1 Pooling output shape: (1, 4, 4, 3)
解释:
- 1x1 池化不会改变特征图的空间维度,输出形状仍然是 `(1, 4, 4, 3)`。
总结
- `GlobalAveragePooling2D` 是全局平均池化层,对每个通道的所有像素值取平均,输出形状为 `(batch_size, channels)`。
- 它不是 1x1 池化,1x1 池化只是对每个像素进行操作,不会改变空间维度。
- 全局平均池化常用于替代全连接层或减少计算量。
问题:全平均池化层在VGG16中的应用
在 VGG16 中,全局平均池化层(Global Average Pooling, GAP) 并不是原始网络结构的一部分。VGG16 的原始设计使用了全连接层(Fully Connected Layers)来将卷积层提取的特征映射到分类结果。然而,全局平均池化层可以在对 VGG16 进行修改或迁移学习时使用,以替代全连接层,从而减少参数数量并防止过拟合。
在 VGG16 中,全局平均池化层(Global Average Pooling, GAP) 并不是原始网络结构的一部分。VGG16 的原始设计使用了全连接层(Fully Connected Layers)来将卷积层提取的特征映射到分类结果。然而,全局平均池化层可以在对 VGG16 进行修改或迁移学习时使用,以替代全连接层,从而减少参数数量并防止过拟合。
VGG16 的原始结构
VGG16 的原始结构如下:
1. 卷积层:13 个卷积层(使用 3x3 卷积核)。
2. 池化层:5 个最大池化层(2x2 池化核,步幅为 2)。
3. 全连接层:3 个全连接层(前两个有 4096 个神经元,最后一个有 1000 个神经元,对应 ImageNet 的 1000 个类别)。
4. Softmax 分类器:输出类别概率。
VGG16 的全连接层引入了大量参数(约 1.2 亿个参数中的 90% 来自全连接层),这可能导致过拟合,尤其是在数据集较小的情况下。
全局平均池化层在 VGG16 中的应用
在迁移学习或修改 VGG16 时,可以用全局平均池化层替代全连接层。以下是具体步骤和优势:
1. 替代全连接层
- 移除 VGG16 的原始全连接层。
- 在最后一个卷积层后添加全局平均池化层。
添加一个输出层(如 `Dense` 层)用于分类。
2. 优势
- 减少参数数量:全局平均池化层没有可训练的参数,显著减少了模型复杂度。
- 防止过拟合:减少参数数量有助于防止过拟合,尤其是在小数据集上。
- 空间不变性:全局平均池化对输入图像的空间位置不敏感,更适合处理不同尺寸的输入。
修改后的 VGG16 结构示例
以下是一个使用全局平均池化层修改 VGG16 的示例:
import tensorflow as tf
from tensorflow.keras.applications import VGG16
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense
from tensorflow.keras.models import Model
# 加载 VGG16 模型,不包括顶层(全连接层)
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# 添加全局平均池化层
x = base_model.output
x = GlobalAveragePooling2D()(x)
# 添加自定义输出层(假设有 10 个类别)
predictions = Dense(10, activation='softmax')(x)
# 构建最终模型
model = Model(inputs=base_model.input, outputs=predictions)
# 打印模型结构
model.summary()
修改后的模型结构
修改后的模型结构如下:
1. 卷积层:VGG16 的 13 个卷积层。
2. 全局平均池化层:对每个特征图取平均值,输出形状为 `(batch_size, 512)`。
3. 输出层:一个 `Dense` 层,输出类别概率。
对比原始 VGG16 和修改后的模型
使用场景
- 迁移学习:在小数据集上微调 VGG16 时,使用全局平均池化层可以减少过拟合。
- 输入尺寸灵活:全局平均池化层允许输入图像的尺寸不固定(如非 224x224)。
- 轻量化模型:减少参数数量,适合资源受限的环境。
总结
虽然全局平均池化层不是 VGG16 原始结构的一部分,但在迁移学习或修改 VGG16 时,可以用它替代全连接层,从而减少参数数量、防止过拟合,并提高模型的灵活性。这种方法在现代深度学习实践中非常常见,尤其是在处理小数据集或需要轻量化模型时。
问题:为什么VGG16网络中输入的图像原始size至少为32?在大于32的同时是否需要满足size是32的倍数?
VGG16 网络中输入的图像尺寸至少为 32x32,是因为网络经过 5 次最大池化层(每次缩小一半),最终特征图会缩小到 1x1,如果输入小于 32x32,池化后特征图会消失,无法进行计算。输入尺寸不需要是 32 的倍数,但必须是池化层能正确处理的大小(即每次池化后尺寸为整数),所以常见的输入尺寸是 224x224,这是经过实验验证的高效尺寸。
问题:opencv库对于图像识别、目标检测类的深度学习任务设计的网络中起到什么作用,可以用VGG16、YOLO等网络作为例子说明?
OpenCV 在图像识别和目标检测任务中主要起到预处理和后处理的作用。例如,在使用 VGG16 或 YOLO 等深度学习网络时,OpenCV 可以用于读取图像、调整尺寸、归一化、颜色空间转换等预处理操作,以及将网络的输出结果(如边界框、类别标签)可视化到图像上。它本身不负责训练或推理,但为深度学习模型提供了高效的数据处理和结果展示工具。
OpenCV、Matplotlib 和 AI 框架(如 TensorFlow、PyTorch)的预处理方法各有侧重:OpenCV 专注于高效的图像操作(如缩放、裁剪、颜色转换),适合实际应用中的预处理;Matplotlib 主要用于图像的可视化和展示,便于调试和分析;而 AI 框架自带的预处理方法(如 tf.image、torchvision.transforms)则更贴合模型训练的需求,通常与数据加载器集成,支持批量处理和增强。三者可以结合使用,OpenCV 处理数据,Matplotlib 可视化结果,AI 框架完成模型训练和推理。