第四周,猴痘识别
🍺要求:
训练过程中保存效果最好的模型参数。
加载最佳模型参数识别本地的一张图片。
测试集accuracy到达88%。
参考文章: https://blog.csdn.net/qq_38251616/article/details/126284706
作者:K同学啊
本文为360天深度学习训练营中的学习记录博客
一、前期工作
import pathlib
from tensorflow import keras
from tensorflow.keras import models,layers
import matplotlib.pyplot as plt
import tensorflow as tf
1、导入数据`
data_dir = 'D:\AIoT学习\深度学习训练营\第四周\pictures'
data_dir = pathlib.Path(data_dir)
该文章数据为训练内部数据集
2、查看数据
image_count = len(list(data_dir.glob('*/*.jpg')))
print('图片总数为',image_count)
图片总数为 2142
import PIL
monkeypox = list(data_dir.glob('Monkeypox/*.jpg'))
PIL.Image.open(str(monkeypox[0]))
二、数据预处理
1、加载数据
使用image_dataset_from_directory方法将磁盘中的数据加载到tf.data.Dataset中,与上周一样
测试集与验证集的关系:
-
- 验证集并没有参与训练过程梯度下降过程的,狭义上来讲是没有参与模型的参数训练更新的。
-
- 但是广义上来讲,验证集存在的意义确实参与了一个“人工调参”的过程,我们根据每一个epoch训练之后模型在valid data上的表现来决定是否需要训练进行early stop,或者根据这个过程模型的性能变化来调整模型的超参数,如学习率,batch_size等等。
-
- 因此,我们也可以认为,验证集也参与了训练,但是并没有使得模型去overfit验证集
img_height = 224
img_width = 224
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset='training',
seed=123,
image_size=(img_height,img_width))
Found 2142 files belonging to 2 classes.
Using 1714 files for training.
class_names = train_ds.class_names
print(class_names)
[‘Monkeypox’, ‘Others’]
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset='validation',
seed=123,
image_size=(img_height,img_width))
Found 2142 files belonging to 2 classes.
Using 428 files for validation.
2、可视化数据
plt.figure(figsize=(20,10))
for image,labels in train_ds.take(1):
for i in range(20):
plt.subplot(5,10,i+1)
plt.imshow(image[i].numpy().astype('uint8'))#变量存储为 1 个字节(8 位)的无符号整数
plt.title(class_names[labels[i]])
plt.axis('off')
3、再次检查数据`
for image_batch,labels_batch in train_ds:
print(image_batch.shape) #每批图片的shape
print(labels_batch.shape) #每批图片对应label的shape
break
(32, 224, 224, 3)
(32,)
4、配置数据
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
三、构建CNN网络
num_classes = 2
model = models.Sequential([
layers.experimental.preprocessing.Rescaling(1./255,input_shape=(img_height,img_width,3)),
layers.Conv2D(16,(3,3),activation='relu',input_shape=(img_height,img_width,3)),
layers.MaxPool2D((2,2)), #考虑首先关注这类病的特殊之处而不是背景信息
layers.Conv2D(32,(3,3),activation='relu'),
layers.AveragePooling2D((2,2)),
layers.Conv2D(64,(3,3)),
layers.Flatten(),
layers.Dense(128,activation='relu'),
layers.Dropout(0.3),
layers.Dense(2,activation='sigmoid') #二分类数据,因此激活函数采用sigmoid
])
model.summary()
四、编译
opt = tf.keras.optimizers.Adam(learning_rate=1e-4)
model.compile(optimizer=opt,
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
五、训练模型
tf.keras.callbacks.ModelCheckpoint(
filepath, monitor='val_loss', verbose=0, save_best_only=False,
save_weights_only=False, mode='auto', save_freq='epoch',
options=None, **kwargs)
* monitor:要监视的值
* verbose:信息展示模式,0或1
* save_best_only :设置为True时,检测值有改进时才会保存当前模型
* mode:'auto','min','max'之一,在save_best_only=True时决定性能最佳模型的评判准则,如当检测值为val_acc时,模型应为max,val_loss对应min,在auto模式下,评价准则由被
检测值的名字自动推断
* save_weights_only:若设置为True,则只保存模型权重,否则将保存整个模型
* period:CheckPoint之间间隔的epoch数
回调函数是一个函数的合集,会在训练的阶段中所使用。你可以使用回调函数来查看训练模型的内在状态和统计。你可以传递一个列表的回调函数(作为 callbacks 关键字参数)到 Sequential 或 Model 类型的 .fit() 方法。
- modelcheckpoint在每次迭代之后保存模型
- EarlyStopping :这个callback能监控设定的评价指标,在训练过程中,评价指标不再上升时,训练将会提前结束,防止模型过拟合,
- LearningRateScheduler :模型训练过程中调整学习率,通常而言,随着训练次数的变多,适当地降低学习率有利于模型收敛在全局最优点,因此这个callback需要搭配一个学习率调度器使用,在每个epoch开始时,schedule函数会获取最新的学习率并用在当前的epoch中
- ReduceLROnPlateau:不是按照预先设定好的调度调整学习率,它会在评价指标停止提升时降低学习率
- TerminateOnNaN :在损失变为NaN时停止训练。
from tensorflow.keras.callbacks import ModelCheckpoint
epochs = 50
checkpointer = ModelCheckpoint(filepath = 'best_model.h5',
monitor='val_accuracy',
verbose=1,
save_best_only = True,
mode='max',
save_weights_only=True)
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=epochs,
callbacks=[checkpointer])
最终结果val_accuracy did not improve from 0.89252
画出对应准确率与损失函数图像
可见第10轮后,模型测试集准确率不再有显著提升,但随着训练集损失函数不断减小并趋于稳定,测试集损失函数不断上升,可以看出存在明显过拟合现象,但最优模型的测试集准确率已达到89%
方案二
添加L2正则化,对第一个卷积层修改
layers.Conv2D(16,(3,3),activation='relu',input_shape=(img_height,img_width,3),kernel_regularizer=keras.regularizers.l2(0.05)),
并将池化层全部更改为平均值池化,同时将Drop层参数增加至0.5
最终结果为val_accuracy did not improve from 0.89252
图像为
过拟合情况仍十分明显
方案三
model3 = models.Sequential([
layers.experimental.preprocessing.Rescaling(1./255,input_shape=(img_height,img_width,3)),
layers.Conv2D(16,(3,3),activation='relu',input_shape=(img_height,img_width,3),kernel_regularizer=keras.regularizers.l2(0.1),padding='same'),
layers.AveragePooling2D((2,2)),
layers.Conv2D(32,(3,3),activation='relu'),
layers.AveragePooling2D((2,2)),
layers.Conv2D(64,(3,3),activation='relu'),
layers.AveragePooling2D((2,2)),
layers.Conv2D(128,(3,3),activation='relu'),#增加新卷积层
layers.Dropout(0.5),#对卷积层与全连接层后均添加drop层
layers.Flatten(),
layers.Dense(64,activation='relu'), #将全连接层特征数缩减
layers.Dropout(0.3),
layers.Dense(2,activation='sigmoid')
])
该方案下,测试集损失函数趋于稳定,最高准确率达到了89.4%,但仍有过拟合风险。
2. 指定图片进行预测
#加载效果最好的模型权重
model4.load_weights('best_model4.h5')
import numpy as np
import tensorflow as tf
#img = Image.open("./第四周/pictures/Others/NM15_02_11.jpg")
img = PIL.Image.open(r'D:\AIoT学习\深度学习训练营\第四周\pictures\Others\NM15_02_11.jpg')
image = np.array(img) #需要先转为ndarray格式
image = tf.image.resize(image,size=(224,224))
img_array = tf.expand_dims(image,0)
predictions = model4.predict(img_array)
print("预测结果为:",class_names[np.argmax(predictions)])
预测结果为: Others
总结
当模型出现过拟合时,有时存在随着测试集损失函数随模拟轮次增加逐渐变大的现象,我们通过正则化,drop层,池化等方法有时可以时测试集损失函数趋于稳定的情况,但可能无法显著改善测试集准确率。
通过callsback模块我们可以更好的对模型进行检测,同时仅保留模型优化后的系数