Keras猫狗大战九:Xception迁移学习训练,精度达到98.1%

keras提供了多种ImageNet预训练模型,前面的文章都采用resnet50,这里改用Xception预训练模型进行迁移学习。

import os

from keras import layers,models,optimizers
from keras.applications.xception import Xception,preprocess_input
from keras.layers import *    
from keras.models import Model

定义模型:

base_model = Xception(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = Dropout(0.2)(x)
x = Dense(256)(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = Dropout(0.2)(x)
predictions = Dense(1, activation='sigmoid')(x)

model = Model(inputs=base_model.input, outputs=predictions)

optimizer = optimizers.RMSprop(lr=1e-4)

def get_lr_metric(optimizer):
    def lr(y_true, y_pred):
        return optimizer.lr

    return lr

lr_metric = get_lr_metric(optimizer)

model.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['acc',lr_metric])

准备训练数据:

from keras.preprocessing.image import ImageDataGenerator

batch_size = 64

train_datagen = ImageDataGenerator(
    rotation_range=90,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    vertical_flip=True,
    preprocessing_function=preprocess_input)

test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)


train_generator = train_datagen.flow_from_directory(
        # This is the target directory
        train_dir,
        # All images will be resized to 150x150
        target_size=(150, 150),
        batch_size=batch_size,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=batch_size,
        class_mode='binary')

训练模型:

from keras.callbacks import ReduceLROnPlateau,EarlyStopping

early_stop = EarlyStopping(monitor='val_loss', patience=13)

reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=7, mode='auto', factor=0.2)

callbacks = [early_stop,reduce_lr]

history = model.fit_generator(
      train_generator,
      steps_per_epoch=train_generator.samples//batch_size,
      epochs=100,
      validation_data=validation_generator,
      validation_steps=validation_generator.samples//batch_size,
        callbacks=callbacks)

训练32轮后提前结束:

Epoch 1/100
281/281 [==============================] - 152s 542ms/step - loss: 0.2750 - acc: 0.8793 - lr: 1.0000e-04 - val_loss: 0.1026 - val_acc: 0.9665 - val_lr: 1.0000e-04
Epoch 2/100
281/281 [==============================] - 144s 513ms/step - loss: 0.1547 - acc: 0.9388 - lr: 1.0000e-04 - val_loss: 0.1355 - val_acc: 0.9673 - val_lr: 1.0000e-04
Epoch 3/100
281/281 [==============================] - 143s 510ms/step - loss: 0.1204 - acc: 0.9531 - lr: 1.0000e-04 - val_loss: 0.0791 - val_acc: 0.9788 - val_lr: 1.0000e-04
......
Epoch 30/100
281/281 [==============================] - 142s 504ms/step - loss: 0.0103 - acc: 0.9964 - lr: 4.0000e-06 - val_loss: 0.0702 - val_acc: 0.9842 - val_lr: 4.0000e-06
Epoch 31/100
281/281 [==============================] - 141s 503ms/step - loss: 0.0111 - acc: 0.9961 - lr: 4.0000e-06 - val_loss: 0.0667 - val_acc: 0.9842 - val_lr: 4.0000e-06
Epoch 32/100
281/281 [==============================] - 142s 504ms/step - loss: 0.0123 - acc: 0.9954 - lr: 4.0000e-06 - val_loss: 0.0710 - val_acc: 0.9847 - val_lr: 4.0000e-06

测试数据也要进行preprocess_input处理:
def get_input_xy(src=[]):
    pre_x = []
    true_y = []

    class_indices = {'cat': 0, 'dog': 1}

    for s in src:
        input = cv2.imread(s)
        input = cv2.resize(input, (150, 150))
        input = cv2.cvtColor(input, cv2.COLOR_BGR2RGB)
        pre_x.append(preprocess_input(input))

        _, fn = os.path.split(s)
        y = class_indices.get(fn[:3])
        true_y.append(y)

    pre_x = np.array(pre_x)

    return pre_x, true_y

    
def plot_sonfusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues):
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    print(tick_marks, type(tick_marks))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks([-0.5,1.5], classes)

    print(cm)
    ok_num = 0
    for k in range(cm.shape[0]):
        print(cm[k,k]/np.sum(cm[k,:]))
        ok_num += cm[k,k]
        
    print(ok_num/np.sum(cm))
        
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

    thresh = cm.max() / 2.0
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j], horizontalalignment='center', color='white' if cm[i, j] > thresh else 'black')

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predict label')

测试图片:

dst_path = r'D:\BaiduNetdiskDownload\large'
test_dir = os.path.join(dst_path, 'test')
test = os.listdir(test_dir)

images = []

# 获取每张图片的地址,并保存在列表images中
for testpath in test:
    for fn in os.listdir(os.path.join(test_dir, testpath)):
        if fn.endswith('jpg'):
            fd = os.path.join(test_dir, testpath, fn)
            images.append(fd)

# 得到规范化图片及true label
pre_x, true_y = get_input_xy(images)

# 预测
predictions = model.predict(pre_x)
pred_y = [1 if predication[0] > 0.5 else 0 for predication in predictions]
# pred_y=np.argmax(predictions,axis=1)

# 画混淆矩阵
confusion_mat = confusion_matrix(true_y, pred_y)
plot_sonfusion_matrix(confusion_mat, classes=range(2))

测试结果为98.1%:

[[1220   30]
 [  17 1233]]
0.976
0.9864
0.9812
猫的准确度为97.6%,狗的为98.6%,总的准确度为98.1%。混淆矩阵图:

 

posted @ 2019-12-16 21:24  碧水青山  阅读(3405)  评论(0编辑  收藏  举报