猫狗大战在一开始接触深度学习的时候,实现过,也写过一篇博客。但是当时的理解并不是很深,在做过之前的实验之后,再次接触猫狗大战,就有一些别的体会了。
本次实验基于自己搭建的CNN与VGG19的官方模型,实现猫狗大战。引入混淆矩阵与Accuracy_Loss图观察模型准确率。
1.导入库
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import os,pathlib,PIL
from tensorflow import keras
from tensorflow.keras import layers,models,Sequential,Input,Model
from tensorflow.keras.layers import Conv2D,MaxPooling2D,Flatten,Dense
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
2.数据准备
#数据所在文件地址
data_dir = "E:/tmp/.keras/datasets/cats_and_dogs"
data_dir = pathlib.Path(data_dir)
img_count = len(list(data_dir.glob('*/*.jpg')))
print(img_count)#共3400张图片
all_images_paths = list(data_dir.glob('*'))##”*”匹配0个或多个字符
all_images_paths = [str(path) for path in all_images_paths]
all_label_names = [path.split("\\")[5].split(".")[0] for path in all_images_paths]
#['cats','dogs']
参数设置
height = 224
width = 224
epochs = 40
batch_size = 128
数据处理
包括数据增强的一系列操作以及按照8:2的比例划分为训练集和测试集
train_data_gen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1./255,
rotation_range=45,
shear_range=0.2,
zoom_range=0.2,
validation_split=0.2,
horizontal_flip=True
)
train_ds = train_data_gen.flow_from_directory(
directory=data_dir,
target_size=(height,width),
batch_size=batch_size,
shuffle=True,
class_mode='categorical',
subset='training'
)
test_ds = train_data_gen.flow_from_directory(
directory=data_dir,
target_size=(height,width),
batch_size=batch_size,
shuffle=True,
class_mode='categorical',
subset='validation'
)
查看数据
plt.figure(figsize=(15, 10)) # 图形的宽为15高为10
for images, labels in train_ds:
for i in range(8):
ax = plt.subplot(5, 8, i + 1)
plt.imshow(images[i])
plt.title(all_label_names[np.argmax(labels[i])])
plt.axis("off")
break
plt.show()
达到了预期的目标
3.模型搭建
包括三层卷积池化层+Dropout+两层Dense层
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,3,padding="same",activation="relu",input_shape=(height,width,3)),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Conv2D(32,3,padding="same",activation="relu"),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Conv2D(64,3,padding="same",activation="relu"),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512,activation="relu"),
tf.keras.layers.Dense(2)
])
优化器的设置:
learning_rate是影响模型准确率的一个重要因素。
①学习率大
优点:学习速率加快、有助于跳出局部最优值
缺点:模型训练不收敛、模型不精确
②学习率小
优点:有助于模型收敛,模型细化、提高模型精度
缺点:收敛缓慢,很难跳出局部最优值
动态学习率:指数衰减型(ExponentialDecay)。在每一个epoch开始前,学习率(learning_rate)都将会重置为初始学习率(initial_learning_rate),然后再重新开始衰减。
计算公式如下所示:
learning_rate =initial_learning_rate * decay_rate ^ (step / decay_steps)
#设置优化器
#起始学习率
init_learning_rate = 1e-4
lr_sch = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate=init_learning_rate,
decay_steps=50,
decay_rate=0.96,
staircase=True
)
gen_optimizer = tf.keras.optimizers.Adam(learning_rate=lr_sch)
模型编译&&训练
model.compile(
optimizer=gen_optimizer,
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy']
)
history = model.fit(
train_ds,
epochs=epochs,
validation_data=test_ds
)
训练结果可视化
#训练结果可视化
accuracy = history.history["accuracy"]
test_accuracy = history.history["val_accuracy"]
loss = history.history["loss"]
test_loss = history.history["val_loss"]
epochs_range = range(epochs)
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.plot(epochs_range,accuracy,label = "Training Acc")
plt.plot(epochs_range,test_accuracy,label = "Test Acc")
plt.legend()
plt.title("Training and Test Acc")
plt.subplot(1,2,2)
plt.plot(epochs_range,loss,label = "Training loss")
plt.plot(epochs_range,test_loss,label = "Test loss")
plt.legend()
plt.title("Training and Test loss")
plt.show()
40个epochs之后,模型的准确率在97%左右,准确率比较高。而且经过数据增强之后,模型的过拟合效果得到了改善。下图是上次经过50个epochs之后的效果,这次的网络模型与上次一样,但是优化器不同,致使模型的准确率得到了提高。
模型保存:
model.save("E:/tmp/.keras/datasets/model.h5")
模型加载:
model = tf.keras.models.load_model("E:/tmp/.keras/datasets/model.h5")
利用模型进行预测:
plt.figure(figsize=(18,18))
plt.suptitle("预测结果展示")
for images,labels in test_ds:
for i in range(16):
ax = plt.subplot(4,4,i+1)
plt.imshow(images[i])
img_array = tf.expand_dims(images[i], 0)
# 使用模型预测图片中的动物
predictions = model.predict(img_array)
plt.title(all_label_names[np.argmax(predictions)])
plt.axis("off")
break
plt.show()
4.VGG19
本次利用官方搭建的VGG19网络对同样的数据集进行识别。
conv_base = tf.keras.applications.VGG19(weights='imagenet',include_top=False)
#设置为不可训练
conv_base.trainable =False
#模型搭建
model = tf.keras.Sequential()
model.add(conv_base)
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(512,activation='relu'))
model.add(tf.keras.layers.Dense(2,activation='sigmoid'))
在epochs=10的情况下,准确率达到了99%左右,效果已经非常好了。
5.混淆矩阵
绘制混淆矩阵时的模型为自己搭建的CNN网络模型
from sklearn.metrics import confusion_matrix
import seaborn as sns
import pandas as pd
#绘制混淆矩阵
def plot_cm(labels,pre):
conf_numpy = confusion_matrix(labels,pre)#根据实际值和预测值绘制混淆矩阵
conf_df = pd.DataFrame(conf_numpy,index=all_label_names,columns=all_label_names)#将data和all_label_names制成DataFrame
plt.figure(figsize=(8,7))
sns.heatmap(conf_df,annot=True,fmt="d",cmap="BuPu")#将data绘制为混淆矩阵
plt.title('混淆矩阵',fontsize = 15)
plt.ylabel('真实值',fontsize = 14)
plt.xlabel('预测值',fontsize = 14)
plt.show()
test_pre = []
test_label = []
for images,labels in test_ds:
for image,label in zip(images,labels):
img_array = tf.expand_dims(image,0)#增加一个维度
pre = model.predict(img_array)#预测结果
test_pre.append(all_label_names[np.argmax(pre)])#将预测结果传入列表
test_label.append(all_label_names[np.argmax(label)])#将真实结果传入列表
break#由于硬件问题。这里我只用了一个batch,一共128张图片。
plot_cm(test_label,test_pre)#绘制混淆矩阵
总结:
经过数据增强,模型的过拟合问题得到了解决。改变优化器之后,模型的准确率得到了提高。VGG19的官方模型准确率很高,但是运行速度偏慢。其实博主也利用了VGG16的官方模型,但是不知是何缘故,模型的准确率一直是50%,而上次进行猫狗大战时,VGG16的模型准确率很高,其中的问题目前还不得而知。路过的大佬有知道的,希望不吝赐教。
努力加油a啊