- 本文为365天深度学习训练营 内部限免文章(版权归 K同学啊 所有)
- ** 参考文章地址:[TensorFlow入门实战|365天深度学习训练营-第8周:猫狗识别(训练营内部成员可读) ]**
- 作者:K同学啊
文章目录
- 一、本周学习内容:
- 1、自己搭建VGG16网络
- 2、了解model.train_on_batch()
- 3、了解tqdm,并使用tqdm实现可视化进度条
- 二、前言
- 三、电脑环境
- 四、前期准备
- 1、导入相关依赖项
- 2、设置GPU(我下载的tensorflow-gpu 默认使用GPU)
- 3、加载数据集和展示
- (1)、数据集加载
- (2)、数据展示
- 五、数据预处理
- 六、搭建CNN网络
- 七、绘制损失函数图像和准确度图像
def vgg_net(num_layer,filter):
blk = Sequential()
for _ in range(num_layer):
blk.add(Conv2D(filters=filter,kernel_size=3,padding='same',activation='relu'))
blk.add(MaxPool2D(pool_size=(2,2),strides=2))
return blk
conv_arch = [(2,64),(2,128),(3,256),(3,512),(3,512)]
model = Sequential()
for num_layer,filter in conv_arch:
model.add(vgg_net(num_layer,filter))
model.add(Sequential([
Flatten(),
Dense(4096,activation='relu'),
Dropout(0.5),
Dense(4096,activation='relu'),
Dropout(0.5),
Dense(len(class_num),activation='softmax') # 输出类别数自行更改
]))
x = tf.random.uniform((1,224,224,3))
y = model(x)
print(model.summary())
y_pred = model.train_on_batch(
x,
y=None,
sample_weight=None,
class_weight=None,
reset_metrics=True,
return_dict=False,
)
x:模型输入,单输入就是一个 numpy 数组, 多输入就是 numpy 数组的列表
y:标签,单输出模型就是一个 numpy 数组, 多输出模型就是 numpy 数组列表
sample_weight:mini-batch 中每个样本对应的权重,形状为 (batch_size)
class_weight:类别权重,作用于损失函数,为各个类别的损失添加权重,主要用于类别不平衡的情况, 形状为 (num_classes)
reset_metrics:默认True,返回的metrics只针对这个mini-batch, 如果False,metrics 会跨批次累积
return_dict:默认 False, y_pred 为一个列表,如果 True 则 y_pred 是一个字典
可看这篇文章描述train_on_batch
tqdm是 Python 进度条库,可以在 Python长循环中添加一个进度提示信息。用户只需要封装任意的迭代器,是一个快速、扩展性强的进度条工具库。
这篇文章介绍tqdm的使用
我们的数据图片共有3400张,两个类别,类别即为文件夹名。
类别包括:[‘Dark’, ‘Green’, ‘Light’, ‘Medium’]
在我们使用tensorflow.keras.preprocessing.image_dataset_from_directory()函数读取后会弹出下列提示
Found 3400 files belonging to 2 classes.
Using 680 files for validation.
[‘cat’, ‘dog’]
电脑系统:Windows 10
语言环境:Python 3.8.8
编译器:Pycharm 2021.1.3
深度学习环境:TensorFlow 2.8.0,keras 2.8.0
显卡及显存:RTX 3070 8G
from keras.models import Sequential
from keras.layers import *
from tensorflow import keras
from keras.callbacks import ModelCheckpoint
import tensorflow as tf
import matplotlib.pyplot as plt
只使用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")
使用cpu和gpu
os.environ[“CUDA_VISIBLE_DEVICES”] = “-1”
# 数据集加载
traindatadir = "./dataset"
train = keras.preprocessing.image_dataset_from_directory(directory=traindatadir,
validation_split=0.2,
subset='training',
seed=469,
label_mode='categorical',
image_size=(224,224),
batch_size=32)
val = keras.preprocessing.image_dataset_from_directory(directory=traindatadir,
validation_split=0.2,
subset='validation',
seed=469,
label_mode='categorical',
image_size=(224,224),
batch_size=32)
class_names = train.class_names
print(class_names)
图片展示
# 图片展示
plt.figure(figsize=(15, 10)) # 图形的宽为15高为10
for images, labels in train_ds.take(1):
for i in range(32):
ax = plt.subplot(5, 8, i + 1)
plt.imshow(images[i])
plt.title(class_names[labels[i]])
plt.axis("off")
plt.show() #使用pycharm的需要加入这行代码才能将图像显示出来
# train.take(i) 取出第i组图片数据和标签,即将所有图片打包后一个batch为32,
将数据归一化并加载入内存中
AUTOTUNE = tf.data.AUTOTUNE
def preprocess_image(image,label):
return (image/255.0,label)
# 归一化处理
train_ds = train_ds.map(preprocess_image, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(preprocess_image, num_parallel_calls=AUTOTUNE)
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
# 网络模型
def vgg_net(num_layer,filter):
blk = Sequential()
for _ in range(num_layer):
blk.add(Conv2D(filters=filter,kernel_size=3,padding='same',activation='relu'))
blk.add(MaxPool2D(pool_size=(2,2),strides=2))
return blk
conv_arch = [(2,64),(2,128),(3,256),(3,512),(3,512)]
# model = Sequential([Conv2D(filters=64,kernel_size=3,padding='same',activation='relu',input_shape=(224,224,1))])
model = Sequential()
for num_layer,filter in conv_arch:
model.add(vgg_net(num_layer,filter))
# print(model.summary())
model.add(Sequential([
Flatten(),
Dense(4096,activation='relu'),
Dropout(0.5),
Dense(4096,activation='relu'),
Dropout(0.5),
Dense(len(class_names),activation='softmax')
]))
x = tf.random.uniform((1,224,224,3))
y = model(x)
print('y',y)
print(model.summary())
model.compile(optimizer="adam",
loss ='sparse_categorical_crossentropy',
metrics =['accuracy'])
from tqdm import tqdm
import tensorflow.keras.backend as K
epochs = 10
lr = 1e-4
# 记录训练数据,方便后面的分析
history_train_loss = []
history_train_accuracy = []
history_val_loss = []
history_val_accuracy = []
for epoch in range(epochs):
train_total = len(train_ds)
val_total = len(val_ds)
"""
total:预期的迭代数目
ncols:控制进度条宽度
mininterval:进度更新最小间隔,以秒为单位(默认值:0.1)
"""
with tqdm(total=train_total, desc=f'Epoch {epoch + 1}/{epochs}', mininterval=1, ncols=100) as pbar:
lr = lr * 0.92
K.set_value(model.optimizer.lr, lr)
for image, label in train_ds:
"""
训练模型,简单理解train_on_batch就是:它是比model.fit()更高级的一个用法
想详细了解 train_on_batch 的同学,
可以看看我的这篇文章:https://www.yuque.com/mingtian-fkmxf/hv4lcq/ztt4gy
"""
history = model.train_on_batch(image, label)
train_loss = history[0]
train_accuracy = history[1]
pbar.set_postfix({"loss": "%.4f" % train_loss,
"accuracy": "%.4f" % train_accuracy,
"lr": K.get_value(model.optimizer.lr)})
pbar.update(1)
history_train_loss.append(train_loss)
history_train_accuracy.append(train_accuracy)
print('开始验证!')
with tqdm(total=val_total, desc=f'Epoch {epoch + 1}/{epochs}', mininterval=0.3, ncols=100) as pbar:
for image, label in val_ds:
history = model.test_on_batch(image, label)
val_loss = history[0]
val_accuracy = history[1]
pbar.set_postfix({"loss": "%.4f" % val_loss,
"accuracy": "%.4f" % val_accuracy})
pbar.update(1)
history_val_loss.append(val_loss)
history_val_accuracy.append(val_accuracy)
print('结束验证!')
print("验证loss为:%.4f" % val_loss)
print("验证准确率为:%.4f" % val_accuracy)
Epoch 1/10: 100%|██████████| 85/85 [00:56<00:00, 1.50it/s, loss=0.6747, accuracy=0.5938, lr=9.2e-5]
Epoch 1/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 1/10: 100%|█████████████████████| 22/22 [00:05<00:00, 4.03it/s, loss=0.6325, accuracy=1.0000]
Epoch 2/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.6325
验证准确率为:1.0000
Epoch 2/10: 100%|█████████| 85/85 [00:57<00:00, 1.48it/s, loss=0.5680, accuracy=0.6562, lr=8.46e-5]
Epoch 2/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 2/10: 100%|█████████████████████| 22/22 [00:06<00:00, 3.66it/s, loss=0.4805, accuracy=0.8750]
Epoch 3/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.4805
验证准确率为:0.8750
Epoch 3/10: 100%|█████████| 85/85 [01:07<00:00, 1.26it/s, loss=0.5843, accuracy=0.7188, lr=7.79e-5]
开始验证!
Epoch 3/10: 100%|█████████████████████| 22/22 [00:04<00:00, 5.15it/s, loss=0.5533, accuracy=0.7500]
Epoch 4/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.5533
验证准确率为:0.7500
Epoch 4/10: 100%|█████████| 85/85 [01:06<00:00, 1.28it/s, loss=0.0835, accuracy=0.9688, lr=7.16e-5]
Epoch 4/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 4/10: 100%|█████████████████████| 22/22 [00:05<00:00, 4.24it/s, loss=0.0185, accuracy=1.0000]
Epoch 5/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.0185
验证准确率为:1.0000
Epoch 5/10: 100%|█████████| 85/85 [01:09<00:00, 1.22it/s, loss=0.0667, accuracy=0.9688, lr=6.59e-5]
Epoch 5/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 5/10: 100%|█████████████████████| 22/22 [00:05<00:00, 3.74it/s, loss=0.0099, accuracy=1.0000]
Epoch 6/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.0099
验证准确率为:1.0000
Epoch 6/10: 100%|█████████| 85/85 [01:14<00:00, 1.14it/s, loss=0.0395, accuracy=0.9688, lr=6.06e-5]
Epoch 6/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 6/10: 100%|█████████████████████| 22/22 [00:05<00:00, 3.77it/s, loss=0.0012, accuracy=1.0000]
Epoch 7/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.0012
验证准确率为:1.0000
Epoch 7/10: 100%|█████████| 85/85 [01:14<00:00, 1.14it/s, loss=0.0461, accuracy=1.0000, lr=5.58e-5]
Epoch 7/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 7/10: 100%|█████████████████████| 22/22 [00:05<00:00, 3.80it/s, loss=0.0012, accuracy=1.0000]
结束验证!
验证loss为:0.0012
验证准确率为:1.0000
Epoch 8/10: 100%|█████████| 85/85 [01:16<00:00, 1.10it/s, loss=0.0364, accuracy=1.0000, lr=5.13e-5]
Epoch 8/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 8/10: 100%|█████████████████████| 22/22 [00:05<00:00, 3.68it/s, loss=0.0031, accuracy=1.0000]
Epoch 9/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.0031
验证准确率为:1.0000
Epoch 9/10: 100%|█████████| 85/85 [01:16<00:00, 1.11it/s, loss=0.0117, accuracy=1.0000, lr=4.72e-5]
开始验证!
Epoch 9/10: 100%|█████████████████████| 22/22 [00:06<00:00, 3.23it/s, loss=0.0005, accuracy=1.0000]
Epoch 10/10: 0%| | 0/85 [00:00<?, ?it/s]结束验证!
验证loss为:0.0005
验证准确率为:1.0000
Epoch 10/10: 100%|████████| 85/85 [01:16<00:00, 1.12it/s, loss=0.0004, accuracy=1.0000, lr=4.34e-5]
Epoch 10/10: 0%| | 0/22 [00:00<?, ?it/s]开始验证!
Epoch 10/10: 100%|████████████████████| 22/22 [00:05<00:00, 3.77it/s, loss=0.0008, accuracy=1.0000]
结束验证!
验证loss为:0.0008
验证准确率为:1.0000
绘制代码与前几周相同
# 画准确度图
epochs_range = range(epochs)
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, history_train_accuracy, label='Training Accuracy')
plt.plot(epochs_range, history_val_accuracy, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, history_train_loss, label='Training Loss')
plt.plot(epochs_range, history_val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()