我的环境:
本文选自专栏:《深度学习100例》
深度学习新人必看:《小白入门深度学习》
往期精彩-卷积神经网络篇:
往期精彩-循环神经网络篇:
往期精彩-生成对抗网络篇:
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")
import matplotlib.pyplot as plt
import os,PIL,pathlib
import numpy as np
import pandas as pd
import warnings
from tensorflow import keras
warnings.filterwarnings("ignore")#忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
import pathlib
data_dir = "./31-data/"
data_dir = pathlib.Path(data_dir)
image_count = len(list(data_dir.glob('*/*')))
print("图片总数为:",image_count)
图片总数为: 30608
# 统计每一个类别的数目
class_name = []
class_sum = []
for i in data_dir.glob('*'):
one_dir = ".\\" + str(i)
one_dir = pathlib.Path(one_dir)
class_name.append(str(i).split(".")[1])
class_sum.append(len(list(one_dir.glob('*'))))
class_dict = {'class_name':class_name,'class_sum':class_sum}
class_df = pd.DataFrame(class_dict,columns=['class_name', 'class_sum'])
# 按照图片数量进行降序排序
class_df = class_df.sort_values(by="class_sum" , ascending=False)
class_df.head()
class_name | class_sum | |
---|---|---|
256 | clutter | 827 |
250 | airplanes-101 | 800 |
144 | motorbikes-101 | 798 |
252 | faces-easy-101 | 435 |
231 | t-shirt | 358 |
def draw_bar(X,Y):
plt.figure(figsize=(6, 4))
plt.barh(X, Y, align='center',color=['r','g','b','c','y','m'],alpha=0.7)
plt.xticks(fontsize=12) # 设置刻度字体大小
plt.yticks(fontsize=12)
plt.xlabel('图片数量',size=12) #设置x轴标签
# plt.ylabel('y轴',size=12) #设置y轴标签
plt.title('数据集数量top-5与bottom-5对比分析',size=14)
plt.show()
top_5_X = list(class_df["class_name"][ :5])
top_5_Y = list(class_df["class_sum"][ :5])
bottom_5_X = list(class_df["class_name"][-5: ])
bottom_5_Y = list(class_df["class_sum"][-5: ])
X= top_5_X+bottom_5_X
Y =top_5_Y+bottom_5_Y
draw_bar(X,Y)
在实验开始时查看数据集分布情况,部分类别图片数量过少时,需要及时补充数据。
batch_size = 16
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=12,
image_size=(img_height, img_width),
batch_size=batch_size)
Found 30607 files belonging to 257 classes.
Using 24486 files for training.
"""
关于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=12,
image_size=(img_height, img_width),
batch_size=batch_size)
Found 30607 files belonging to 257 classes.
Using 6121 files for validation.
class_names = list(class_df["class_name"])
# print("数据类别有:",class_names)
print("需要识别的物体一共有%d类"%len(class_names))
需要识别的物体一共有257类
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break
(16, 224, 224, 3)
(16,)
AUTOTUNE = tf.data.AUTOTUNE
def train_preprocessing(image,label):
return (image/255.0,label)
train_ds = (
train_ds#.cache() # 如果数据量过大,尽量不要缓存,不然电脑会卡死
.map(train_preprocessing) # 这里可以设置预处理函数
.prefetch(buffer_size=AUTOTUNE)
)
val_ds = (
val_ds#.cache() # 如果数据量过大,尽量不要缓存,不然电脑会卡死
.map(train_preprocessing) # 这里可以设置预处理函数
.prefetch(buffer_size=AUTOTUNE)
)
plt.figure(figsize=(10, 8)) # 图形的宽为10高为5
plt.suptitle("数据展示")
for images, labels in train_ds.take(1):
for i in range(15):
plt.subplot(4, 5, i + 1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
# 显示图片
plt.imshow(images[i])
# 显示标签
# plt.xlabel(class_names[labels[i]-1])
plt.show()
from tensorflow.keras.models import Model
from tensorflow.keras import layers
from tensorflow.keras import backend
def dense_block(x, blocks, name):
for i in range(blocks):
x = conv_block(x, 32, name=name + '_block' + str(i + 1))
return x
def conv_block(x, growth_rate, name):
bn_axis = 3
x1 = layers.BatchNormalization(axis=bn_axis,
epsilon=1.001e-5,
name=name + '_0_bn')(x)
x1 = layers.Activation('relu', name=name + '_0_relu')(x1)
x1 = layers.Conv2D(4 * growth_rate, 1,
use_bias=False,
name=name + '_1_conv')(x1)
x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,
name=name + '_1_bn')(x1)
x1 = layers.Activation('relu', name=name + '_1_relu')(x1)
x1 = layers.Conv2D(growth_rate, 3,
padding='same',
use_bias=False,
name=name + '_2_conv')(x1)
x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1])
return x
def transition_block(x, reduction, name):
bn_axis = 3
x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,
name=name + '_bn')(x)
x = layers.Activation('relu', name=name + '_relu')(x)
x = layers.Conv2D(int(backend.int_shape(x)[bn_axis] * reduction), 1,
use_bias=False,
name=name + '_conv')(x)
x = layers.AveragePooling2D(2, strides=2, name=name + '_pool')(x)
return x
def DenseNet(blocks, input_shape=None, classes=1000, **kwargs):
img_input = layers.Input(shape=input_shape)
bn_axis = 3
# 224,224,3 -> 112,112,64
x = layers.ZeroPadding2D(padding=((3, 3), (3, 3)))(img_input)
x = layers.Conv2D(64, 7, strides=2, use_bias=False, name='conv1/conv')(x)
x = layers.BatchNormalization(
axis=bn_axis, epsilon=1.001e-5, name='conv1/bn')(x)
x = layers.Activation('relu', name='conv1/relu')(x)
# 112,112,64 -> 56,56,64
x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x)
x = layers.MaxPooling2D(3, strides=2, name='pool1')(x)
# 56,56,64 -> 56,56,64+32*block[0]
# Densenet121 56,56,64 -> 56,56,64+32*6 == 56,56,256
x = dense_block(x, blocks[0], name='conv2')
# 56,56,64+32*block[0] -> 28,28,32+16*block[0]
# Densenet121 56,56,256 -> 28,28,32+16*6 == 28,28,128
x = transition_block(x, 0.5, name='pool2')
# 28,28,32+16*block[0] -> 28,28,32+16*block[0]+32*block[1]
# Densenet121 28,28,128 -> 28,28,128+32*12 == 28,28,512
x = dense_block(x, blocks[1], name='conv3')
# Densenet121 28,28,512 -> 14,14,256
x = transition_block(x, 0.5, name='pool3')
# Densenet121 14,14,256 -> 14,14,256+32*block[2] == 14,14,1024
x = dense_block(x, blocks[2], name='conv4')
# Densenet121 14,14,1024 -> 7,7,512
x = transition_block(x, 0.5, name='pool4')
# Densenet121 7,7,512 -> 7,7,256+32*block[3] == 7,7,1024
x = dense_block(x, blocks[3], name='conv5')
x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='bn')(x)
x = layers.Activation('relu', name='relu')(x)
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
x = layers.Dense(classes, activation='softmax', name='fc1000')(x)
inputs = img_input
if blocks == [6, 12, 24, 16]:
model = Model(inputs, x, name='densenet121')
elif blocks == [6, 12, 32, 32]:
model = Model(inputs, x, name='densenet169')
elif blocks == [6, 12, 48, 32]:
model = Model(inputs, x, name='densenet201')
else:
model = Model(inputs, x, name='densenet')
return model
def DenseNet121(input_shape=[224,224,3], classes=len(class_names), **kwargs):
return DenseNet([6, 12, 24, 16], input_shape, classes, **kwargs)
def DenseNet169(input_shape=[224,224,3], classes=len(class_names), **kwargs):
return DenseNet([6, 12, 32, 32], input_shape, classes, **kwargs)
def DenseNet201(input_shape=[224,224,3], classes=len(class_names), **kwargs):
return DenseNet([6, 12, 48, 32], input_shape, classes, **kwargs)
model = DenseNet121()
optimizer = tf.keras.optimizers.Adam(lr=1e-3)
model.compile(optimizer=optimizer,
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
from tensorflow.keras.callbacks import ModelCheckpoint, Callback, EarlyStopping, ReduceLROnPlateau, LearningRateScheduler
NO_EPOCHS = 40
PATIENCE = 5
VERBOSE = 1
# 设置动态学习率
# annealer = LearningRateScheduler(lambda x: 1e-4 * 0.98 ** x)
# 设置早停
# earlystopper = EarlyStopping(monitor='loss', patience=PATIENCE, verbose=VERBOSE)
# 设置回调函数
checkpointer = ModelCheckpoint('best_model.h5',
monitor='val_accuracy',
verbose=VERBOSE,
save_best_only=True,
save_weights_only=True)
train_model = model.fit(train_ds,
epochs=NO_EPOCHS,
verbose=1,
validation_data=val_ds,
callbacks=[checkpointer])
Epoch 1/40
1531/1531 [==============================] - 155s 94ms/step - loss: 5.1739 - accuracy: 0.0677 - val_loss: 19.6963 - val_accuracy: 0.0601
Epoch 00001: val_accuracy improved from -inf to 0.06012, saving model to best_model.h5
Epoch 2/40
1531/1531 [==============================] - 140s 92ms/step - loss: 4.7255 - accuracy: 0.1058 - val_loss: 4.7597 - val_accuracy: 0.1132
Epoch 00002: val_accuracy improved from 0.06012 to 0.11322, saving model to best_model.h5
Epoch 3/40
1531/1531 [==============================] - 139s 91ms/step - loss: 4.3067 - accuracy: 0.1527 - val_loss: 4.2869 - val_accuracy: 0.1626
......
Epoch 00036: val_accuracy did not improve from 0.44257
Epoch 37/40
1531/1531 [==============================] - 140s 91ms/step - loss: 0.1387 - accuracy: 0.9556 - val_loss: 4.4015 - val_accuracy: 0.4468
Epoch 00037: val_accuracy improved from 0.44257 to 0.44682, saving model to best_model.h5
Epoch 38/40
1531/1531 [==============================] - 140s 91ms/step - loss: 0.1244 - accuracy: 0.9622 - val_loss: 4.2792 - val_accuracy: 0.4485
Epoch 00038: val_accuracy improved from 0.44682 to 0.44846, saving model to best_model.h5
Epoch 39/40
1531/1531 [==============================] - 136s 89ms/step - loss: 0.1210 - accuracy: 0.9627 - val_loss: 4.3829 - val_accuracy: 0.4511
Epoch 00039: val_accuracy improved from 0.44846 to 0.45107, saving model to best_model.h5
Epoch 40/40
1531/1531 [==============================] - 138s 90ms/step - loss: 0.1113 - accuracy: 0.9668 - val_loss: 4.4362 - val_accuracy: 0.4527
Epoch 00040: val_accuracy improved from 0.45107 to 0.45270, saving model to best_model.h5
acc = train_model.history['accuracy']
val_acc = train_model.history['val_accuracy']
loss = train_model.history['loss']
val_loss = train_model.history['val_loss']
epochs_range = range(len(acc))
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()
加入Dropout层后过拟合现象得到了缓解,没有那么明显了。
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 : %s, accuracy:' % score[0], score[1])
test_accuracy_report(model)
Loss : 4.436242580413818, accuracy: 0.4527038037776947