Время прочтения: 3 мин.

Для реализации задуманного нам нужно выполнить три этапа:

  1. Сформировать датасет
  2. Построить сеть
  3. Проверить результат

Этап 1: Формируем датасет

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

Для тех, у кого нет под рукой большого количества нужных изображений, стоит опробовать следующие варианты:

  • обычные запросы в поисковых системах (Google, Yandex, TOR) PictureYandexGraber/PictureGoogleGraber – помогут скачать изображения прямо по запросу;
  • вот в этой статье перечислены основные источники датасетов —https://habr.com/ru/post/452392/

Этап 2: Создаем сеть

Задаем параметры: высоту, ширину, каналы изображения (3 – цветное, 1 – черно-белое), количество эпох и коэффициент скорости обучения

# Параметры 

IMAGE_WIDTH = 128
IMAGE_HEIGHT = 128
IMAGE_CHANNELS = 3
INPUT_SHAPE = (IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS)
EPOCHS = 35

# 0.0005, 0.001, 0.00146 
LR = 0.001

Этап 3: Подготавливаем данные.

На этом шаге мы создаем отдельные папки с данными для обучения и валидации:

C:\User\Train\
	\class1\
		Img1.jpg
		Img2.jpg
	\class2\ 
		Img001.jpg
		Img002.jpg
C:\User\Validation\
	\class1\
		Img3.jpg
		Img4.jpg
	\class2\ 
		Img003.jpg
		Img004.jpg

Здесь мы задаем путь к сохраненному датасету, создаем ImageDataGenerator для аугментации (незначительного преобразования) изображений для расширения тренировочной выборки и забираем изображения из директорий/

# Данные, аугментация

from keras.preprocessing.image import ImageDataGenerator

train = r'Путь к тренировочным данным (C:\User\Train\)'
validat = r'Путь к проверочным данным (C:\User\Validation\)'

train_datagen = ImageDataGenerator(rotation = 40,
                                   rescale=1./255,
                                  shear_range = 0.2,
                                  zoom_range = 0.2,
                                  horizontal_flip = True,
                                  fill_mode = 'nearest',
                                  width_shift_range = 0.2,
                                  height_shift_range = 0.2)


test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory(superTrain,
                                                 target_size = (128, 128),
                                                 batch_size = 32,
                                                 class_mode = 'binary',
                                                 shuffle=True,
                                                 seed=42)

testing_set = test_datagen.flow_from_directory(validat,
                                            target_size = (128, 128),
                                            batch_size = 1,
                                            shuffle=False,
                                            class_mode = 'binary')
# Настройски обучения

import time

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, Activation
from keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint

# Используем ранний выход, если модель не улучшается в течение 5 шагов
earlystop = EarlyStopping(monitor='val_loss', patience=5, verbose=0)

# Сохраняем лучшую модель относительно val_loss (значения потерь при проверке)
checkpointer = ModelCheckpoint(filepath = r'Путь к модели (‘C:\User\best_weight.hdf5'), monitor='val_loss', verbose=0, save_best_only=True)

Строим CNN сеть

from keras.optimizers import Adam

print(‘Поехали’)

STEP_SIZE_TRAIN = training_set.n//training_set.batch_size
STEP_SIZE_TEST = testing_set.n//testing_set.batch_size

CONV_LAYERS = [2]
LAYER_SIZES = [64]
DENSE_LAYERS = [2]

# Оптимизатор
opt = Adam(lr=LR, decay=1e-6)

for dense_layer in DENSE_LAYERS:
    for layer_size in LAYER_SIZES:
        for conv_layer in CONV_LAYERS:
            NAME = "{}-conv-{}-nodes-{}-dense-{}".format(conv_layer, layer_size, dense_layer, int(time.time()))
            print(NAME)

            model = Sequential()
            
            # Входной слой 
            model.add(Conv2D(layer_size, (3, 3), input_shape = INPUT_SHAPE, activation = 'relu'))
            model.add(MaxPooling2D(pool_size = (2, 2)))

            # Скрытый слой
            for l in range(conv_layer-1):
                model.add(Conv2D(layer_size, (3, 3)))
                model.add(Activation('relu'))
                model.add(MaxPooling2D(pool_size=(2, 2)))

            model.add(Flatten())

            for _ in range(dense_layer):
                model.add(Dense(layer_size))
                model.add(Activation('relu'))
            
            # Выходной слой
            model.add(Dense(1))
            model.add(Activation('sigmoid'))

	    callbacks = [earlystop, checkpointer]

            model.compile(loss='binary_crossentropy',
                          optimizer=opt,
                          metrics=['binary_accuracy'])

            # Смотрим слои
            model.summary()
            
            # Запускаем обучение	
            history = model.fit(training_set, 
                                epochs = EPOCHS, 
                                steps_per_epoch=STEP_SIZE_TRAIN,
                                validation_data = testing_set,
                                validation_steps=STEP_SIZE_TEST,
                                callbacks=callbacks)

Этап 3: проверяем результаты

Выводим основные метрики

from sklearn.metrics import classification_report, confusion_matrix

# Выводим названия классов/папок            
print(training_set.class_indices) 

# Основные метрики 
print('Classification Report')
print(classification_report(testing_set.classes, y_pred, target_names=labels))

Делаем предсказание на новом изображении

from keras.preprocessing import image
import numpy as np

img_path = r'Путь к изображению C:\User\....\img.jpg'

test_image = image.load_img(img_path, target_size = INPUT_SHAPE)
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = model.predict(test_image)

if result[0][0] == 1:
    prediction = 'class2'
else:
    prediction = 'class1'

print(prediction, result)

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

Надеемся, данная статья поможет освоить азы построения нейронных сетей.