介绍
使用tensorflow2 keras的预训练模型ResNet50训练猫狗识别
关键
使用ResNet系列预训练模型,与VGG16、Xception 、DenseNet121 、MobileNet 等不同,需要做额外处理,否则会发生过拟合,验证集的准确率不上升
代码
import tensorflow as tf
import tensorflow.keras.backend as K
import glob
import os.path
import matplotlib.pyplot as plt
定义获取图片路径、label的函数
name_label_map={"cat":0,"dog":1}
# 根据图片名字获取label
def get_labels(paths):
test_labels=[]
for item in paths:
filename=os.path.basename(item)
labelname=filename[:filename.find(".")]
label=name_label_map.get(labelname)
test_labels.append(label)
return test_labels
# 获取图片路径和对应的label
# 图片过多,全读取会内存溢出,通过参数num设置读取数量
def get_path(path,num):
dogs_train_paths=glob.glob(path)
dogs_train_paths=dogs_train_paths[:num]
labels=get_labels(dogs_train_paths)
return dogs_train_paths,labels
获取猫狗测试集路径、label
获取狗的测试集图片路径、label
dogs_test_paths,dogs_test_labels=get_path(r"../input/dogs-vs-cats/test/dogs/*.jpg",test_num)
dogs_test_paths[:5],dogs_test_paths[-5:],len(dogs_test_paths),dogs_test_labels[:5],dogs_test_labels[-5:],len(dogs_test_labels)
获取猫的测试集图片路径、label
cats_test_paths,cats_test_labels=get_path(r"../input/dogs-vs-cats/test/cats/*.jpg",test_num)
cats_test_paths[:5],cats_test_paths[-5:],len(cats_test_paths),cats_test_labels[:5],cats_test_labels[-5:],len(cats_test_labels)
合并猫狗图片路径、label
test_paths=[]
test_paths.extend(dogs_test_paths)
test_paths.extend(cats_test_paths)
test_labels=[]
test_labels.extend(dogs_test_labels)
test_labels.extend(cats_test_labels)
test_paths[:5],test_paths[-5:],test_labels[:5],test_labels[-5:]
获取猫狗训练集路径、label
获取狗的训练集图片路径、label
dogs_train_paths,dogs_train_labels=get_path(r"../input/dogs-vs-cats/train/dogs/*.jpg",train_num)
dogs_train_paths[:5],dogs_train_paths[-5:],len(dogs_train_paths),dogs_train_labels[:5],dogs_train_labels[-5:],len(dogs_train_labels)
获取猫的训练集图片路径、label
cats_train_paths,cats_train_labels=get_path(r"../input/dogs-vs-cats/train/cats/*.jpg",train_num)
cats_train_paths[:5],cats_train_paths[-5:],len(cats_train_paths),cats_train_labels[:5],cats_train_labels[-5:],len(cats_train_labels)
合并猫狗图片路径、label
train_paths=[]
train_paths.extend(dogs_train_paths)
train_paths.extend(cats_train_paths)
train_labels=[]
train_labels.extend(dogs_train_labels)
train_labels.extend(cats_train_labels)
train_paths[:5],train_paths[-5:],train_labels[:5],train_labels[-5:]
创建测试集的Dataset
train_size=len(train_paths)
img_resize=256
AUTOTUNE=tf.data.experimental.AUTOTUNE
batch_size=8
def parse_test(test_path,test_label):
img_data=tf.io.read_file(test_path)
img_arr=tf.io.decode_jpeg(img_data,channels=3)
img_arr=img_arr/255
img_arr=tf.image.resize(img_arr,(img_resize,img_resize))
return img_arr,test_label
test_ds=tf.data.Dataset.from_tensor_slices((test_paths,test_labels))
test_ds2=test_ds.map(parse_test,num_parallel_calls=AUTOTUNE).batch(batch_size).prefetch(AUTOTUNE)
创建训练集的Dataset
def parse_train(path,label):
img_data=tf.io.read_file(path)
img_arr=tf.io.decode_jpeg(img_data,channels=3)
img_arr=img_arr/255
img_arr=tf.image.resize(img_arr,(img_resize,img_resize))
return img_arr,label
train_ds=tf.data.Dataset.from_tensor_slices((train_paths,train_labels))
train_ds2=train_ds.map(parse_train,num_parallel_calls=AUTOTUNE).shuffle(train_size).batch(batch_size).prefetch(AUTOTUNE)
创建模型
由于ResNet系列模型含有tf.keras.layers.BatchNormalization,其实现有bug,在冻结参数时,需要通过K.set_learning_phase(0)进行设置
详见:
https://www.malaoshi.top/show_1EF5JnCCFGcd.html
另一种创建模型方式:
https://www.malaoshi.top/show_1EF5JUYBib4t.html
def build():
K.set_learning_phase(0)
base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False,
input_shape=(img_resize, img_resize, 3), )
K.set_learning_phase(1)
# base_model.trainable=False
model=tf.keras.Sequential()
model.add(base_model)
model.add(tf.keras.layers.GlobalAveragePooling2D())
# model.add(tf.keras.layers.Dense(512,activation="relu",kernel_regularizer=tf.keras.regularizers.l2(0.0001)))
model.add(tf.keras.layers.Dense(512,activation="relu"))
model.add(tf.keras.layers.Dense(1,activation="sigmoid"))
return model
训练
model=build()
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001),loss="binary_crossentropy",metrics=["acc"])
history=model.fit(train_ds2,epochs=5,validation_data=test_ds2)
model.save("model.h5",save_format="h5")
显示训练集的准确率和测试集的准确率
plt.plot(history.epoch,history.history["acc"],label="acc")
plt.plot(history.epoch,history.history["val_acc"],label="val_acc")
plt.legend()
显示训练集的损失值和测试集的损失值
plt.plot(history.epoch,history.history["loss"],label="loss")
plt.plot(history.epoch,history.history["val_loss"],label="val_loss")
plt.legend()