目录
1.跑通代码
2.代码分析
2.1
2.2
2.3
2.4
2.5
2.6
3.总结
>- ** 本文为[365天深度学习训练营](https://mp.weixin.qq.com/s/k-vYaC8l7uxX51WoypLkTw) 中的学习记录博客**
>- ** 参考文章地址: [深度学习100例-卷积神经网络(CNN)猴痘病识别 | 第45天](https://blog.csdn.net/qq_38251616/article/details/126284706)**
>- ** 作者:[K同学啊](https://mp.weixin.qq.com/s/k-vYaC8l7uxX51WoypLkTw)**
(1条消息) tensorflow零基础入门学习_重邮研究森的博客-CSDN博客_tensorflow 学习https://blog.csdn.net/m0_60524373/article/details/124143223
本文开发环境:tensorflowgpu2.5
我这个人对于任何代码,我都会先去跑通之和才会去观看内容,哈哈哈,所以第一步我们先不管37=21,直接把博主的代码复制黏贴一份运行结果。(PS:做了一些修改,因为原文是jupyter,而我在pycharm)
from tensorflow import keras
from tensorflow.keras import layers, models
import os, PIL, pathlib
import matplotlib.pyplot as plt
import tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")
if gpus:
gpu0 = gpus[0] # 如果有多个GPU,仅使用第0个GPU
tf.config.experimental.set_memory_growth(gpu0, True) # 设置GPU显存用量按需使用
tf.config.set_visible_devices([gpu0], "GPU")
gpus
data_dir = "./data/"
data_dir = pathlib.Path(data_dir)
Monkeypox = list(data_dir.glob('Monkeypox/*.jpg'))
PIL.Image.open(str(Monkeypox[0]))
batch_size = 32
img_height = 224
img_width = 224
"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
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),
batch_size=batch_size)
"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
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),
batch_size=batch_size)
class_names = train_ds.class_names
print(class_names)
plt.figure(figsize=(20, 10))
for images, labels in train_ds.take(1):
for i in range(20):
ax = plt.subplot(5, 10, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
num_classes = 2
"""
关于卷积核的计算不懂的可以参考文章:https://blog.csdn.net/qq_38251616/article/details/114278995
layers.Dropout(0.4) 作用是防止过拟合,提高模型的泛化能力。
在上一篇文章花朵识别中,训练准确率与验证准确率相差巨大就是由于模型过拟合导致的
关于Dropout层的更多介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/115826689
"""
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)), # 卷积层1,卷积核3*3
layers.AveragePooling2D((2, 2)), # 池化层1,2*2采样
layers.Conv2D(32, (3, 3), activation='relu'), # 卷积层2,卷积核3*3
layers.AveragePooling2D((2, 2)), # 池化层2,2*2采样
layers.Dropout(0.3),
layers.Conv2D(64, (3, 3), activation='relu'), # 卷积层3,卷积核3*3
layers.Dropout(0.3),
layers.Flatten(), # Flatten层,连接卷积层与全连接层
layers.Dense(128, activation='relu'), # 全连接层,特征进一步提取
layers.Dense(num_classes) # 输出层,输出预期结果
])
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'])
from tensorflow.keras.callbacks import ModelCheckpoint
epochs = 50
checkpointer = ModelCheckpoint('best_model.h5',
monitor='val_accuracy',
verbose=1,
save_best_only=True,
save_weights_only=True)
history = model.fit(train_ds,
validation_data=val_ds,
epochs=epochs,
callbacks=[checkpointer])
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
# 加载效果最好的模型权重
model.load_weights('best_model.h5')
from PIL import Image
import numpy as np
# img = Image.open("./data/Monkeypox/M06_01_04.jpg") #这里选择你需要预测的图片
img = Image.open("./data/Others/NM15_02_11.jpg") #这里选择你需要预测的图片
image = tf.image.resize(img, [img_height, img_width])
img_array = tf.expand_dims(image, 0)
predictions = model.predict(img_array) # 这里选用你已经训练好的模型
print("预测结果为:",class_names[np.argmax(predictions)])
点击pycharm即可运行出最后的预测结果!
这里的结果是指网络模型的保存和损失函数这些的输出,对于模型的预测结果我们将在最后显示。
神经网络的整个过程我分为如下六部分,而我们也会对这六部分进行逐部分分析。那么这6部分分别是:
六步法:
1->import
2->train test(指定训练集的输入特征和标签)
3->class MyModel(model) model=Mymodel(搭建网络结构,逐层描述网络)
4->model.compile(选择哪种优化器,损失函数)
5->model.fit(执行训练过程,输入训练集和测试集的特征+标签,batch,迭代次数)
6->验证
导入:这里很容易理解,也就是导入本次实验内容所需要的各种库。在本案例中主要包括以下部分:
蓝框1:
调用各类库
蓝框2:
设置电脑gpu工作,如果你的电脑没有gpu就不设置,或者你的gpu显存不够,训练时出问题了,那么就设在为cpu模式
对于这里的话我们可以直接复制黏贴,当需要一些其他函数时,只需要添加对应的库文件即可。
设置训练集和测试集:对于神经网络的训练包括了两种数据集合,一个是训练集,一个是测试集。其中训练集数据较多,测试集较少,因为训练一个模型数据越多相对的模型更准确。
本文中利用的数据集在文章下方,该数据集是一个猴痘细胞和其他细胞的彩色图像数据集合
设置数据集的文件夹位置,把该文件夹下面的数据名字全部读取到列表中,并且显示第一种图片
蓝框2:
设置输入数据集图片的尺寸为224x224,通道数32
这里就是设置训练集了。利用了image_dataset_from_directory(),很明显可以看出来,这是一个图像数据来自文件夹函数。而这个文件夹就是data_dir。
蓝框1:
输出根据上诉函数设置之后的标签有哪些
蓝框2:
输出数据集前20张图片
蓝框3:
输出根据上诉函数设置之后的数据尺寸
该部分主要是加速电脑训练和数据乱序的。也可以使用另外的写法,可以参考我的天气识别博客
到这里,数据集的设置就结束了。我们可以发现相对于来说相对于minist数据集,代码多了很多,而这是因为数据集来源不一样,以及对于数据显示我们多显示了一下。但核心内容还是设置数据集
网络模型搭建:这里也是神经网络的重点了!废话不多说,直接开始!
重点:
现在我们来分析一下图片中经过每层后数据的维度怎么来的
经过卷积层1之后,原数据224x224还是222x222是因为(224-3)/stride+1=222,32变为16是因为当前卷积核通道数为16。
经过池化层1之后,原数据222变为111是因为池化池的卷积核为2,所以111=222/2
其他的卷积层都是按照这个方式来计算的。如果你想看详细的计算过程,可以参考我的天气识别模型,那里模型简单一点,我把整个过程都分析了。
(1条消息) 实现天气彩色图像识别_重邮研究森的博客-CSDN博客https://blog.csdn.net/m0_60524373/article/details/126153389
到此,网络模型我们变分析完了。
注意事项:我们发现这里的卷积层每一次的引入了激活函数,这是因为输入是彩色图像,引入激活函数可以更好的提取特征,而正是因为提取特征相对较多,我们又引入了防止过拟合。对于越复杂是数据越要引入激活函数,但是激活函数过多容易过拟合
该部分也同样重要,主要完成模型训练过程中的优化器,损失函数,准确率的设置。
我们结合本文来看
蓝框1:
对于这三个内容的含义可以参考我的文章开头的另外一篇基础博文进行了详细的介绍
蓝框2:
这里是设置相当于在训练模型时,如果第二轮训练结果比第一轮好,那么保留第二轮参数,如果第三轮训练比第二轮差,则还是保留第三轮参数,最后留下效果最好的那一个。
关于该函数可以参考下面文章
部分就是执行训练了,那么执行训练肯定需要设置训练集数据及其标签,测试集数据及其标签,训练的epoch
当训练执行完毕,我们就可以拿一个测试集合中或者其他满足格式的数据进行验证了
这里就是绘制训练集和测试集的准确率和损失函数图像
我们取测试集合图片进行验证(这里代码不在上面,是单独测试用的,我放到下面了)
plt.figure(figsize=(15, 8))
for images, labels in val_ds.take(1):
for i in range(batch_size):
ax = plt.subplot(5, 10, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
img_array=tf.expand_dims(images[i],0)
predictions=model.predict(img_array)
plt.title(class_names[np.argmax(predictions)])
plt.axis("off")
plt.show()
from sklearn.metrics import confusion_matrix
import seaborn as sns
import pandas as pd
from PIL import Image
import numpy as np
# 定义一个绘制混淆矩阵图的函数
def plot_cm(labels, predictions):
# 生成混淆矩阵
conf_numpy = confusion_matrix(labels, predictions)
# 将矩阵转化为 DataFrame
conf_df = pd.DataFrame(conf_numpy, index=class_names, columns=class_names)
plt.figure(figsize=(8, 7))
sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu")
plt.title('混淆矩阵', fontsize=15)
plt.ylabel('真实值', fontsize=14)
plt.xlabel('预测值', fontsize=14)
plt.show()
val_pre = []
val_label = []
for images, labels in val_ds:#这里可以取部分验证数据(.take(1))生成混淆矩阵
for image, label in zip(images, labels):
# 需要给图片增加一个维度
img_array = tf.expand_dims(image, 0)
# 使用模型预测图片中的人物
prediction = model.predict(img_array)
val_pre.append(class_names[np.argmax(prediction)])
val_label.append(class_names[label])
plot_cm(val_label, val_pre)
plt.show()
from sklearn import metrics
def test_accuracy_report(model):
print(metrics.classification_report(val_label, val_pre, target_names=class_names))
score = model.evaluate(val_ds, verbose=0)
print('Loss function: %s, accuracy:' % score[0], score[1])
test_accuracy_report(model)
模型验证就到此结束了,现在我们需要做另外一件事,就是根据模型结果进行模型修改!
修改1
我们看到当前的损失函数图像中,我感觉准确率和损失函数数值不够好,而且图像貌似有点过拟合。那么我们进行修改如下:
1.加入批标准化
2.增加训练epoch
epochs = 55
得到结果如下:
我们可以看到,测试准确率提高到了0.91(之前参考博主的准确率是:0.89) 有提高
我们可以看到,测试集的损失函数在10之和居然上升了,有问题
我们可以看到,测试集的准确率在百分百,有问题
修改2
于是我打算通过减少网络复杂度降低过拟合,我减少了网络层数如下:
现在的结果更惨了,如图所示:准确率下降,损失函数也增加,图像也更难看。
这说明,由于网络层数减少,学习的还是不够!!!有问题
修改3
这次我打算在原基础知识不去掉卷积层,而是再最后一个卷积层之和再加入一个批标准化。
我们可以看到,准确率来到了0.90,有提高
我们可以看到,损失函数波动有点大,但是相对于修改一来说不是上升形式,有提高