УДК 004.8

Распознавание рукописных цифр при помощи сверточных нейронных сетей

Гель Андрей Юрьевич – студент бакалавриата Балтийского федерального университета имени Иммануила Канта.

Аннотация: В статье рассматривается применение сверточных нейронных сетей для задачи классификации рукописных цифр. Дается теоретическое описание сверточных нейронных сетей и их составных слоев. Затем описывается практическая часть построения такого рода сетей. Характеризуются входные данные для обучения, затем над этими данными выполняется аугментация для преодоления проблемы переобучения модели. Далее строится конкретная структура нейронной сети и производится обучение на подготовленных данных. После обучения модели сверточной нейронной сети, выполняется оценка точности модели с помощью метрик классификации для каждой из цифр отдельно.

Ключевые слова: машинное обучение, классификация, сверточные нейронные сети, распознавание изображений.

Введение

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

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

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

Сверточные нейронные сети

Свёрточная нейронная сеть (англ. convolutional neural network, CNN) — специальная архитектура искусственных нейронных сетей, предложенная Яном Лекуном в 1988 году и нацеленная на эффективное распознавание образов, входит в состав технологий глубокого обучения (англ. deep learning) [1].

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

1

Рисунок 1. Входные данные сверточной нейронной сети.

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

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

Сверточный слой представляет из себя набор карт (другое название – карты признаков, в обиходе это обычные матрицы), у каждой карты есть синаптическое ядро (в разных источниках его называют по-разному: сканирующее ядро или фильтр) [2].

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

2

Рисунок 2. Работа сверточного слоя.

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

Следующий слой, в который попадают данные при использовании сверточной нейронной сети это слой пуллинга. Пулинговый слой призван снижать размерность изображения. Исходное изображение делится на блоки размером w×h и для каждого блока вычисляется некоторая функция. Чаще всего используется функция максимума (англ. max pooling) или (взвешенного) среднего [3].

3

Рисунок 3. Пример операции пуллинга.

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

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

Последним слоем, через который пройдут данные в сверточной нейронной сети является полносвязный слой. Полносвязный слой — слой, выходные нейроны которого связаны со всеми входными нейронами. Нейроном в данном случае называется математическая модель искуственного нейрона, основанная на представлении о биологическом нейроне, однако в действительности не имеющая с ним практически ничего общего [4].

4

Рисунок 4. Работа полносвязного слоя.

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

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

Подготовка данных для обучения

Для того чтобы будущая нейронная сеть смогла различать различные рукописные цифры ее необходимо обучить на соответствующем наборе данных. В качестве данных для обучения можно взять готовый датасет MNIST из библиотеки Keras. Это набор данных из 60 000 изображений в оттенках серого 28x28 из 10 цифр, а также тестовый набор из 10 000 изображений [5].

5

Рисунок 5. Визуализация данных датасета MNIST.

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

Листинг 1. Предобработка данных MNIST

from keras.datasets import mnist

num_classes = 10

input_shape = (28, 28, 1)

 (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

x_train = x_train.astype("float32") / 255

x_test = x_test.astype("float32") / 255

x_train = np.expand_dims(x_train, -1)

x_test = np.expand_dims(x_test, -1)

y_train = keras.utils.to_categorical(y_train, num_classes)

y_test = keras.utils.to_categorical(y_test, num_classes)

Запишем в переменную num_classes количество объектов для классификации. Так как мы классифицируем рукописные цифры, то количество классов будет равным 10. В переменную input_shape запишем размерность данных для обучения. В данном случае это изображения размером 28х28 с одним каналом цветности.

Далее непосредственно загружаем датасет из библиотеки Keras с помощью метода load_data. Далее делим данные на 255, чтобы значения в датасете изменялись в пределах от 0 до 1 (нормализация значений). И в конечном счете преобразовываем векторы классов в бинарные матрицы классов.

После этих преобразований было получено 4 массива данных: x_train (изображения обучающей выборки), x_test (изображения тестовой выборки), y_train (множество ответов для обучающей выборки), y_test (множество ответов для тестовой выборки).

Следующий шаг это решить проблему переобучения модели. Один из способов этого использование аугментации ("увеличение") тренировочного датасета без привлечения реальных новых картинок. Попробуем изменять наши исходные картинки перед тем, как они попадут в сетку при помощи различных трансформаций. Конечно, можно было бы поштучно изменить каждую картинку, сохранить, как новый датасет и тренировать модель уже на нем. Но это дает меньшую вариативность преобразований, занимает много места и памяти. Чтобы не изменять каждую картинку вручную, используют генераторы.

Создадим такой генератор на основе наших данных при помощи модуля ImageDataGenerator из библиотеки Keras.

Листинг 2. Создание аугментации данных

from keras.preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(width_shift_range=0.1, rotation_range=75)

train_generator = datagen.flow(x_train, y_train, batch_size=128)

В качестве трансформаций используется: width_shift_range=0.1 (случайно подвинуть картинку по горизонтали на 0.1 ширины), rotation_range=75 (случайно повернуть картинку в диапазоне от 0 до 75 градусов).

6

Рисунок 6. Визуализация данных датасета MNIST после аугментации.

Теперь после того как данные были предварительно обработаны и над ними выполнена аугментация, они полностью готовы к применению машинного обучения.

Создание структуры нейронной сети

Теперь, когда данные подготовлены для применения нейронной сетью, необходимо создать структуру будущей модели. Построим сверточную нейросеть из нескольких VGG-блоков: conv-conv-maxpool. VGG - семейство существующих архитектур нейросетей, которые демонстрируют одни из лучших результатов в задачах выделения признаков из картинок.

Зададим функцию, создающую модель нейросети из двух VGG блоков - define_model, где

  • Kernel_initializer - способ задавания начальных значений для весов ядра сверточного слоя нейросети
  • he_uniform - специальное распределение, которое позволяет улучшить способности нейросети в сравнении с просто случайным распределением весов

Листинг 3. Создание структуры сверточной нейронной сети

def define_model():

model = Sequential()

#VGG1-блок

model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(28, 28, 1)))

model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))

model.add(MaxPooling2D((2, 2)))

model.add(Dropout(0.2))

#VGG2-блок

model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))

model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))

model.add(MaxPooling2D((2, 2)))

model.add(Dropout(0.2))

# Разворачиваем данные в вектор

model.add(Flatten())

model.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))

model.add(Dropout(0.2))

model.add(Dense(10, activation='softmax'))

model.compile(loss='categorical_crossentropy',

optimizer = 'nadam',

metrics = ['accuracy'])

return model

В каждом VGG-блоке определяется 2 сверточных слоя. После них используется метод MaxPooling, который уменьшает размер обрабатываемого изображения, выбирая из 4 пикселей 1 с максимальным значением, чтобы это быстрее считалось. В конце блока применяется слой dropout, который на каждом шаге «выключает» 20% случайно выбранных нейронов.

После VGG-блоков данные разворачиваются в вектор и добавляются полносвязные слои.

Когда все слои заданы модель осталось скомпилировать. Компилируем модель с функцией ошибки categorical crossentropy, оптимизатором Адам (оптимизатор, который со стандартным набором параметров может обучить эффективную нейросеть), и метрикой - количеством правильно угаданных картинок.

Обучение нейронной сети

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

Листинг 4. Обучение модели

base_model = define_model()

history_cnn = gen_model.fit_generator(train_generator,

epochs=10,

validation_data=(x_test, y_test))

При помощи функции define_model строим последовательную сверточную нейросеть. Обучим модель с данными из генератора при помощи метода fit_generator. На выходе будет получена натренированная модель и структура history_cnn, из которой можно достать значения функции ошибки и метрик качества на обеих выборках. Количество эпох равно 10.

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

Листинг 5. Вывод графиков точности на валидационной и обучающих выборках

plt.plot(history_cnn.history['val_accuracy'], '-o', label='validation accuracy')

plt.plot(history_cnn.history['accuracy'], '--s', label='training accuracy')

plt.legend();

7

Рисунок 7. Графики изменения точности на валидационной и обучающих выборках.

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

Листинг 6. Вывод точности для каждой из цифр отдельно

from sklearn.metrics import classification_report

predict_gen = gen_model.predict(x_test)

predict_gen = np.argmax(predict_gen, axis = 1)

y_test1 = np.argmax(y_test, axis = 1)

print(classification_report(y_test1, predict_gen))

Таблица 1. Метрики результатов классификации рукописных цифр.

Цифра

precision

recall

f1-score

support

0

1.00

1.00

1.00

985

1

0.99

0.99

0.99

1135

2

0.99

0.99

0.99

1032

3

0.99

0.99

0.99

1010

4

0.98

0.99

0.99

982

5

0.99

0.98

0.99

892

6

0.99

0.99

0.99

958

7

0.98

0.99

0.99

1028

8

1.00

0.99

0.99

974

9

0.98

0.98

0.98

1009

Как видно по полученным метрикам, модель лучше всего распознает цифры «0» и «8» точность их распознавания равна 1. В случае с остальными цифрами точность их распознавания не ниже 0.98, что демонстрирует отличный результат работы модели.

Заключение

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

При реализации практической части была успешно построена и обучена сверточная нейронная сеть для распознавания рукописных цифр.

В качестве исходных данных для обучения был взят датасет MNIST из библиотеки Keras, содержащий 60000 изображений с рукописными цифрами и еще 10000 изображения для тестирования модели.

Затем данные из датасета MNIST были нормализованы и преобразованы векторы классов в бинарные матрицы классов. Данные разбиты на обучающую и тестовую выборки.

Далее к данным применена аугментация (случайный сдвиг по горизонтали и случайный поворот картинки).

После первичных преобразований данных была создана структура нейронной сети, содержащая 2 VGG-блока и 2 полносвязных слоя в конце.

Произведено обучение модели на подготовленных данных. Количество эпох задано равным 10.

В конечном счете, получена точность модели, которая равна ~98.9%. А также точность модели для каждой из цифр, которая представлена в таблице 1.

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

Список литературы

  1. Свёрточная нейронная сеть. — Текст : электронный // Wikipedia : [сайт]. — URL: https://ru.wikipedia.org/wiki/Свёрточная_нейронная_сеть (дата обращения: 23.05.2023).
  2. Сверточная нейронная сеть, часть 1: структура, топология, функции активации и обучающее множество. — Текст : электронный // habr : [сайт]. — URL: https://habr.com/ru/articles/348000/ (дата обращения: 24.05.2023).
  3. Сверточные нейронные сети. — Текст : электронный // neerc.ifmo : [сайт]. — URL: https://neerc.ifmo.ru/wiki/index.php?title=Сверточные_нейронные_сети (дата обращения: 23.05.2023).
  4. Свёрточная нейронная сеть с нуля. Часть 4. Полносвязный слой. — Текст : электронный // programforyou : [сайт]. — URL: https://programforyou.ru/poleznoe/convolutional-network-from-scratch-part-four-fully-connected-layer#:~:text=Полносвязный слой — слой, выходные нейроны,с ним практически ничего общего. (дата обращения: 24.05.2023).
  5. MNIST digits classification dataset. — Текст : электронный // Keras : [сайт]. — URL: https://keras.io/api/datasets/mnist/ (дата обращения: 23.05.2023).

Интересная статья? Поделись ей с другими: