Обучение нейронной сети распознаванию цифр 0–9 считается «Привет, мир» глубокого обучения. Как и в традиционных примерах «Hello World», где вас заставляют выводить на экран текст «Hello World», возможность классифицировать цифры с помощью модели, обученной на MNIST с удовлетворительным уровнем точности, является признаком того, что ваша среда была установка успешно.

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

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

Посмотрев демо, приступим к кодированию. Я сделал код доступным в моей учетной записи Github, так что не стесняйтесь клонировать его и опробовать локально на своей рабочей станции. Кроме того, я считаю важным сообщить вам, что модель в коде не самая лучшая из возможных, однако для демонстрационного приложения я считаю, что это нормально. Если есть какие-то улучшения, которые вы хотите сделать, просто создайте PR репо, и я с радостью внесу ваши изменения, если они действительно улучшат производительность. На самом деле, модель переоснащается обучающими данными, и я не стал добавлять регуляризаторы или слои исключения для контроля переобучения, потому что я хочу, чтобы это было легко для всех. Изображение ниже свидетельствует о том, что модель не соответствует обучающим данным.

Хватит разговоров! Давайте обсудим код!

В строке 12 я загружаю данные обучения и тестирования MNIST. Набор данных MNIST состоит из 60 000 обучающих изображений и 10 000 тестовых изображений для оценки производительности вашей сети.

Между строками 16 и 20 я предварительно обрабатываю данные, чтобы они соответствовали формату, необходимому для обучения модели, которую нужно построить. Исходные данные обучения имеют форму (60000,28,28). То есть 60 000 образцов изображений размером 28x28 пикселей. Однако в нашу модель CNN будут подаваться изображения в оттенках серого 28x28. И поскольку изображения в градациях серого имеют только 1 канал, я изменяю форму данных на (60000,28,28,1). Очень важным шагом в обучении моделей DL является масштабирование функций. Цель масштабирования функций - убедиться, что значения отдельных функций не слишком сильно различаются. Если значения характеристик слишком отличаются от начальных случайных значений веса, назначенных узлам в слоях, градиентный спуск будет делать большие шаги, и мы не сможем найти точку глобального минимума. В изображениях в градациях серого хранятся значения пикселей от 0 до 255. 0 для полного черного и 255 для полного белого. Любое значение от 0 до 255 будет оттенком серого, приближающимся к белому в положительном направлении оси x и черному в отрицательном направлении оси x. Чтобы масштабировать функции так, чтобы они имели значения в диапазоне от 0 до 1, я делю каждое значение пикселя на 255. Таким образом, значения пикселей в обучающем и тестовом изображениях достаточно близки к случайно назначенным весам в начале обучение.

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

Игнорировать строку 22. Я адаптировал этот код из плотно связанной модели, которую я построил ранее, и я забыл удалить эту строку. В CNN это не нужно.

Между строками 26 и 36 я строю модель, компилирую ее и подгоняю к предварительно обработанным обучающим данным. Кроме того, я оставляю 30% обучающих данных для использования для проверки. В идеале данные проверки должны использоваться для настройки гиперпараметров, когда вы пробуете различные архитектуры моделей, скорости обучения и т. Д., Чтобы найти лучшую модель и параметры, которые наилучшим образом соответствуют вашим данным. В данном конкретном случае я не выполнял настройку гиперпараметров, потому что хочу, чтобы это была демонстрация «Hello World».

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

self.model.fit (self.training_images, self.training_targets, validation_split = 0.3, callbacks = [EarlyStopping (терпение = 2)], эпохи = 50)

Между полотном 38 и 40 я определяю метод «прогнозирования», который применяет те же шаги предварительной обработки к входному изображению и просит сеть предсказать цифру для изображения. Важно отметить, что вы не можете попросить модель DL делать прогнозы на основе данных, которые отличаются от данных, на которых она была обучена. В методе прогнозирования я изменяю размер изображения до изображения 28x28 пикселей (потому что это размер изображений в наборе данных MNIST), я преобразовываю его в (28,28,1) и, наконец, масштабирую пиксели для получения значений от 0 до 1, разделив их на 255, как это было сделано на этапе предварительной обработки перед обучением модели.

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

В строках 5 и 6 я создаю экземпляр класса NeuralNet, который мы создали для модели, и вызываю show_performance, чтобы показать график потерь и точности в зависимости от эпох. Не стесняйтесь прокомментировать строку 6, если вы не хотите видеть этот график. Да какая разница :).

В одной строке 9 я создаю холст в оттенках серого 600x600 пикселей, который будет служить нам нашей поверхностью для рисования в окне OpenCV. Чтобы обозначить интересующую область на холсте, где, как я предполагаю, будет нарисована цифра, я выделяю центральные 400x400 пикселей и устанавливаю их черного цвета. Также обратите внимание, что важно, чтобы ваши цифры были нарисованы белыми чернилами на черном фоне, потому что именно так были созданы изображения в наборе данных MNIST. Белое на черном !!!

Метод draw_line, определенный в строке 17, просто рисует белую линию между двумя точками на заданном холсте.

Строки с 20 по 34 определяют обратный вызов ловушки мыши, который будет вызываться каждый раз, когда событие мыши происходит в окне OpenCV. Таким образом, он фиксирует координаты x-y указателя мыши между моментом, когда вы начинаете рисовать цифру, нажимая «s» (подробнее об этом позже), и временем, когда вы отпускаете левую кнопку мыши. Для всех этих захваченных точек x-y рисуются линии, соединяющие их, образуя фигуру на пути, который вы проложили с помощью указателя мыши.

Между строками 37 и 38 создается именованное окно OpenCV и регистрируется обратный вызов ловушки мыши сверху для прослушивания событий мыши в этом окне.

Между строками с 40 по 53 окна OpenCV перехватывают нажатия клавиш для выполнения следующих действий:

  1. Нажмите "s", чтобы указать, что вы хотите начать рисовать цифру.
  2. Нажмите «c», чтобы очистить ранее нарисованную цифру и подготовить холст для другого рисунка.
  3. Когда закончите рисовать цифру, нажмите «p». Это заставит обученную модель показать, что она предсказывает начертанную вами цифру. Прогноз будет показан в консоли.
  4. Наконец, когда вам достаточно этой демонстрации, нажмите «q», чтобы выйти из холста OpenCV.

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

Теперь, когда вы могли делать прогнозы на изображениях вне MNIST, что дальше? Что ж, просто дайте волю своему воображению. Вы можете дополнительно выполнить настройку гиперпараметров, чтобы модель была готова к производству. А когда у вас будет достаточно хорошая модель, вы можете экспортировать полученные веса в файл для переноса обучения. Только представьте, что вы можете нарисовать 0, чтобы выключить свет, или 1, чтобы включить его. Вы можете легко сделать это с помощью Raspberry Pi. Вы также можете изменить канал на телевизоре, указав номер канала. Все, что вам нужно для этого, - это поверхность для рисования (мобильный телефон) и инфракрасный светодиод. Вы также можете позволить людям рисовать PIN-коды для аутентификации вместо нажатия клавиш. Ваше воображение - единственный здесь ограничивающий фактор.

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