用keras预训练模型ResNet50训练猫狗识别

介绍

使用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()

原文出处:/show_1EF5KBECaJhw.html