Задача «кошки против собак» — классический пример классификации изображений в компьютерном зрении, где задача состоит в том, чтобы научить модель различать изображения кошек и собак. Эта задача часто используется в качестве эталона для оценки производительности алгоритмов компьютерного зрения и для сравнения различных подходов к классификации изображений.

В этой задаче я использовал очистку данных, дополнение и передачу обучения более новым моделям CNN, построенным на Tensorflow, для классификации изображений.

Этапы проекта:

  1. Доступ к данным
  2. Очистка и анализ данных
  3. Увеличение данных и разделение набора обучения/проверки
  4. Модель обучения с трансферным обучением
  5. Получение результатов на веб-изображениях

Вот полный код проекта для получения дополнительных ссылок и лучшего понимания:«https://www.kaggle.com/code/harshag811/dogs-vs-cats-prediction-with-98-5-accuracy. /блокнот"

1. Доступ к данным и очистка данных

Хотя в Интернете доступно множество наборов данных, я предпочел этот набор данных от Kaggle, который содержит около 25 000 изображений (12 500 для кошек и 12 500 для собак). Набор данных такого размера идеально подходит для обучения нашей модели.

Чтобы запустить новое ядро ​​на Kaggle с набором данных и использовать ускорение графического процессора:

  1. Перейдите по ссылке, содержащей набор данных.
  2. Нажмите «Новая записная книжка» в правом верхнем углу страницы.
  3. Откроется новый блокнот.
  4. Чтобы запустить код на графическом процессоре, перейдите в раскрывающийся список настроек в правой части экрана.
  5. Смените ускоритель на GPU. Это настроит GPU для проекта.
  6. Теперь удалите первую ячейку записной книжки.
  7. После этих шагов вы можете теперь следовать руководству с этого момента. Это позволит вам работать с набором данных, не загружая его на свой компьютер, а также позволит вам работать с ядром с дополнительной инфраструктурой графического процессора, что ускорит процесс обучения.

ШАГ 1. Загрузка библиотек

# importing basic python libraries
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# importing tensorflow library and keras images API methods for data augmentation
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator, image_dataset_from_directory

# libraries for handling images and paths
import PIL
from pathlib import Path
from PIL import UnidentifiedImageError

# importing warnings to prevent from unnecessary outputs
import warnings
warnings.filterwarnings('ignore')

На данный момент мы импортировали важные библиотеки, которые будут полезны для этого проекта. Теперь пришло время поработать с данными.

ШАГ 2. Загрузка и очистка данных

Теперь пришло время получить доступ к данным, которые мы будем использовать для нашей задачи классификации изображений. В правой части записной книжки в разделе input вы найдете "microsoft-catsvsdogs-dataset". В этом разделе внутри PetImages у нас есть разделы «Кошки» и «собаки», содержащие изображения. Мы будем загружать эти данные, чтобы их можно было использовать для нашей задачи классификации.

Проработав несколько итераций и решив случай непригодных изображений, я придумал код, который идентифицирует бесполезные изображения (в нашем случае 2 из 25000 изображений). Давайте запустим код ниже, чтобы узнать, какие это изображения в нашем наборе данных.

path = Path("../input/microsoft-catsvsdogs-dataset/PetImages").rglob("*.jpg")
for img_p in path:
    try:
        img = PIL.Image.open(img_p)
    except PIL.UnidentifiedImageError:
            print(img_p)

# path here is our image dataset path => and it looks into .jpg files
# if any image is unidentified, that image path is printed

Приведенный выше код печатает:

../input/microsoft-catsvsdogs-dataset/PetImages/Dog/11702.jpg
../input/microsoft-catsvsdogs-dataset/PetImages/Cat/666.jpg

Эти 2 файла изображений не идентифицированы.

Теперь у нас есть большинство файлов .jpg и несколько файлов .db, которые бесполезны. Итак, в этом коде мы попытаемся найти в наших файлах расширения, отличные от .jpg, и удалим их.

# changing the file path
!cp -r ../input/microsoft-catsvsdogs-dataset/PetImages ./

# ends will take down the file extensions except .jpg
ends = []

# the code below will make sure that non jpg files are removed
for content in ('Cat', 'Dog'):
    path = os.path.join('./PetImages/', content)
    print(path)
    print(len(os.listdir(path)))
    for file in os.listdir(path):
        dot = file.index('.')
        end = file[dot+1:]
        if end != 'jpg':
            if ends.count(end) == 0:
                ends.append(end)
            fpath = path + '/' + file
            os.remove(fpath)

# printing list of non-jpg extensions               
set(ends)

Был получен следующий вывод:

./PetImages/Cat
12501
./PetImages/Dog
12501
{'db'}

Это говорит о том, что у нас есть 12501 изображение кошек и собак, а также файлы с расширениями .db.

Теперь удаляем поврежденные файлы:

to_skip = ['./PetImages/Dog/11702.jpg', './PetImages/Cat/666.jpg', './PetImages/Dog/3982.jpg']

for lnks in to_skip:
    os.remove(lnks)

Наш набор данных теперь чист, и мы готовы работать над дополнением, разделением набора и моделированием.

2. Анализ данных

  • Разделение данных без увеличения => Здесь мы будем использовать метод image_dataset_from_directory, который мы импортировали ранее, и зададим ему такие параметры, как batch_size=32, image_size=(224, 224) и validation_split=0.1. соответственно.
train_df = image_dataset_from_directory(
    directory='./PetImages',
    color_mode='rgb',
    batch_size=32,
    image_size=(224, 224),
    validation_split=0.1,
    subset='training',
    seed=45
)

val_df = image_dataset_from_directory(
    directory='./PetImages',
    color_mode='rgb',
    batch_size=32,
    image_size=(224, 224),
    validation_split=0.1,
    subset='validation',
    seed=45
)
  • Нанесение изображений
# using matplotlib library for plotting cats and dogs images of our dataset

plt.figure(figsize=(12, 12))
num_rows = 3
num_cols = 3

for imgs, labels in train_df.take(1):
    print(imgs.shape)
    print(labels)
    for i in range(9):
        s = plt.subplot(num_rows, num_cols, i+1)
        plt.imshow(imgs[i].numpy().astype('uint8'))
        plt.title(int(labels[i]))
        plt.axis('off')

Следующее изображение было получено с ключом 1, помеченным как собаки, и ключом 2, пометившим кошек.

3. Расширение данных

Использование метода image.ImageDataGenerator() из keras.preprocessing API для увеличения данных. Это гарантирует создание filp-изображений, повернутых на 20 градусов и масштабированных до 1/255. Из этих дополненных изображений создается обучающий и проверочный набор изображений.

MAIN_PATH = './PetImages'

CLASSES = os.listdir(MAIN_PATH)
NUM_CLASSES = 2
HEIGHT,WIDTH = 224, 224
BATCH_SIZE = 32
SPLIT = 0.2


train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    horizontal_flip=True,
    validation_split=SPLIT)

train_ds = train_datagen.flow_from_directory(
    MAIN_PATH,
    target_size = (HEIGHT,WIDTH),
    batch_size = BATCH_SIZE,
    subset = "training",
    class_mode = "categorical",
    shuffle = True
)

val_ds = train_datagen.flow_from_directory(
    MAIN_PATH,
    target_size = (HEIGHT,WIDTH),
    batch_size = BATCH_SIZE,
    subset = "validation",
    class_mode = "categorical",
    shuffle = True
)

Теперь основная задача — применение модели трансферного обучения.

4. ПЕРЕНОС ОБУЧЕНИЯ

ШАГ 1.Импорт трансферного обучения — модель DENSENET201 с помощью Keras API.

from keras.applications.densenet import DenseNet201

ШАГ 2. Использование DenseNet с параметром include_top=False

Мы выбираем веса imagenet и входную форму (224, 224, 3)

dnsnet = DenseNet201(include_top=False, weights='imagenet', input_shape=(224, 224, 3))

ШАГ 3. Модель

Использовалась модель плотности сети201 с весами imagenet и дополнительно были добавлены 2 скрытых слоя.

Уровень-1 со 100 узлами и уровень-2 с 50 узлами. Уровень 3 — это выходной слой с двумя узлами, дающими результат для классификации кошек и собак.

for layer in dnsnet.layers:
    layer.trainable=False


x = tf.keras.layers.Flatten()(dnsnet.output)
x = tf.keras.layers.Dense(100, activation='relu')(x)
x = tf.keras.layers.Dense(50, activation='relu')(x)
preds = tf.keras.layers.Dense(2, activation='sigmoid')(x)

model1 = tf.keras.models.Model(inputs=dnsnet.input, outputs=preds)
# Creating the callback function

def create_callbacks():
    
    cpk_path = './best_model.h5'
    
    checkpoint = tf.keras.callbacks.ModelCheckpoint(
        filepath=cpk_path,
        monitor='val_accuracy',
        mode='max',
        save_best_only=True,
        verbose=1,
    )

    reducelr = tf.keras.callbacks.ReduceLROnPlateau(
        monitor='val_accuracy',
        mode='max',
        factor=0.1,
        patience=3,
        verbose=0
    )

    earlystop = tf.keras.callbacks.EarlyStopping(
        monitor='val_accuracy',
        mode='max',
        patience=10, 
        verbose=1
    )
    
    callbacks = [checkpoint, reducelr, earlystop]         
    
    return callbacks

Компиляция, обучение и прогнозирование

model1.compile(
    loss=tf.keras.losses.binary_crossentropy,
    optimizer=tf.keras.optimizers.Adam(lr=1e-4),
    metrics=['accuracy']
)

callbacks = create_callbacks()

model1.fit(train_ds, epochs=15, validation_data=val_ds, callbacks=callbacks)

preds = model1.predict(val_ds)
preds = np.argmax(preds)

print((preds == val_ds.labels).sum())
print(len(val_ds.labels))
print(model1.evaluate(val_ds))

Эта модель обеспечивает точность 99,7 % на тренировочном наборе.

5. Прогнозы

  • Сохранение, загрузка и оценка модели
model1.save('densenet_best_model.h5')

new_model = tf.keras.models.load_model('best_model.h5')
new_model2 = tf.keras.models.load_model('densenet_best_model.h5')

new_model.evaluate(val_ds)
new_model2.evaluate(val_ds)

Теперь, чтобы проверить, хорошо ли работает модель, я составил небольшой набор данных из 20 изображений кошек и собак, взятых случайным образом из Google, и пометил их соответствующим образом.

Ссылку на набор данных можно найти здесь. Вы также можете создать свой аналогичный набор данных для этой цели.

  • Загрузка нового набора данных и получение прогнозов

Вы можете поместить этот набор данных в раздел ввода справа и получить к нему доступ непосредственно оттуда.

images = os.listdir('../input/catdogsforCheck')

# Plotting images
plt.figure(figsize=(12, 12))
num_rows = 3
num_cols = 3

for i in range(9):
    s = plt.subplot(num_rows, num_cols, i+1)
    img = Image.open('../input/catdogsforCheck/' + str(images[i]))
    img = np.array(img)
    plt.imshow(img)
    plt.title(images[i][:1])
    plt.axis('off')

Вот некоторые из изображений различных входных форм и типов, которые я поместил в набор данных.

  • Прогноз
from keras.applications.densenet import preprocess_input
prediction_table = []

for i in range(len(images)):
    actual_label = images[i][:1]
    img = Image.open('../input/catdogsforCheck/' + str(images[i]))
    img = img.resize(val_ds.target_size)
    img = np.array(img)
    x = np.expand_dims(img, axis=0)
    x = preprocess_input(x)
    
    prediction = np.argmax(new_model.predict(x), axis=1)
    data = {'Image': i, 'ActualLabel': actual_label, 'Prediction': prediction[0]}
    prediction_table.append(data)
    
prediction_table = pd.DataFrame(prediction_table)

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()

prediction_table.ActualLabel = le.fit_transform(prediction_table.ActualLabel)


prediction_table
  • Результаты

19 из 20 изображений были предсказаны хорошо.

Итак, точность составляет 95%. Но если в предсказание будут включены тысячи изображений, например, тренировочный набор, он будет точно иметь 98–99% исправлений.

Спасибо за чтение этого. Это мой самый первый учебник по программированию, поэтому, пожалуйста, извините меня за плохой сценарий, но я обещаю дать мне лучшее в следующих уроках.

С уважением и благодарностью.