Python, Нейронные сети, Обработка документов

Классификация изображений с помощью TensorFlow и Keras

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

На данных момент популярными в использовании библиотеками на Python, для написания нейросети, являются TensorFlow и Keras. Стоит отметить, что и их эффективность тоже находится на высоте.

Классификацию изображения можно описать как подача изображения в нейронную сеть и присвоения какой-либо метки этому изображению. Метка, выбранная нейросетью, будет соответствовать классу, который вы заблаговременно определили. Изображению может быть присвоена как одна, так и несколько меток. Если изначально была определена одна метка, это будет задачей по «распознаванию», если задача подразумевает поиск нескольких типов меток, тогда принято говорить, что это задача «классификации».

Работа нейросети состоит из процессов:

1) Извлечение признаков при помощи фильтров (Признаки — это элементы данных, которые будут обрабатываться нейронной сетью и объединяют все изображения, принадлежащие одной группе).

2) Функции активации (Функция активации берет на обработку значения признаков, которые после преобразования свёрточным слоем имеют вид линейной формы и усиливают их нелинейность).

3) Объединение слоёв (Оно «облегчает» изображение: берёт информацию об изображении, и сокращает её).

4) Сжатие (Значения последних слоёв преобразуется в столбец (вектор) последовательно упорядоченных чисел).

5) Связка слоёв (На этом этапе определяется вероятность принадлежности изображения каждому из классов в пределах единицы).

Если вы новичок и эти понятия ни о чём вам не говорят, то советую сначала поискать дополнительную информацию в интернете. К счастью, материалов опубликовано достаточно много.

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

Перед тем как приступить к написанию кода, необходимо проверить данные которые вы хотите обработать. Необходимо чтобы все фотографии были в едином формате, разрешении. Конечно же нужно подготовить обучающую и тестовую выборку, качественно разделив фотографии по признакам. Даже если вы пользуетесь готовым DataSet, то не стоит пропускать шаг проверки фотографий, ответственность за качество итогового результата, будет на том, кто его предоставил.

Приступим к написанию кода (в комментариях много полезной информации, советую их не пропускать):

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K

image_width, image_height = 250, 250 # Указываем разрешение для изображений к единому формату

directory_data_train= 'dir/train' #Указываем путь к обучающей выборке train_data_dir 
directory_data_validation= 'dir/validation'  #Указываем путь к проверочной выборке validation_data_dir 

# Сразу устанавливаем необходимые параметры

train_sample = 1450
validation_sample = 850
epochs = 8
lot_size = 25  #batch_size 
if K.image_data_format() != 'channels_first':
     input_shape = (image_width, image_height, 3)
else:
     input_shape = (3, image_width, image_height)   

Первый этап закончен, все необходимые библиотеки импортированы, параметры установлены. Выбор разрешения изображений тоже важен, советую поэкспериментировать и подставлять их в диапазоне от 200-300 с шагом в 50px.

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

Параметр lot_size это количество пакетов, обрабатываемое при тренировке модели за единицу времени. Если компьютер, на котором вы работаете, недостаточно мощный, то не стоит делать значение этого параметра слишком маленьким. Чем больше значение lot_size, тем быстрее будет проходить обучение.

pattern = Sequential() # Создание модели

# Первый слой нейросети
pattern.add(Conv2D(32, (3, 3), input_shape=input_shape))
pattern.add(Activation('relu'))
patternl.add(MaxPooling2D(pool_size=(2, 2)))

# Второй слой нейросети
pattern.add(Conv2D(32, (3, 3)))
pattern.add(Activation('relu'))
pattern.add(MaxPooling2D(pool_size=(2, 2)))

# Третий слой нейросети
pattern.add(Conv2D(64, (3, 3)))
pattern.add(Activation('relu'))
pattern.add(MaxPooling2D(pool_size=(2, 2)))

#Aктивация, свертка, объединение, исключение
pattern.add(Flatten())
pattern.add(Dense(64))
pattern.add(Activation('relu'))
pattern.add(Dropout(0.5))
pattern.add(Dense(2))# число классов
pattern.add(Activation('softmax'))

#Cкомпилируем модель с выбранными параметрами. Также укажем метрику для оценки.
pattern.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

Следующим шагом нужно провести аугментацию (больше о параметрах настройки ImageGenerator можно почитать по ссылке):

# Задаём параметры аугментации
train_datagen = ImageDataGenerator(
    rescale=1. / 255, # коэффициент масштабирования
    shear_range=0.2, # Интенсивность сдвига
    zoom_range=0.2, # Диапазон случайного увеличения
    horizontal_flip=True) # Произвольный поворот по горизонтали
 test_datagen = ImageDataGenerator(rescale=1. / 255)

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

Перед тем как начать тренировку модели нужно запустить предобработку изображений:

#Предобработка обучающей выборки
 train_processing = train_datagen.flow_from_directory(
    directory_data_train,
    target_size=(image_width, image_height), # Размер изображений
    batch_size=lot_size, #Размер пакетов данных
    class_mode='categorical') # Режим класса

#Предобработка тестовой выборки
validation_processing= test_datagen.flow_from_directory(
    directory_data_validation,
    target_size=(image_width, image_height),
    batch_size=lot_size,
    class_mode='categorical')

Почитать больше о параметрах функции flow_from_directory можно по ссылке

Осталось только запустить тренировку и посмотреть на результат:

pattern.fit_generator(
    train_processing, # Помещаем обучающую выборку
    steps_per_epoch=train_sample // lot_size, #количество итераций пакета до того, как период обучения считается завершенным
    epochs=epochs, # Указываем количество эпох
    validation_data=validation_processing, # Помещаем проверочную выборку
    validation_steps=validation_sample  // lot_size) # Количество итерации, но на проверочном пакете данных

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

Оценка работы обученной модели должна проходить на размеченных данных, не участвующих в обучении. На скриншоте параметр loss означает коэффициент неудачной работы модели, а accuracy наоборот показывает коэффициент удачной отработки модели.

Если обучение проходит хорошо, то loss будет уменьшаться, accuracy наоборот увеличиваться. Если вы заметили, что loss начал расти, то количество epochs нужно уменьшить. Если результат вас совсем не устраивает, то стоит поменять параметры train_sample, alidation_sample, lot_size, добавить, или убрать слои нейросети.

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

Результат, который вы видите на скриншоте я получила на обучающей выборке 4000 и тестовой 2000 изображений.

Сохранять результат работы модели, очень важно (не сохранив результат работы модели, вы теряете самое важное, время, затраченное на этап работы модели — это может занять от 5 минут до часа и более, в зависимости от объёмов ваших выборок):

pattern.save_weights('first_model_weights.h5') #Сохранение весов модели
pattern.save('path') #Сохранение модели
pattern.load_weights('first_model_weights.h5') # Загрузка весов модели
prediction = pattern.predict(x) #Использование модели для предсказания

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

Советуем почитать