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

В основном преобразование таких вещей:

to

$\frac{977}{312}\lambda^3-580\neq 458$

который компилируется в:

$\frac{977}{312}\lambda³-580\neq 458$

Эта статья в блоге должна дать вам общее представление о том, как решить эту проблему, не давая современного решения.

Я использовал этот набор данных от Kaggle, чтобы получить рукописные математические символы.

В этом наборе данных 82 символа, но для этого проекта я использовал только следующие:

['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+', '=', 'leq', 'neq', 'geq', 'alpha', 'beta', 'lambda', 'lt', 'gt', 'x', 'y']

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

Вы можете найти скрипт, который я использовал для генерации изображений, на GitHub

Он производит только очень простые неравенства, одно с дробями и одно без них. Следующим шагом для меня было индивидуальное обучение подмножества символов с использованием CNN в тензорном потоке. Это очень похоже на их учебник по MNIST. Я добавил дополнительный слой свертки и объединения и использовал изображения размером 48x48 вместо 28x28, поскольку изображения в наборе данных имеют размер 45x45, но в CNN они должны делиться на $ 2,2²,2³ ,\dots$ в зависимости от количества имеющихся у вас слоев.

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

Что значит:

  • Я использовал ограничивающие рамки символов на основе моего генератора
  • Масштабировал/дополнял изображение до 40x40 (сохраняя соотношение сторон)
  • Увеличил до 48х48.
  • Центрирование с использованием центра масс

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

Для обучения я использовал среду GPU в Google Colab.

и этот фрагмент для загрузки изображений с GDrive.

Тренировка с использованием графического процессора Tesla K80 была очень быстрой, и я добился точности теста >99%.

Это, конечно, только первая часть этого проекта. Следующий — найти отдельные символы в написанном от руки уравнении. Моя первая идея заключается в том, что я использовал в своей статье двухлетней давности под названием скользящее окно. Это оказалось совершенно бесполезным, поскольку оно очень медленное и очень часто дает ложноположительные результаты. Я уверен, что еще два года назад подходы были бы лучше. В любом случае, я попробовал API обнаружения объектов от Tensorflow, который может находить объекты на изображениях реального мира. Звучало многообещающе, но оказалось, что я не смог заставить его работать в Google Colab и на моем компьютере с видеокартой AMD Firepro — не знаю, как сделать его пригодным для Tensorflow — поэтому без графического процессора заняло слишком много времени, и мне было трудно его отлаживать.

После нескольких прогулок и повышенного уровня стресса я подумал: это в основном черные чернила на белой бумаге, насколько это сложно? Очевидно, это проще, чем найти человека на каком-то странном (естественном) фоне. Иногда нейронные сети — это не совсем то, что нужно.

Поэтому я взглянул на OpenCV и нашел поиск ограничивающих рамок с помощью OpenCV.

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

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

Вот несколько моментов, касающихся этих ограничивающих рамок: обычно штрихи должны быть соединены, чтобы быть частью одной и той же ограничивающей рамки, что не относится к $\lambda$ здесь и не относится к $=,\leq,\ geq$. В последнем случае это не проблема, так как $=$ — это просто два знака минус друг над другом, а $› — поверх знака минус.

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

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

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

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

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

и/или послушайте это выступление:

Теперь я использовал свой сценарий генератора для создания последовательностей (ввода и вывода), что означает решить, какая информация необходима для создания кода LaTeX. Важно не только то, какие символы были обнаружены, но и положение этих символов и их порядок в последовательности. Мой подход заключался в том, чтобы прочитать уравнение сверху вниз слева направо, что, очевидно, не лучший выбор для дробей, но я хотел проверить, насколько хорошо оно на самом деле работает, поскольку модель должна его изучить. Затем я использовал абсолютную позицию в диапазоне от 0 до 1 символа, а также относительную позицию по отношению к символу, перед которым полезно для таких вещей, как степени, а также высоту и ширину символа (также нормализованные), которые разумно понять, что длинный знак «минус» на самом деле может быть штрихом дроби.

Это обучение было довольно быстрым на моем компьютере без видеокарты и дало относительно хорошие результаты.

Я использовал два измерения точности: первое — насколько последовательность верна, поэтому, если целевая последовательность: 1234$, а результат — 1324$, то это на 50% правильно, так как 1 и 4 верны. Другое измерение — это то, как часто вся последовательность оказывается правильной.

Прежняя точность составляет около 95%, что также связано с тем, что последовательность $1234$ на самом деле является $1234\quad$, поэтому в конце есть несколько дополнительных пробелов, которые обычно предсказываются правильно. Более строгая точность без пробелов составляет около 85%, а около 60% последовательностей полностью правильны, что само по себе можно разделить на две категории: точность без дробей составляет 80%, а с дробями - только 40%.

Если вас интересуют современные решения, я бы посоветовал прочитать эту статью:

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

Мой код снова доступен на GitHub.

Партнерская ссылка Амазон:

Первоначально опубликовано на http://opensourc.es/blog/he2latex.