Распознавание символов, нарисованное от руки, с использованием TensorFlow.js (продолжение)

В последней части этой серии я показал вам, как обучить модель глубокого обучения на большом наборе данных с помощью TensorFlow.js (версия Node). Мы также увидели, как переключаться между режимом полного обучения и режимом частичного обучения, и, наконец, как сохранить обученную модель для использования во внешнем интерфейсе.

Этот пост представляет собой серию статей о глубоком обучении с помощью JavaScript. Я рекомендую вам ознакомиться с первыми двумя частями, чтобы узнать больше:

Часть 1: Прогнозирование площадей лесных пожаров (регрессия)

Часть 2: Распознавание рисованных символов (классификация)

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

  • Создайте холст JavaScript, на котором вы можете нарисовать число
  • Напишите код для извлечения изображения с холста
  • Обработать изображение
  • Загрузите сохраненную модель CNN
  • Делайте прогнозы с помощью модели
  • И, наконец, отобразите результат в пользовательском интерфейсе

Ссылка на полный код

Во-вторых, для запуска приложения нам понадобится мини-сервер. К счастью, express-generator, который мы использовали в предыдущем посте для создания скелета приложения, сделал это за нас. Глядя в конец файла app.js, вы можете увидеть строку, в которую мы экспортируем экспресс-приложение.

Чтобы запустить сервер, откройте терминал или командную строку в корневой папке вашего приложения (где находится app.js) и запустите:

npm start

Затем откройте браузер и перейдите по ссылке:

http://localhost:3000/

Если вы использовали ручки в качестве представления по умолчанию при создании скелета приложения с помощью express-generator, то вы, вероятно, столкнетесь с такой страницей с ошибкой:

Не беспокоиться! Это происходит из-за того, что у вас нет файла просмотра в общедоступном каталоге или каталоге просмотров. Чтобы исправить это, мы создадим index.html файл в общедоступном каталоге. Этот файл будет содержать дизайн нашего пользовательского интерфейса и интерфейс нашего приложения.

Отвези меня домой (Index.html)

Как мы упоминали ранее, файл index.html будет содержать HTML-код для пользовательского интерфейса. Давайте посмотрим поближе:

  • В заголовке файла index.html мы загружаем Bootstrap через CDN - это дает нам доступ к современному дизайну и быстродействию.
  • Затем (и это самое главное) мы загружаем пакет tensorflow.js. На этот раз мы загружаем его через CDN, а не на стороне клиента, как мы это делали в первом руководстве. Это дает нам доступ к TensorFlow API для обработки наших данных и загрузки сохраненной модели в браузере. И, наконец, загружаем JQuery.
  • Затем мы создаем div, чтобы удерживать наш холст (id=canvasDiv). Холст, на котором будет рисовать пользователь, будет создан с использованием JavaScript. Вскоре мы займемся этим процессом.
  • Затем мы добавляем еще два div, один с идентификатором predDiv, который будет отображать прогноз модели. Здесь мы также добавляем немного встроенного стиля.
  • Затем мы создаем две кнопки для взаимодействия с пользовательским интерфейсом. Первая кнопка (predict) делает прогноз после того, как число было нарисовано на холсте, а вторая кнопка (clear) удаляет текущий рисунок холста.
  • Наконец, в конце HTML-страницы мы связываем файл index.js в папке JavaScript.

Сохраните новый index.html файл, а затем запустите команду npm start в терминале. Откройте браузер и перейдите на свой локальный хост:

http://localhost:3000/

Теперь вы должны увидеть страницу, подобную показанной ниже:

Пространство над двумя кнопками - это пустой контейнер div для нашего холста, который мы создадим затем с помощью JavaScript.

Сделайте его живым (index.js)

Файл index.js - это сердце нашего приложения. Здесь мы создаем холст, на котором пользователь рисует, добавляем код для обработки изображения, загружаем сохраненную модель TensorFlow, делаем прогнозы и, наконец, отображаем результат в пользовательском интерфейсе. Во-первых, давайте разберемся с кодом, необходимым для рисования на холсте:

Да, это длинный фрагмент кода, но уверяю вас, это проще, чем кажется. Давайте пройдемся по каждому сегменту:

  • В первых 7 строках мы устанавливаем некоторые параметры, такие как ширина, высота, размер штриха, цвет и оператор if для нашего холста.
  • Далее мы создаем три массива. Первые два массива (clickX и clickY) будут содержать координаты (X, Y), нарисованные пользователем. Позже это используется для перерисовки всех точек на холсте. Следующий массив clickD содержит список логических значений. Если это false, это означает, что пользователь не рисует на холсте; в противном случае (true) пользователь рисует на холсте.
  • Затем мы получаем объект холста через его идентификатор, а затем создаем новый объект холста с помощью функции JavaScript createElement. После создания элемента холста мы устанавливаем для атрибутов значения, которые мы инициализировали ранее, а затем прикрепляем его к div холста, который мы создали в пользовательском интерфейсе.
  • Затем мы получаем контекст холста - это дает нам доступ к только что созданному объекту холста, чтобы его можно было обновлять в реальном времени с помощью событий мыши или касания.

В следующем разделе кода мы определяем функции, которые будут указывать, взаимодействует ли пользователь в данный момент с холстом или нет. В частности, мы будем использовать такие события, как mousedown, mousemove, mosueup, и mouseleave.

  • На mousedown, то есть когда пользователь удерживает мышь на холсте, мы получаем текущую точку / координату со страницы браузера, добавляем ее в массивы, которые мы инициализировали ранее, а затем рисуем ее на холсте, вызывая функцию drawOnCanvas. .
  • На mousemove, то есть когда пользователь перетаскивает мышь по холсту, мы также получаем точки, но на этот раз мы последовательно обновляем массив clickD логическими значениями, указывающими, что пользователь перетаскивает мышь. Это позволяет нам реконструировать перетаскиваемый путь.
  • На mouseup и mouseleave мы просто устанавливаем состояние рисования как false и ничего не делаем. Это состояние, когда пользователь перестал взаимодействовать с холстом.
  • Следующая функция, addUserGesture, просто помещает любую переданную точку в соответствующие массивы.
  • drawOnCanvas выполняет собственно рисунок на холсте. Перебирая каждую точку в сохраненных массивах, мы вызываем контекст холста, который мы создали ранее, и перерисовываем точки на экране, используя указанные стили. Это происходит каждый раз, когда пользователь нажимает на холст или перемещает его по холсту.
  • И наконец, мы добавляем функцию clear. Эта функция просто очищает все точки в текущем контексте холста, а также очищает массивы.

Теперь вы можете перезагрузить index.html страницу и поиграть с объектом холста. По завершении нажмите кнопку clear и убедитесь, что все работает нормально.

Теперь, когда у нас есть холст, давайте загрузим сохраненную модель и начнем прогнозирование!

Добавление движка (index.js)

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

  • Сначала мы получаем элементы пользовательского интерфейса для нашего обновленного состояния модели и отображаем прогноз модели.
  • Затем мы добавляем прослушиватель событий DOMContentLoaded. Это вызовет функцию loadmodel, как только страница загрузится. Это гарантирует, что модель загружается вовремя и вовремя доступна пользователю.
  • В функции loadmodel сначала используйте функцию tf.loadLayersModel, чтобы вести модель. Здесь мы передаем путь модели из папки ресурсов в общедоступный каталог. Обратите внимание, как мы добавили путь к серверу localhost: 3000 и не указали полный путь? Это связано с тем, что экспресс обслуживает все файлы в общей папке клиенту. Это означает, что все файлы в общей папке доступны для использования во внешнем интерфейсе и могут быть загружены.
  • Затем мы добавляем функцию getImageFromCanvas. Это происходит так, как предполагается: он принимает объект холста и передает его функции tf.browser.fromPixels . Эта функция может считывать данные непосредственно с объекта холста и преобразовывать его в пиксели изображения.
  • Затем мы привязываем несколько функций предварительной обработки к тензору изображения (ниже).

resizeNearestNeighbor: Использует алгоритм ближайшего соседа для сжатия пикселя изображения с холста (400 x 400) до 28 x 28. Помните, что это входной размер для нашей CNN.

mean: принимает среднее значение результата функции изменения размера и помогает преобразовать тензор в 2-мерный.

expandDims(2): Здесь мы расширяем последние два измерения тензора, чтобы преобразовать его в 3 измерения (28 X 28 x 1).

expandDims: используется для добавления дополнительного измерения к первой оси (ось партии). Это преобразует тензор в 4-мерный (1 x 28 x 28 x 1). Что приемлемо для нашей модели.

toFloat: преобразует все значения тензора в число с плавающей запятой.

И, наконец, мы делим тензоры на 255. Это помогает нормализовать отдельные элементы.

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

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

Прогноз возврата - это тензор вероятностей для каждого класса (1–10), поэтому для получения предсказанного класса мы просто получаем класс с наивысшей вероятностью, используя функцию argmax.

Наконец, мы обновляем элемент пользовательского интерфейса predval результатом прогноза.

Вот и все! Ваша заявка готова. А теперь давайте проверим.

Вернитесь в свой браузер и перезагрузите страницу. Вы должны увидеть, что модель загружена успешно. Начать рисовать!

Теперь нарисуйте число и нажмите кнопку «Прогноз». Вы должны увидеть прогноз модели справа от чертежа, как показано ниже:

Примечание. Ваша модель может быть не всегда правильной - это определенно приемлемо (и нормально). Вы всегда можете переобучить свою модель, попробовать разные архитектуры и т. Д. Есть множество руководств, которые научат вас, как улучшить ваши модели.







Хотя многие из них написаны на Python, вы можете легко перенести архитектуру на TensorFlow.js, поскольку он использует тот же API, что и Keras.

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

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

А пока оставайтесь в безопасности и продолжайте учиться!

Свяжитесь со мной в Твиттере.

Свяжитесь со мной в LinkedIn.

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

Являясь независимой редакцией, Heartbeat спонсируется и публикуется Comet, платформой MLOps, которая позволяет специалистам по данным и группам машинного обучения отслеживать, сравнивать, объяснять и оптимизировать свои эксперименты. Мы платим участникам и не продаем рекламу.

Если вы хотите внести свой вклад, отправляйтесь на наш призыв к участникам. Вы также можете подписаться на наши еженедельные информационные бюллетени (Deep Learning Weekly и Comet Newsletter), присоединиться к нам в » «Slack и подписаться на Comet в Twitter и LinkedIn для получения ресурсов, событий и гораздо больше, что поможет вам быстрее и лучше строить лучшие модели машинного обучения.