>- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/rbOOmire8OocQ90QM78DRA) 中的学习记录博客**
>- **🍖 原作者:[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)**
我的环境:
- 系统环境:WSL2+Ubuntu22.04
- 语言环境:Python3.8.18
- 编译器:vscode+jupyter notebook
- 深度学习环境:TensorFlow2.10.0
🍺 要求:
1. 使用categorical_crossentropy(多分类的对数损失函数)完成本次选题(完成)
2. 探究不同损失函数的使用场景与代码实现(完成)
🍻 拔高(可选):
1. 自己搭建VGG-16网络框架(完成)
2. 调用官方的VGG-16网络框架(完成)
3. 使用VGG-16算法训练该模型(完成)
🔎 探索(难度有点大)
1. 准确率达到60%(65.00%,完成)
本次项目开始使用在图像分类里面著名的VGG-16模型。
自己搭建的代码如下:
from tensorflow.keras import models, layers
# 构建VGG16模型
model = models.Sequential()
# 添加卷积层部分
model.add(layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)))
model.add(layers.Conv2D(64, (3, 3), activation='relu', input_shape=(img_height, img_width, 3), padding='same'))
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# 添加全连接层部分
model.add(layers.Flatten())
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(len(class_names), activation='softmax')) # 输出层,使用softmax激活函数进行多类别分类
model.summary()
同时也可以使用直接从tensorflow库中调用的方法:
from tensorflow.keras.applications import VGG16
# 加载VGG16模型,不包括全连接层,使用ImageNet的权重
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(img_height, img_width, 3))
# 冻结VGG16的卷积层,不进行训练
base_model.trainable = False
# 在VGG16基础上添加自定义的全连接层
model = models.Sequential([
base_model,
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(len(class_names), activation='softmax)
])
model.summary() # 打印网络结构
模型优化
VGG-16有个严重的缺陷就是模型过于复杂,所以过拟合严重。
直接训练的结果:
Epoch 21/100
51/51 [==============================] - ETA: 0s - loss: 7.0076e-05 - accuracy: 1.0000
Epoch 21: val_accuracy did not improve from 0.41111
51/51 [==============================] - 21s 421ms/step - loss: 7.0076e-05 - accuracy: 1.0000 - val_loss: 6.0546 - val_accuracy: 0.4111
Epoch 22/100
训练准确率达到1,验证准确率只有0.4111,很明显的过拟合,来自于VGG16模型的复杂度过高
首先将调整模型,为模型加入标准化、L2正则化、dropout层:
from tensorflow.keras import models, layers
# 构建VGG16模型
model = models.Sequential()
# 添加卷积层部分
model.add(layers.experimental.preprocessing.Rescaling(1./255, input_shape=(224, 224, 3)))
model.add(layers.Conv2D(64, (3, 3), activation='relu', input_shape=(256, 256, 3), padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# 添加全连接层部分
model.add(layers.Flatten())
model.add(layers.Dense(2048, activation='relu', kernel_regularizer='l2'))
model.add(layers.Dropout(0.3)) # 添加Dropout层
model.add(layers.Dense(1024, activation='relu', kernel_regularizer='l2'))
model.add(layers.Dense(len(class_names), activation='softmax')) # 输出层,使用softmax激活函数进行多类别分类
model.summary()
再进行数据增强:
import tensorflow as tf
def augment_images(image, label):
image = tf.image.random_flip_left_right(image) # 随机水平翻转
image = tf.image.random_contrast(image, lower=0.5, upper=1.5) # 随机对比度
image = tf.image.random_brightness(image, max_delta=0.2) # 随机亮度
image = tf.image.random_saturation(image, lower=0.5, upper=1.5) # 随机饱和度
noise = tf.random.normal(tf.shape(image), mean=0.0, stddev=0.1)
image = tf.clip_by_value(image + noise, 0.0, 1.0) # 添加高斯噪声并将像素值限制在0到1之间
return image, label
# 对训练集数据进行增强
augmented_train_ds = train_ds.map(augment_images)
# 使用增强后的数据进行训练
history = model.fit(augmented_train_ds,
validation_data=val_ds,
epochs=epochs,
callbacks=[checkpointer, earlystopper])
训练结果:
Epoch 48/100
51/51 [==============================] - ETA: 0s - loss: 3.8111 - accuracy: 1.0000
Epoch 48: val_accuracy improved from 0.63889 to 0.65000, saving model to best_model.h5
51/51 [==============================] - 29s 572ms/step - loss: 3.8111 - accuracy: 1.0000 - val_loss: 5.2972 - val_accuracy: 0.6500
65.00%,完成任务