Keras区分狗和猫

67 阅读4分钟

Kaggle概述与数据集下载:www.kaggle.com/c/dogs-vs-c…
原外文教程:deeplizard.com/learn/video…

在本次比赛中,您将编写一个算法来对图像是包含狗还是猫进行分类。这对人类、狗和猫来说都很容易。您的计算机会发现它有点困难。

代码的注释很详细,可参考。

import glob
import itertools
import os
import random
import shutil

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from keras_visualizer import visualizer
from sklearn.metrics import confusion_matrix
from tensorflow.keras.layers import Dense, Flatten, MaxPooling2D, Conv2D
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing.image import ImageDataGenerator


def plot_confusion_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))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    thresh = cm.max() / 2.
    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('Predicted label')
    plt.show()


def plotImages(images_arr):
    """画图,可以不用看"""
    fig, axes = plt.subplots(1, 10, figsize=(20,20))
    axes = axes.flatten()
    for img, ax in zip(images_arr, axes):
        ax.imshow(img)
        ax.axis('off')
    plt.tight_layout()
    plt.show()

# 1、整理数据,将数据进行分类放置
os.chdir('dogs-vs-cats/train')
if os.path.isdir('../cnn/train/dog') is False:
    os.makedirs('../cnn/train/dog')
    os.makedirs('../cnn/train/cat')
    os.makedirs('../cnn/valid/dog')
    os.makedirs('../cnn/valid/cat')
    os.makedirs('../cnn/test/dog')
    os.makedirs('../cnn/test/cat')
    for i in random.sample(glob.glob('cat*'), 500):
        shutil.move(i, '../cnn/train/cat')
    for i in random.sample(glob.glob('dog*'), 500):
        shutil.move(i, '../cnn/train/dog')
    for i in random.sample(glob.glob('cat*'), 100):
        shutil.move(i, '../cnn/valid/cat')
    for i in random.sample(glob.glob('dog*'), 100):
        shutil.move(i, '../cnn/valid/dog')
    for i in random.sample(glob.glob('cat*'), 50):
        shutil.move(i, '../cnn/test/cat')
    for i in random.sample(glob.glob('dog*'), 50):
        shutil.move(i, '../cnn/test/dog')
os.chdir('../../')

# 图像数据路径
train_path = 'dogs-vs-cats/cnn/train'
valid_path = 'dogs-vs-cats/cnn/valid'
test_path = 'dogs-vs-cats/cnn/test'

# 2、使用VGG16预处理图像并创建图像生成器
# flow_from_directory()创建一个DirectoryIterator,它从相应的数据目录生成一批标准化的张量图像数据
# 其中:
#   target_size参数为图像大小,这会将所有图像调整为指定的大小。在此处指定的大小由神经网络预期的输入大小决定
#   classes参数需要一个包含基础类名称的列表
#   shuffle=False,默认情况下,数据集被打乱
train_batches = ImageDataGenerator(preprocessing_function=tf.keras.applications.vgg16.preprocess_input)\
    .flow_from_directory(directory=train_path, target_size=(224, 224), classes=['cat', 'dog'], batch_size=10)
valid_batches = ImageDataGenerator(preprocessing_function=tf.keras.applications.vgg16.preprocess_input)\
    .flow_from_directory(directory=valid_path, target_size=(224, 224), classes=['cat', 'dog'], batch_size=10)
test_batches = ImageDataGenerator(preprocessing_function=tf.keras.applications.vgg16.preprocess_input)\
    .flow_from_directory(directory=test_path, target_size=(224, 224), classes=['cat', 'dog'], batch_size=10, shuffle=False)

# 测试,从训练集中生成一批图像和标签
# 这个batch的大小是我们在创建train_batches时由batch_size设置的
# One-Hot编码,classes=['cat', 'dog'] => 狗:[0,1],猫:[1,0]
# imgs, labels = next(train_batches)
# plotImages(imgs)
# print(labels[:5])

# 3、创建模型
model = Sequential()
# 3.1、二维卷积层
model.add(Conv2D(filters=32,                # 指定的输出过滤器数量(32)的选择是任意的
                 kernel_size=(3, 3),        # 所选的内核大小(3x3)通常是非常常用的大小
                 activation='relu',
                 padding='same',            # 启用 零填充
                 input_shape=(224, 224, 3)  # 仅在第一层,我们还指定了输入尺寸;图像高224,宽224,RGB颜色通道3
                 )
          )
# 3.2、添加一个最大池化层来池化并降低数据的维数
# 一般来说,最大池化是在卷积层之后添加的
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
# 3.3、二维卷积层
model.add(Conv2D(filters=64,  # 此处的选择再次是任意的,但通常选择在后面的层中比在前面的层中具有更多的过滤器
                 kernel_size=(3, 3),
                 activation='relu',
                 padding='same'
                 )
          )
# 3.4、添加一个最大池化层来池化并降低数据的维数
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
# 3.5、将卷积层的输出"展平"传递给一个下一个层
model.add(Flatten())
# 3.6、网络的输出层
model.add(Dense(units=2,                # 它有2节点,一个给猫,一个给狗
                activation='softmax'    # 输出上使用激活函数,以便每个样本的输出是cat和dog的概率分布
                )
          )
# 4、查看模型的结构
model.summary()
# 查看神经元连接结构
visualizer(model, format='png', view=True)
# 5、编译模型
# 当我们只有两个类时,我们可以将输出层配置为只有一个输出,而不是两个
# 并用binary_crossentropy作我们的损失,而不是categorical_crossentropy
# 两个选项都同样有效,并获得完全相同的结果
# 有了binary_crossentropy,但是,最后一层需要使用sigmoid,而不是softmax作为其激活函数
model.compile(optimizer=Adam(learning_rate=0.0001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 6、训练模型
model.fit(x=train_batches,
          steps_per_epoch=len(train_batches),
          validation_data=valid_batches,
          validation_steps=len(valid_batches),
          epochs=10,
          verbose=1)

# 7、预测数据
predictions = model.predict(x=test_batches,
                            steps=len(test_batches),
                            verbose=0)
np.round(predictions)

# 8、将测试集的真实标签,以及来自模型的测试集的预测标签传递给了混淆矩阵
# 可以通过调用test_batches.classes来访问测试集未打乱的真实标签
# 使用np.argmax(predictions, axis=-1)为每个预测选择具有最高值的元素,将one-hot编码的预测标签转换为与真实标签相同的格式
cm = confusion_matrix(y_true=test_batches.classes,
                      y_pred=np.argmax(predictions, axis=1))
cm_plot_labels = ['cat', 'dog']
plot_confusion_matrix(cm=cm, classes=cm_plot_labels, title='Confusion Matrix')

# 9、保存模型
model.save('demo.h5')
# 载入模型示例:
# model = load_model('demo,h5')

预测单张图片:

# 预测单张图片
model = load_model('demo.h5')
from PIL import Image
img = Image.open('dogs-vs-cats/cnn/test/dog/dog.6412.jpg')
img = np.array(img.resize((224, 224), Image.ANTIALIAS)).reshape((1, 224, 224, 3))
predictions = model.predict(
    x=img,
    verbose=0
)
print(np.round(predictions))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述