Распознавание знаков – Репозиторий Самарского национального исследовательского университета имени академика С.П. Королёва: Недопустимый идентификатор

Содержание

Оптическое распознавание символов — Википедия

Оптическое распознавание символов (англ. optical character recognition, OCR) — механический или электронный перевод изображений рукописного, машинописного или печатного текста в текстовые данные, использующиеся для представления символов в компьютере (например, в текстовом редакторе). Распознавание широко применяется для преобразования книг и документов в электронный вид, для автоматизации систем учёта в бизнесе или для публикации текста на веб-странице. Оптическое распознавание символов позволяет редактировать текст, осуществлять поиск слов или фраз, хранить его в более компактной форме, демонстрировать или распечатывать материал, не теряя качества, анализировать информацию, а также применять к тексту электронный перевод, форматирование или преобразование в речь. Оптическое распознавание текста является исследуемой проблемой в областях распознавания образов, искусственного интеллекта и компьютерного зрения.

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

В 1929 году Густав Таушек (Gustav Tauschek) получил патент на метод оптического распознавания текста в Германии, после чего за ним последовал Гендель (Paul W. Handel), получив патент на свой метод в США в 1933. В 1935 году Таушек также получил патент США на свой метод. Машина Таушека представляла собой механическое устройство, которое использовало шаблоны и фотодетектор.

В 1950 году Дэвид Х. Шепард (David H. Shepard), криптоаналитик из агентства безопасности вооружённых сил Соединённых Штатов, проанализировав задачу преобразования печатных сообщений в машинный язык для обработки компьютером, построил машину, решающую данную задачу. После того как он получил патент США, он сообщил об этом в «Вашингтон Дэйли Ньюз» (27 апреля 1951) и в «Нью-Йорк Таймс» (26 декабря 1953). Затем Шепард основал компанию, разрабатывающую интеллектуальные машины, которая вскоре выпустила первые в мире коммерческие системы оптического распознавания символов.

Первая коммерческая система была установлена на «Ридерс Дайджест» в 1955 году. Вторая система была продана компании «Стандарт Ойл» для чтения кредитных карт для работы с чеками. Другие системы, поставляемые компанией Шепарда, были проданы в конце 1950-х годов, в том числе сканер страниц для национальных воздушных сил США, предназначенный для чтения и передачи по телетайпу машинописных сообщений. IBM позже получила лицензию на использование патентов Шепарда.

Примерно в 1965 году «Ридерс Дайджест» и «Ар-Си-Эй» начали сотрудничество с целью создать машину для чтения документов, использующую оптическое распознавание текста, предназначенную для оцифровки серийных номеров купонов «Ридерс Дайджест», вернувшихся из рекламных объявлений. Для печати на документах барабанным принтером «Ар-Си-Эй» был использован специальный шрифт OCR-A. Машина для чтения документов работала непосредственно с компьютером RCA 301 (одна из первых полупроводниковых ЭВМ). Скорость работы машины была 1500 документов в минуту: она проверяла каждый документ, исключая те, которые она не смогла обработать правильно.

Почтовая служба Соединённых Штатов с 1965 года для сортировки почты использует машины, работающие по принципу оптического распознавания текста, созданные на основе технологий, разработанных исследователем Яковом Рабиновым. В Европе первой организацией, использующей машины с оптическим распознаванием текста, был британский почтамт. Почта Канады использует системы оптического распознавания символов с 1971 года. На первом этапе в центре сортировки системы оптического распознавания символов считывают имя и адрес получателя и печатают на конверте штрихкод. Он наносится специальными чернилами, которые отчётливо видимы в ультрафиолетовом свете. Это делается, чтобы избежать путаницы с полем адреса, заполненным человеком, которое может быть в любом месте на конверте.

В 1974 году Рэй Курцвейл создал компанию «Курцвейл Компьютер Продактс», и начал работать над развитием первой системы оптического распознавания символов, способной распознать текст, напечатанный любым шрифтом. Курцвейл считал, что лучшее применение этой технологии — создание машины чтения для слепых, которая позволила бы слепым людям иметь компьютер, умеющий читать текст вслух. Данное устройство требовало изобретения сразу двух технологий — ПЗС планшетного сканера и синтезатора, преобразующего текст в речь. Конечный продукт был представлен 13 января 1976 во время пресс-конференции, возглавляемой Курцвейлом и руководителями национальной федерации слепых.

В 1978 году компания «Курцвейл Компьютер Продактс» начала продажи коммерческой версии компьютерной программы оптического распознавания символов. Два года спустя Курцвейл продал свою компанию корпорации «Ксерокс», которая была заинтересована в дальнейшей коммерциализации систем распознавания текста. «Курцвейл Компьютер Продактс» стала дочерней компанией «Ксерокс», известной как «Скансофт».

Первой коммерчески успешной программой, распознающей кириллицу, была программа «AutoR» российской компании «ОКРУС». Программа начала распространяться в 1992 году, работала под управлением операционной системы DOS и обеспечивала приемлемое по скорости и качеству распознавание даже на персональных компьютерах IBM PC/XT с процессором Intel 8088 при тактовой частоте 4,77 МГц. В начале 90-х компания Hewlett-Packard поставляла свои сканеры на российский рынок в комплекте с программой «AutoR». Алгоритм «AutoR» был компактный, быстрый и в полной мере «интеллектуальный», то есть по-настоящему шрифтонезависимый. Этот алгоритм разработали и испытали ещё в конце 60-х два молодых биофизика, выпускники МФТИ — Г. М. Зенкин и А. П. Петров. Свой метод распознавания они опубликовали в журнале «Биофизика» в номере 12, вып. 3 за 1967 год. В настоящее время алгоритм Зенкина-Петрова применяется в нескольких прикладных системах, решающих задачу распознавания графических символов. На основе алгоритма компанией Paragon Software Group в 1996 была создана технология PenReader. Г.М Зенкин продолжил работу над технологией PenReader в компании Paragon Software Group

[1]. Технология используется в одноимённом продукте компании[2].

В 1993 году вышла технология распознавания текстов российской компании ABBYY. На её основе создан ряд корпоративных решений и программ для массовых пользователей. В частности, программа для распознавания текстов ABBYY FineReader, приложения для распознавания текстовой информации с мобильных устройств, система потокового ввода документов и данных ABBYY FlexiCapture. Технологии распознавания текстов ABBYY OCR лицензируют международные ИТ-компании, такие как Fujitsu, Panasonic, Xerox, Samsung

[3], EMC и другие.

Текущее состояние технологии оптического распознавания текста[править | править код]

Точное распознавание латинских символов в печатном тексте в настоящее время возможно, только если доступны чёткие изображения, такие, как сканированные печатные документы. Точность при такой постановке задачи превышает 99 %, абсолютная точность может быть достигнута только путём последующего редактирования человеком. Проблемы распознавания рукописного «печатного» и стандартного рукописного текста, а также печатных текстов других форматов (особенно с очень большим числом символов) в настоящее время являются предметом активных исследований.

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

Распознавание символов онлайн иногда путают с оптическим распознаванием символов. Последний — это офлайн-метод, работающий со статической формой представления текста, в то время как онлайн-распознавание символов учитывает движения во время письма. Например, в онлайн-распознавании, использующем PenPoint OS или планшетный ПК, можно определить, с какой стороны пишется строка: справа налево или слева направо.

Онлайн-системы для распознавания рукописного текста «на лету» в последнее время стали широко известны в качестве коммерческих продуктов. Алгоритмы таких устройств используют тот факт, что порядок, скорость и направление отдельных участков линий ввода известны. Кроме того, пользователь научится использовать только конкретные формы письма. Эти методы не могут быть использованы в программном обеспечении, которое использует сканированные бумажные документы, поэтому проблема распознавания рукописного «печатного» текста по-прежнему остаётся открытой. На изображениях с рукописным «печатным» текстом без артефактов может быть достигнута точность в 80 % — 90 %, но с такой точностью изображение будет преобразовано с десятками ошибок на странице. Такая технология может быть полезна лишь в очень ограниченном числе приложений.

Ещё одной широко исследуемой задачей является распознавание рукописного текста. В данное время достигнутая точность даже ниже, чем для рукописного «печатного» текста. Более высокие показатели могут быть достигнуты только с использованием контекстной и грамматической информации. Например, в ходе распознания искать целые слова в словаре легче, чем пытаться выявить отдельные знаки из текста. Знание грамматики языка может также помочь определить, является ли слово глаголом или существительным. Формы отдельных рукописных символов иногда могут не содержать достаточно информации, чтобы точно (более 98 %) распознать весь рукописный текст.

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

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

Инструменты для препроцессинга изображений / New Professions Lab corporate blog / Habr

Привет, Хабр! Продолжаем серию материалов от выпускника нашей программы Deep Learning, Кирилла Данилюка, об использовании сверточных нейронных сетей для распознавания образов — CNN (Convolutional Neural Networks)

Введение


За последние несколько лет сфера компьютерного зрения (CV) переживает если не второе рождение, то огромный всплеск интереса к себе. Во многом такой рост популярности связан с эволюцией нейросетевых технологий. Например, сверточные нейронные сети (convolutional neural networks или CNN) отобрали себе большой кусок задач по генерации фич, ранее решаемых классическими методиками CV: HOG, SIFT, RANSAC и т.д.

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


MultiNet как пример нейронной сети (трех в одной), которую мы будем использовать в одном из следующих постов. Источник.

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

  • Chapter 6: Deep Feedforward Networks — глава из книги Deep Learning от I.Goodfellow, Y.Bengio и A.Courville. Очень рекомендую.
  • CS231n Convolutional Neural Networks for Visual Recognition  — популярный курс от Fei-Fei Li и Andrej Karpathy из Стэнфорда. В курсе содержатся отличные материалы сделан упор на практику и проектирование.
  • Deep Learning  — курс от Nando de Freitas из Оксфорда.
  • Intro to Machine Learning  — бесплатный курс от Udacity для новичков с доступным изложением материала, затрагивает большое количество тем в машинном обучении.

Совет: чтобы убедиться в том, что вы владеете основами нейронных сетей, напишите свою сеть с нуля и поиграйте с ней!

Вместо того, чтобы повторять основы, данная серия статей фокусируется на нескольких конкретных архитектурах нейронных сетей: STN (spatial transformer network), IDSIA (сверточная нейросеть для классификации дорожных знаков), нейросеть от NVIDIA для end-to-end разработки автопилота и MultiNet для распознавания и классификации дорожной разметки и знаков. Приступим!

Тема данной статьи — показать несколько инструментов для предобработки изображений. Общий пайплайн обычно зависит от конкретной задачи, я же хотел бы остановиться именно на инструментах. Нейросети — совсем не те магические черные ящики, какими их любят преподносить в медиа: нельзя просто взять и «закинуть» данных в сетку и ждать волшебных результатов. По правилу shit in — shit out в лучшем случае, вы получите score хуже на несколько пунктов. А, скорее всего, просто не сможете обучить сеть и никакие модные техники типа нормализации батчей или dropout вам не помогут. Таким образом, работу нужно начинать именно с данных: их чистки, нормализации и нормировки. Дополнительно стоит задуматься над расширением (data augmentation) исходного картиночного датасета с помощью аффинных преобразований типа вращения, сдвигов, изменения масштаба картинок: это поможет снизить вероятность переобучения и обеспечит лучшую инвариантность классификатора к трансформациям.

Инструмент 1: Визуализация и разведочный анализ данных


В рамках этого и следующего постов мы будем использовать GTSRB  —  датасет по распознаванию дорожных знаков в Германии. Наша задача — обучить классификатор дорожных знаков, используя размеченные данные из GTSRB. В общем случае, лучший способ получить представление об имеющихся данных — построить гистограмму распределения train, validation и/или test наборов данных:

Базовая информация о нашем датасете:

Number of training examples = 34799
Number of validation examples = 4410
Number of testing examples = 12630
Image data shape = (32, 32, 3)
Number of classes = 43

На данном этапе matplotlib — ваш лучший друг. Несмотря на то, что используя лишь pyplot можно отлично визуализировать данные, matplotlib.gridspec позволяет слить 3 графика воедино:
gs = gridspec.GridSpec(1, 3, wspace=0.25, hspace=0.1)
fig = plt.figure(figsize=(12,2))
ax1, ax2, ax3 = [plt.subplot(gs[:, i]) for i in range(3)]

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


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

  • Визуализация изображений. По графику сразу видно множество слишком темных или слишком светлых изображений, поэтому должна быть проведена своего рода нормализация данных, чтобы устранить вариацию яркости.
  • Проверка выборки на несбалансированность. В случае, если в выборке превалируют экземпляры какого-либо класса, необходимо использовать методы undersampling или oversampling.
  • Проверить, что распределения train, validation и test выборок похожи. Это можно проверить, взглянув на гистограммы выше, либо используя ранговый коэффициент корреляции Спирмена. (через scipy)

Инструмент 2: IPython Parallel для scikit-image


Для того, чтобы улучшить сходимость нейронной сети, нужно привести все изображения к единому освещению путем (как рекомендовано в статье LeCun о распознавании дорожных знаков) преобразования их цветовой гаммы в градации серого. Это можно сделать как с помощью OpenCV, так и с помощью отличной библиотеки на Python scikit-image, которая может быть легко установлена с помощью pip (OpenCV же требует самостоятельной компиляции с кучей зависимостей). Нормализация контрастности изображений будет осуществляться с помощью адаптивной нормализации гистограммы (CLAHE, contrast limited adaptive histogram equalization):
skimage.exposure.equalize_adapthist.

Отмечу, что skimage обрабатывает изображения одно за другим, используя лишь одно ядро процессора, что, очевидно, неэффективно. Чтобы распараллелить предобработку изображений, используем библиотеку IPython Parallel (ipyparallel). Одно из преимуществ этой библиотеки — простота: реализовать распараллеленный CLAHE можно всего несколькими строчками кода. Сначала в консоли (с установленной ipyparallel) запустим локальный кластер ipyparallel:

$ ipcluster start

Наш подход к распараллеливанию очень прост: мы разделяем выборку на батчи и обрабатываем каждую партию независимо от остальных. Как только все батчи будут обработаны, мы сливаем их обратно в один набор данных. Моя реализация CLAHE приведена ниже:

from skimage import exposure

def grayscale_exposure_equalize(batch_x_y):
    """Processes a batch with images by grayscaling, normalization and
    histogram equalization.
    
    Args:
        batch_x_y: a single batch of data containing a numpy array of images
            and a list of corresponding labels.
    
    Returns:
        Numpy array of processed images and a list of labels (unchanged).
    """
    x_sub, y_sub = batch_x_y[0], batch_x_y[1]
    x_processed_sub = numpy.zeros(x_sub.shape[:-1])
    for x in range(len(x_sub)):
        # Grayscale
        img_gray = numpy.dot(x_sub[x][...,:3], [0.299, 0.587, 0.114])
        # Normalization
        img_gray_norm = img_gray / (img_gray.max() + 1)
        # CLAHE. num_bins will be initialized in ipyparallel client
        img_gray_norm = exposure.equalize_adapthist(img_gray_norm, nbins=num_bins)
        
        x_processed_sub[x,...] = img_gray_norm
    return (x_processed_sub, y_sub)

Теперь, когда сама трансформация готова, напишем код, который применяет ее к каждому батчу из обучающей выборки:
import multiprocessing
import ipyparallel as ipp
import numpy as np

def preprocess_equalize(X, y, bins=256, cpu=multiprocessing.cpu_count()):
    """ A simplified version of a function which manages multiprocessing logic. 
    This function always grayscales input images, though it can be generalized
    to apply any arbitrary function to batches.
    Args:
        X: numpy array of all images in dataset.
        y: a list of corresponding labels.
        bins: the amount of bins to be used in histogram equalization.
        cpu: the number of cpu cores to use. Default: use all.
    Returns:
        Numpy array of processed images and a list of labels.
    """
    rc = ipp.Client()

    # Use a DirectView object to broadcast imports to all engines
    with rc[:].sync_imports():
        import numpy
        from skimage import exposure, transform, color        

    # Use a DirectView object to set up the amount of bins on all engines
    rc[:]['num_bins'] = bins

    X_processed = np.zeros(X.shape[:-1])    
    y_processed = np.zeros(y.shape)

    # Number of batches is equal to cpu count
    batches_x = np.array_split(X, cpu)
    batches_y = np.array_split(y, cpu)
    batches_x_y = zip(batches_x, batches_y)

    # Applying our function of choice to each batch with a DirectView method
    preprocessed_subs = rc[:].map(grayscale_exposure_equalize, batches_x_y).get_dict()

    # Combining the output batches into a single dataset
    cnt = 0
    for _,v in preprocessed_subs.items():
        x_, y_ = v[0], v[1]
        X_processed[cnt:cnt+len(x_)] = x_
        y_processed[cnt:cnt+len(y_)] = y_
        cnt += len(x_)
    
    return X_processed.reshape(X_processed.shape + (1,)), y_processed

Наконец, применим написанную функцию к обучающей выборке:
# X_train: numpy array of (34799, 32, 32, 3) shape
# y_train: a list of (34799,) shape
X_tr, y_tr = preprocess_equalize(X_train, y_train, bins=128)

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


Результат нормализации изображений и переноса их цветовой гаммы в градации серого


Нормализация распределения для изображений формата RGB (я использовал другую функцию для rc[:].map)

Теперь весь процесс предобработки данных проходит за несколько десятков секунд, поэтому мы можем протестировать разные значения числа интервалов num_bins, чтобы визуализировать их и выбрать наиболее подходящий:


num_bins: 8, 32, 128, 256, 512

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

Наконец, используем ipython magic %store, чтобы сохранить результаты для дальнейшего использования:

# Same images, multiple bins (contrast augmentation)
%store X_tr_8
%store y_tr_8
# ...
%store X_tr_512
%store y_tr_512

Инструмент 3: Онлайн-аугментация данных


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

Для начала обозначим все планируемые преобразования, используя numpy и skimage:

import numpy as np
from skimage import transform
from skimage.transform import warp, AffineTransform

def rotate_90_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 270.0)
    return X_aug

def rotate_180_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 180.0)
    return X_aug

def rotate_270_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 90.0)
    return X_aug

def rotate_up_to_20_deg(X):
    X_aug = np.zeros_like(X)
    delta = 20.
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, random.uniform(-delta, delta), mode='edge')
    return X_aug

def flip_vert(X):
    X_aug = deepcopy(X)
    return X_aug[:, :, ::-1, :]

def flip_horiz(X):
    X_aug = deepcopy(X)
    return X_aug[:, ::-1, :, :]

def affine_transform(X, shear_angle=0.0, scale_margins=[0.8, 1.5], p=1.0):
    """This function allows applying shear and scale transformations
    with the specified magnitude and probability p.
    
    Args:
        X: numpy array of images.
        shear_angle: maximum shear angle in counter-clockwise direction as radians.
        scale_margins: minimum and maximum margins to be used in scaling.
        p: a fraction of images to be augmented.
    """
    X_aug = deepcopy(X)
    shear = shear_angle * np.random.rand()
    for i in np.random.choice(len(X_aug), int(len(X_aug) * p), replace=False):
        _scale = random.uniform(scale_margins[0], scale_margins[1])
        X_aug[i] = warp(X_aug[i], AffineTransform(scale=(_scale, _scale), shear=shear), mode='edge')
    return X_aug

Масштабирование и рандомные повороты rotate_up_to_20_deg увеличивают размер выборки, сохраняя принадлежность изображений к исходным классам. Отражения (flips) и вращения на 90, 180, 270 градусов могут, напротив, поменять смысл знака. Чтобы отслеживать такие переходы, создадим список возможных преобразований для каждого дорожного знака и классов, в которые они будут преобразованы (ниже приведен пример части такого списка):
label_class label_name rotate_90_deg rotate_180_deg rotate_270_deg flip_horiz flip_vert
13 Yield 13
14 Stop
15 No vehicles 15 15 15 15 15
16 Vehicles over
3.5 ton
prohibited
17 No entry 17 17 17
Часть таблицы преобразований. Значения в ячейках показывают номер класса, который примет данное изображение после трансформации. Пустые ячейки означают, что данное преобразование недоступно для этого класса.

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

import pandas as pd

# Generate an augmented dataset using a transform table
augmentation_table = pd.read_csv('augmentation_table.csv', index_col='label_class')

augmentation_table.drop('label_name', axis=1, inplace=True)
augmentation_table.dropna(axis=0, how='all', inplace=True)

# Collect all global functions in global namespace
namespace = __import__(__name__)

def apply_augmentation(X, how=None):
    """Apply an augmentation function specified in `how` (string) to a numpy array X.
    
    Args:
        X: numpy array with images.
        how: a string with a function name to be applied to X, should return 
            the same-shaped numpy array as in X.
    
    Returns:
        Augmented X dataset.
    """
    assert augmentation_table.get(how) is not None
    
    augmentator = getattr(namespace, how)
    return augmentator(X)

Теперь мы можем построить пайплайн, который применяет все доступные функции (преобразования), перечисленные в augmentation_table.csv ко всем классам:
import numpy as np

def flips_rotations_augmentation(X, y):
    """A pipeline for applying augmentation functions listed in `augmentation_table`
    to a numpy array with images X.
    """
    # Initializing empty arrays to accumulate intermediate results of augmentation
    X_out, y_out = np.empty([0] + list(X.shape[1:]), dtype=np.float32), np.empty([0])
    
    # Cycling through all label classes and applying all available transformations
    for in_label in augmentation_table.index.values:
        available_augmentations = dict(augmentation_table.ix[in_label].dropna(axis=0))
        images = X[y==in_label]

        # Augment images and their labels
        for kind, out_label in available_augmentations.items():
            X_out = np.vstack([X_out, apply_augmentation(images, how=kind)])
            y_out = np.hstack([y_out, [out_label] * len(images)])

    # And stack with initial dataset
    X_out = np.vstack([X_out, X])
    y_out = np.hstack([y_out, y])
    
    # Random rotation is explicitly included in this function's body
    X_out_rotated = rotate_up_to_20_deg(X)
    y_out_rotated = deepcopy(y)

    X_out = np.vstack([X_out, X_out_rotated])
    y_out = np.hstack([y_out, y_out_rotated])

    return X_out, y_out

Отлично! Теперь у нас есть 2 готовые функции аугментации данных:
  • affine_transform: кастомизируемые аффинные преобразования без вращения (название я выбрал не очень удачное, потому что, что вращение является одним из аффинных преобразований).
  • flips_rotations_augmentation: случайные вращения и преобразования на основе augmentation_table.csv, меняющие классы изображений.

Финальный шаг — это создать генератор батчей:
def augmented_batch_generator(X, y, batch_size, rotations=True, affine=True,
                              shear_angle=0.0, scale_margins=[0.8, 1.5], p=0.35):
    """Augmented batch generator. Splits the dataset into batches and augments each
    batch independently.
    
    Args:
        X: numpy array with images.
        y: list of labels.
        batch_size: the size of the output batch.
        rotations: whether to apply `flips_rotations_augmentation` function to dataset.
        affine: whether to apply `affine_transform` function to dataset.
        shear_angle: `shear_angle` argument for `affine_transform` function.
        scale_margins: `scale_margins` argument for `affine_transform` function.
        p: `p` argument for `affine_transform` function.
    """
    X_aug, y_aug = shuffle(X, y)
    
    # Batch generation
    for offset in range(0, X_aug.shape[0], batch_size):
        end = offset + batch_size
        batch_x, batch_y = X_aug[offset:end,...], y_aug[offset:end]
        
        # Batch augmentation
        if affine is True:
            batch_x = affine_transform(batch_x, shear_angle=shear_angle, scale_margins=scale_margins, p=p)
        if rotations is True:
            batch_x, batch_y = flips_rotations_augmentation(batch_x, batch_y)
        
        yield batch_x, batch_y

Объединив датасеты с разным числом num_bins в CLAHE в один большой train, подадим его в полученный генератор. Теперь у нас есть два вида аугментации: по контрастности и с помощью аффинных трансформаций, которые применяются к батчу на лету:


Сгенерированные с помощью augmented_batch_generator изображения

Замечание: аугментация нужна для train-сета. Test-сет мы тоже предобрабатываем, но не аугментируем.

Давайте проверим, что мы нечаянно не нарушили распределение классов на расширенном трейне по сравнению с исходным датасетом:


Слева: гистограмма распределения данных из augmented batch generator. Справа: изначальный train. Как видно, значения различаются, но распределения схожи.

Переход к нейронным сетям


После того, как выполнена предобработка данных, все генераторы готовы и датасет готов к анализу, мы можем перейти к обучению. Мы будем использовать двойную свёрточную нейронную сеть: STN (spatial transformer network) принимает на вход предобработанные батчи изображений из генератора и фокусируется на дорожных знаках, а IDSIA нейросеть распознает дорожный знак на изображениях, полученных от STN. Следующий пост будет посвящён этим нейросетям, их обучению, анализу качества и демо-версии их работы. Следите за новыми постами!


Слева: исходное предобработанное изображение. Справа: преобразованное STN изображение, которое принимает на вход IDSIA для классификации.

Оптическое распознавание знаков Википедия

Оптическое распознавание символов (англ. optical character recognition, OCR) — механический или электронный перевод изображений рукописного, машинописного или печатного текста в текстовые данные, использующиеся для представления символов в компьютере (например, в текстовом редакторе). Распознавание широко применяется для преобразования книг и документов в электронный вид, для автоматизации систем учёта в бизнесе или для публикации текста на веб-странице. Оптическое распознавание символов позволяет редактировать текст, осуществлять поиск слов или фраз, хранить его в более компактной форме, демонстрировать или распечатывать материал, не теряя качества, анализировать информацию, а также применять к тексту электронный перевод, форматирование или преобразование в речь. Оптическое распознавание текста является исследуемой проблемой в областях распознавания образов, искусственного интеллекта и компьютерного зрения.

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

История[ | ]

В 1929 году Густав Таушек (Gustav Tauschek) получил патент на метод оптического распознавания текста в Германии, после чего за ним последовал Гендель (Paul W. Handel), получив патент на свой метод в США в 1933. В 1935 году Таушек также получил патент США на свой метод. Машина Таушека представляла собой механическое устройство, которое использовало шаблоны и фотодетектор.

В 1950 году Дэвид Х. Шепард (David H. Shepard), криптоаналитик из агентства безопасности вооружённых сил Соединённых Штатов, проанализировав задачу преобразования печатных сообщений в машинный язык для обработки компьютером, построил машину, решающую данную задачу. После того как он получил патент США, он сообщил об этом в «Вашингтон Дэйли Ньюз» (27 апреля 1951) и в «Нью-Йорк Таймс» (26 декабря 1953). Затем Шепард основал компанию, разрабатывающую интеллектуальные машины, которая вскоре выпустила первые в мире коммерческие системы оптического распознавания символов.

Первая коммерческая система была установлена на «Ридерс Дайджест» в 1955 году. Вторая система была продана компании «Стандарт Ойл» для чтения кредитных карт для работы с чеками. Другие системы, поставляемые компанией Шепарда, были проданы в конце 1950-х годов, в том числе сканер страниц для национальных воздушных сил США, предназначенный для чтения и передачи по телетайпу машинописных сообщений. IBM позже получила лицензию на использование патентов Шепарда.

Примерно в 1965 году «Ридерс Дайджест» и «Ар-Си-Эй» начали сотрудничество с целью создать машину для чтения документов, использующую оптическое распознавание текста, предназначенную для оцифровки серийных номеров купонов «Ридерс Дайджест», вернувшихся из рекламных объявлений. Для печати на документах барабанным принтером «Ар-Си-Эй» был использован специальный шрифт OCR-A. Машина для чтения документов работала непосредственно с компьютером RCA 301 (одна из первых полупроводниковых ЭВМ). Скорость работы машины была 1500 документов в минуту: она проверяла каждый документ, исключая те, которые она не смогла обработать правильно.

Почтовая служба Соединённых Штатов с 1965 года для сортировки почты использует машины, работающие по принципу оптического распознавания текста, созданные на основе технологий, разработанных исследователем Яковом Рабиновым. В Европе первой организацией, использующей машины с оптическим распознаванием текста, был британский почтамт. Почта Канады использует систем

Spatial Transformer Networks / New Professions Lab corporate blog / Habr

Привет, Хабр! Продолжаем серию материалов от выпускника нашей программы Deep Learning, Кирилла Данилюка, об использовании сверточных нейронных сетей для распознавания образов — CNN (Convolutional Neural Networks).

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

Spatial Transformer Network (STN) — один из примеров дифференцируемых LEGO-модулей, на основе которых можно строить и улучшать свою нейросеть. STN, применяя обучаемое аффинное преобразование с последующей интерполяцией, лишает изображения пространственной инвариантности. Грубо говоря, задача STN состоит в том, чтобы так повернуть или уменьшить-увеличить исходное изображение, чтобы основная сеть-классификатор смогла проще определить нужный объект. Блок STN может быть помещен в сверточную нейронную сеть (CNN), работая в ней по большей части самостоятельно, обучаясь на градиентах, приходящих от основной сети.

Весь исходный код проекта доступен на GitHub по ссылке. Оригинал этой статьи можно посмотреть на Medium.

Чтобы иметь базовое представление о работе STN, взгляните на 2 примера ниже:

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

Еще один пример обучения STN и преобразования изображений. Это первая эпоха и первые десятки батчей, использованных для обучения. Видно, как STN распознает очертания знака, чтобы затем сконцентрироваться на нем самом.

STN работает даже в сложных случаях (например, 2 знака на изображении), но самое главное — STN действительно улучшает качество классификатора (IDSIA в моем случае).

Общее устройство STN: курс молодого бойца


Одна из проблем сверточных нейронных сетей — слишком низкая инвариантность к входным данным: разный масштаб, точка съемки, шум на заднем плане и многое другое. Можно, конечно, сказать, что операция пулинга, так не любимая Хинтоном, дает некоторую инвариантность, но фактически она просто уменьшает размер feature map, что выливается в потерю информации.

К сожалению, из-за маленького рецептивного поля в стандартном 2х2 пулинге пространственная инвариантность может быть достигнута лишь в глубоких слоях, близких к output-слою. Также пулинг не обеспечивает инвариантность вращения и масштаба. Кевин Закка хорошо объяснил причину этого в своем посте.

Основной и самый распространенный способ сделать модель устойчивой к этим вариациям — аугментация датасета, что мы и сделали в предыдущей статье:


Аугментированные изображения. В этом посте мы не будем использовать аугментацию.

В таком подходе нет ничего плохого, но нам бы хотелось разработать более умный и автоматизированный метод предобработки изображений, который должен способствовать увеличению точности классификатора. Spatial transformer network (STN) — как раз то, что нам нужно.

Ниже еще один пример работы STN:


Пример из датасета MNIST из статьи-первоисточника. Cluttered MNIST (слева), целевой объект, распознанный STN (центр), преобразованное изображение (справа).

Работа STN модуля может быть сведена к следующему процессу (не включая обучение):


Применение STN преобразования в 4 шага при известной матрице линейных преобразований θ.

Теперь рассмотрим подробнее этот процесс и каждый его этап.

STN: этапы преобразования


Шаг 1. Определить матрицу преобразований θ, которая описывает саму трансформацию:


Аффинное преобразование матрицы θ.

При этом каждому преобразованию соответствует своя матрица. Нас интересуют следующие 4:

  • Тождественное преобразование(на выходе то же самое изображение). Это наши исходные значения θ. В данном случае, матрица θ диагональная:
    theta = np.array([[1.0, 0, 0], [0, 1.0, 0]])
  • Вращение (против часовой стрелки, 45º). cos(45º) = 1/sqrt(2) ≈ 0.7:
    theta = np.array([[0.7, -0.7, 0], [0.7, 0.7, 0]])
  • Приближение. Приближение к центру (в 2 раза):
    theta = np.array([[0.5, 0, 0], [0, 0.5, 0]])
  • Отдаление. Отдаление от центра (в 2 раза):
    theta = np.array([[2.0, 0, 0], [0, 2.0, 0]])

Шаг 2. Вместо того, чтобы применять преобразование напрямую к исходному изображению (U), создадим выборочную сетку (sampling meshgrid) того же размера, что и U. Выборочная сетка — это набор индексов (x_t, y_t), которые покрывают исходное пространство изображений. Сетка не содержит в себе никакой информации о цвете изображений. Лучше это объясняется в коде ниже:
# Implemented in https://github.com/tensorflow/models/blob/master/transformer/spatial_transformer.py

# As I mentioned, we only need height and width of the original image
def _meshgrid(height, width):
	with tf.variable_scope('_meshgrid'):
    	x_t = tf.matmul(tf.ones(shape=tf.stack([height, 1])),
                    	tf.transpose(tf.expand_dims(tf.linspace(-1.0, 1.0, width), 1), [1, 0]))
    	y_t = tf.matmul(tf.expand_dims(tf.linspace(-1.0, 1.0, height), 1),
                    	tf.ones(shape=tf.stack([1, width])))

    	x_t_flat = tf.reshape(x_t, (1, -1))
    	y_t_flat = tf.reshape(y_t, (1, -1))

    	ones = tf.ones_like(x_t_flat)
    	grid = tf.concat(axis=0, values=[x_t_flat, y_t_flat, ones])
return grid

Поскольку это фактическая имплементация в TensorFlow, чтобы понять общую идею, переведем этот код в аналог на numpy:
x_t, y_t = np.meshgrid(np.linspace(-1, 1, width), np.linspace(-1, 1, height))

Шаг 3. Применить матрицу линейных преобразований к созданной выборочной сетке, чтобы получить новый набор точек на сетке, каждая из которых может быть определена как результат умножения матрицы θ на вектор координат (x_t, y_t) со свободным членом:

Шаг 4. Получить подвыборку V, используя исходную карту признаков, преобразованную выборочную сетку (см. Шаг 3) и дифференцируемую функцию интерполяции на ваш выбор (например, билинейная). Интерполяция необходима, так как нам нужно перевести результат сэмплинга (потенциально возможные дробные значения пикселей) в целые числа.


Сэмплинг и интерполяция

Задача обучения. Говоря в общем, если бы мы заранее знали нужные нам значения θ для каждого исходного изображения, можно было бы начинать описанный выше процесс. На деле же, нам бы хотелось извлекать θ из данных с помощью машинного обучения. Это сделать вполне реально. Во-первых, нам нужно убедиться, что функция потерь классификатора дорожных знаков может быть минимизирована с помощью backprop через сэмплер. Во-вторых, мы находим градиенты по U и G (meshgrid): именно поэтому функция интерполяции должна быть дифференцируема или, хотя бы, частично дифференцируема. В-третьих, рассчитываем частные производные x и y по θ. Технические выкладки можно прочитать в исходной пейпе.

Наконец, мы создаем LocNet (локализующая сеть-регрессор), единственной задачей которой будет обучиться и спрогнозировать корректные θ для принимаемого на вход изображения, используя функцию потерь, которая была минимизирована через общий backprop.

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


Заметьте, как меняется θ, пока STN обучается распознавать целевой объект (дорожный знак) на изображениях.

Ниже представлена схема работы STN из оригинальной статьи:


Мы рассмотрели все этапы построения STN: создание LocNet, генератора выборочной сетки (meshgrid) и сэмплера. Теперь построим и обучим на TensorFlow весь классификатор, который включает в свой граф и STN.

Построение модели в TensorFlow


Весь код модели, конечно, не уместится в рамки одной статьи, но он доступен в виде Jupyter-ноутбука в репозитории на GitHub.

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

Во-первых, наша конечная цель — научиться распознавать дорожные знаки, и для ее достижения нам нужно создать какой-то классификатор и обучить его. Вариантов у нас много: от LeNet и до любой другой SOTA-нейросети. В процессе работы над проектом, вдохновившись работой Moodstocks по STN (реализованной в Torch), я использовал архитектуру нейронной сети IDSIA, хотя ничто не мешало взять что-то другое.

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


STN преобразует исходные изображения и подает их на вход IDSIA, которая обучается с помощью backprop и затем классифицирует дорожные знаки.

Ниже приведена часть DAG, в рамках которого исходные изображения преобразуются с помощью STN и подаются на вход классификатору (IDSIA), который рассчитывает логиты:

def stn_idsia_inference_type2(batch_x):
	with tf.name_scope('stn_network_t2'):
    	# Unrolling the STN's LocNet -- stn_output is theta-matrix
    	stn_output = stn_LocNet_type2(stn_convolve_pool_flatten_type2(batch_x))
   	 
    	# Grid generator and sampler
    	transformed_batch_x = transformer(batch_x, stn_output, (32,32, TF_CONFIG['channels']))

	with tf.name_scope('idsia_classifier'):
    	# IDSIA uses transformed_batch_x from STN. Here we unroll the conv layers of IDSIA
    	features, batch_act = idsia_convolve_pool_flatten(transformed_batch_x, multiscale=True)
   	 
    	# Unrolling FC layers of IDSIA
    	logits = idsia_fc_logits(features, multiscale=True)
    
	# Returning lots of objects. `logits` is the one that is really required for the model
return logits, transformed_batch_x, batch_act

Теперь, когда мы знаем метод расчета логитов (STN + IDSIA network), следующим шагом будет оптимизация функции потерь ( в качестве которой мы будем использовать кросс-энтропию или log loss — стандартный выбор для решения задачи классификации):
def calculate_loss(logits, one_hot_y):
	with tf.name_scope('Predictions'):
    	predictions = tf.nn.softmax(logits)
	with tf.name_scope('Model'):
    	cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=one_hot_y)
	with tf.name_scope('Loss'):
    	loss_operation = tf.reduce_mean(cross_entropy)
return loss_operation

Затем нам нужно задать операции (ops) оптимизации и обучения, которые должны распространять ошибки обратно к входным слоям:
boundaries = [100, 250, 500, 1000, 8000]
values = [0.02, 0.01, 0.005, 0.003, 0.001, 0.0001]

starter_learning_rate = 0.02
global_step = tf.Variable(0, trainable=False)

learning_rate = tf.train.piecewise_constant(global_step, boundaries, values)

with tf.name_scope('accuracy'):
	accuracy_operation = tf.reduce_mean(casted_corr_pred)

with tf.name_scope('loss_calculation'):
	loss_operation = calculate_loss(logits, one_hot_y)

with tf.name_scope('adam_optimizer'):
	optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)

with tf.name_scope('training_backprop_operation'):
training_operation = optimizer.minimize(loss_operation, global_step=global_step)

Я инициализировал сеть с большим значением learning rate (0.02), чтобы градиенты могли быстрее распространять информацию к LocNet STN, которая расположена во внешних слоях всей нейронной сети. В противном случае эта сеть будет обучаться медленнее (из-за проблемы «исчезающего» градиента). Маленькие исходные значения learning rate не позволяют нейросети хорошо приближать мелкие дорожные знаки на изображении.

Часть DAG, которая рассчитывает логиты (выход сети) добавляется в граф довольно просто:

with tf.name_scope('batch_data'):
	x = tf.placeholder(tf.float32, (None, 32, 32, TF_CONFIG['channels']), name="InputData")
	y = tf.placeholder(tf.int32, (None), name="InputLabels")
	one_hot_y = tf.one_hot(y, n_classes, name='InputLabelsOneHot')

#### INIT
with tf.name_scope('logits_and_stn_output'):
logits, stn_output, batch_act = stn_idsia_inference_type2(x)

Кусок кода выше развертывает всю сеть — STN + IDSIA, их мы обсудим подробнее ниже.

IDSIA: сеть-классификатор


Вдохновленный работой Moodstocks и оригинальной статьей от IDSIA Swiss AI Group, в которой они использовали ансамбль из CNN, чтобы улучшить ранее достигнутое качество модели, я взял общую идею архитектуры одной сети из ансамбля и реализовал его в TensorFlow самостоятельно. Получившаяся структура классификатора выглядит следующим образом:
  • Слой 1: Convolutional (batch normalization, relu, dropout). Kernel : 7×7, 100 фильтров. На вход: 32x32x1 (В наборе из 256). На выходе: 32x32x100.
  • Слой 2: Max Pooling. На вход: 32x32x100. На выходе: 16x16x100.
  • Слой 3: Convolutional (batch normalization, relu, dropout). Kernel : 5×5, 150 фильтров. На вход: 16x16x100 (in a batch of 256). На выходе: 16x16x150.
  • Слой 4: Max Pooling. На вход: 16x16x150. На выходе: 8x8x150.
  • Слой 5: Convolutional (batch normalization, relu, dropout). Kernel : 5×5, 250 фильтров. На вход: 16x16x100 (в наборе из 256). На выходе: 16x16x150.
  • Слой 6: Max Pooling. На вход: 8x8x250. На выходе: 4x4x250.
  • Слой 7: Дополнительный pooling для multiscale-фич. Kernels: 8, 4, 2 для слоев 1, 2 и 3 соответственно.
  • Слой 8: Вытягивание и конкатенация фич в вектор multiscale-фич. На входе: 2x2x100; 2x2x150; 2x2x250. На выходе: вектор фичей 400+600+1000 = 2000 для полносвязных слоев
  • Слой 9: Fully-connected (batch normalization, relu, dropout). На входе: 2000 признаков (в наборе из 256). 300 нейронов.
  • Слой 10: Logits (batch normalization). На входе: 300 признаков. На выходе: логиты (43 класса).

Все это проиллюстрировано ниже:

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

На вход conv1 подается преобразованное STN изображение, как мы и обсуждали ранее.

Spatial Transformers в TensorFlow


Среди всего разнообразия моделей TensorFlow можно найти реализацию STN, которая и будет использована в нашей сети.

Наша задача — обозначить и обучить LocNet, обеспечить transformer корректными значениями θ и вставить STN модуль в DAG Tensorflow. transformer генерирует сетку и обеспечивает преобразования и интерполяцию.

Конфигурация LocNet представлена ниже:

Сверточные слои LocNet:

  • Слой 1: Max Pooling. На входе: 32x32x1. На выходе: 16x16x1.
  • Слой 2: Convolutional (relu, batch normalization). Kernel : 5×5, 100 фильтров. На входе: 16x16x1 (в наборе из 256). На выходе: 16x16x100.
  • Слой 3: Max Pooling. На входе: 16x16x100. На выходе: 8x8x100.
  • Слой 4: Convolutional (batch normalization, relu). Kernel : 5×5, 200 фильтров. На входе: 8x8x100 (в наборе из 256). На выходе: 8x8x200.
  • Слой 5: Max Pooling. На входе: 8x8x200. На выходе: 4x4x200.
  • Слой 6: Дополнительный pooling для multiscale-фич. Kernels: 4, 2 для сверточных слоев 1 и 2 соответственно.
  • Слой 7: Вытягивание и конкатенация фич в вектор . На входе: 2x2x100; 2x2x200. На выходе: вектор фич размерностью 400+800 = 1200 для полносвязных слоев.

Fully-connected часть LocNet:
  • Слой 8: Fully-connected(batch normalization, relu, dropout). На входе: 1200 признаков (в наборе из 256). 100 нейронов.
  • Слой 9: 2х3 матрица θ, которая задает аффинное преобразование. Веса задаются нулями, свободный член — матрицей, похожей на единичную, с единицами на главной диагонали: [[1.0, 0, 0], [0, 1.0, 0]].
  • Слой 10: Transformer: Генератор сетки и сэмплер, реализованные в spatial_transformer.py. Этот слой производит изображения с теми же измерениями, что и исходные (32x32x1), применяя к ним аффинное преобразование (таким образом, получается приближенное или повернутое изображение).

Структура сверточных слоев LocNet похожа на IDSIA (хотя LocNet состоит из 2 слоев вместо 3, и в ней мы сначала делаем пуллинг). Более любопытна структура полносвязных слоев:

Обучение и результаты


Проблема использования STN модуля с CNN заключается в необходимости следить за тем, чтобы обе сети не переобучались, что делает процесс обучения сложным и нестабильным. С другой стороны, добавление небольшого количества аугментированных данных (особенно аугментирование яркости) в обучающую выборку позволяет сетям не переобучаться. В любом случае, преимущества перевешивают недостатки: даже без аугментации мы получаем хорошие результаты, а STN+IDSIA превосходят по точности IDSIA без этого модуля на 0,5-1%.

В процессе обучения были использованы следующие параметры:

# TF Parameters
TF_CONFIG = {
	'epochs': 20,
	'batch_size': 256,
	'channels': 1
}

# Omitting the model building phase (discussed earlier in this post)
# ...

# Train / validation datasets, see the previous post.
# No augmentations.
train_val_data = {
	'X_train': X_tr_256,
	'y_train': y_tr_256,
	'X_valid': X_val_256,
	'y_valid': y_val_256
}

# Initializing the session and vars:
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

# Skipping details and going to the training:
for i in range(TF_CONFIG['epochs']):
	for batch_x, batch_y in batch_generator(train_val_data['X_train'],
                                        	train_val_data['y_train'],
                                        	batch_size=TF_CONFIG['batch_size']):

    	_, loss, lr = sess.run([training_operation, loss_operation, learning_rate],
                           	feed_dict={x: batch_x,
                                      	y: batch_y,
                                      	dropout_conv: 1.0,
                                      	dropout_loc: 0.9,
dropout_fc1: 0.3}

Уже после 10 эпох мы получаем точность равную 99,3% на validation наборе данных. CNN все еще переобучается, но не забывайте, что мы используем двойную сложную сетку на исходном датасете без его расширения аугментациями. По правде говоря, добавив аугментацию, мне удалось получить точность равную 99,6% на validation сете после 10 итераций (хотя значительно увеличилось время обучения).

Ниже приведены результаты обучения моделей (idsia_1 — это IDSIA сеть без модуля, idsia_stn — это STN+IDSIA). Это точность всей сети на валидации.

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

Наконец, вот результат работы STN трансформера после обучения:

Что ж, резюмируем:

  • STN — дифференцируемый модуль, который может быть интегрирован в сверточную нейронную сеть. Стандартный юзкейс — это поместить его сразу после батч-генератора, чтобы он мог обучить матрицу преобразований θ, которая минимизирует функцию потерь главного классификатора (IDSIA в нашем случае).
  • STN сэмплер применяет аффинное преобразование к исходным изображениям (или карте признаков).
  • STN можно рассматривать как альтернативу аугментации изображений, которая является стандартным способом добиться пространственной инвариантности для CNN.
  • Добавляя один или несколько STN модулей в CNN усложняет обучение, делает его нестабильным: теперь необходимо следить, чтобы обе (вместо одной) сети не переобучались. Как мне кажется, это одна из причин, почему STN пока не так распространены.
  • STN, обученные на аугментированных данных (особенно аугментация яркости) показывают лучшее качество и не переобучаются слишком сильно.

Что такое технология оптического распознавания символов, или OCR

ABBYY
  • Контакты
  • Интернет-магазин
  • Выберите регион
    Global
    Global Web Site English
    North America
    Canada English Mexico Español United States English
    South America
    Brazil Português South America Español

    Europe

    France Français Germany Deutsch Italy Italiano United Kingdom English Spain Español Western Europe English Central and Eastern Europe English Croatia Hrvatski Czech Republic Čeština Hungary Magyar Poland Polski Romania Română Russia Русский Slovakia Slovenčina Ukraine Українська
    Africa and Asia
    China 中文 India and SEA Countries English Israel עברית

Оптическое распознавание символов — Википедия

Оптическое распознавание символов (англ. optical character recognition, OCR) — механический или электронный перевод изображений рукописного, машинописного или печатного текста в текстовые данные, использующиеся для представления символов в компьютере (например, в текстовом редакторе). Распознавание широко применяется для преобразования книг и документов в электронный вид, для автоматизации систем учёта в бизнесе или для публикации текста на веб-странице. Оптическое распознавание символов позволяет редактировать текст, осуществлять поиск слов или фраз, хранить его в более компактной форме, демонстрировать или распечатывать материал, не теряя качества, анализировать информацию, а также применять к тексту электронный перевод, форматирование или преобразование в речь. Оптическое распознавание текста является исследуемой проблемой в областях распознавания образов, искусственного интеллекта и компьютерного зрения.

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

История

В 1929 году Густав Таушек (Gustav Tauschek) получил патент на метод оптического распознавания текста в Германии, после чего за ним последовал Гендель (Paul W. Handel), получив патент на свой метод в США в 1933. В 1935 году Таушек также получил патент США на свой метод. Машина Таушека представляла собой механическое устройство, которое использовало шаблоны и фотодетектор.

В 1950 году Дэвид Х. Шепард (David H. Shepard), криптоаналитик из агентства безопасности вооружённых сил Соединённых Штатов, проанализировав задачу преобразования печатных сообщений в машинный язык для обработки компьютером, построил машину, решающую данную задачу. После того как он получил патент США, он сообщил об этом в «Вашингтон Дэйли Ньюз» (27 апреля 1951) и в «Нью-Йорк Таймс» (26 декабря 1953). Затем Шепард основал компанию, разрабатывающую интеллектуальные машины, которая вскоре выпустила первые в мире коммерческие системы оптического распознавания символов.

Первая коммерческая система была установлена на «Ридерс Дайджест» в 1955 году. Вторая система была продана компании «Стандарт Ойл» для чтения кредитных карт для работы с чеками. Другие системы, поставляемые компанией Шепарда, были проданы в конце 1950-х годов, в том числе сканер страниц для национальных воздушных сил США, предназначенный для чтения и передачи по телетайпу машинописных сообщений. IBM позже получила лицензию на использование патентов Шепарда.

Примерно в 1965 году «Ридерс Дайджест» и «Ар-Си-Эй» начали сотрудничество с целью создать машину для чтения документов, использующую оптическое распознавание текста, предназначенную для оцифровки серийных номеров купонов «Ридерс Дайджест», вернувшихся из рекламных объявлений. Для печати на документах барабанным принтером «Ар-Си-Эй» был использован специальный шрифт OCR-A. Машина для чтения документов работала непосредственно с компьютером RCA 301 (одна из первых полупроводниковых ЭВМ). Скорость работы машины была 1500 документов в минуту: она проверяла каждый документ, исключая те, которые она не смогла обработать правильно.

Почтовая служба Соединённых Штатов с 1965 года для сортировки почты использует машины, работающие по принципу оптического распознавания текста, созданные на основе технологий, разработанных исследователем Яковом Рабиновым. В Европе первой организацией, использующей машины с оптическим распознаванием текста, был британский почтамт. Почта Канады использует системы оптического распознавания символов с 1971 года. На первом этапе в центре сортировки системы оптического распознавания символов считывают имя и адрес получателя и печатают на конверте штрих-код. Он наносится специальными чернилами, которые отчётливо видимы в ультрафиолетовом свете. Это делается, чтобы избежать путаницы с полем адреса, заполненным человеком, которое может быть в любом месте на конверте.

В 1974 году Рэй Курцвейл создал компанию «Курцвейл Компьютер Продактс», и начал работать над развитием первой системы оптического распознавания символов, способной распознать текст, напечатанный любым шрифтом. Курцвейл считал, что лучшее применение этой технологии — создание машины чтения для слепых, которая позволила бы слепым людям иметь компьютер, умеющий читать текст вслух. Данное устройство требовало изобретения сразу двух технологий — ПЗС планшетного сканера и синтезатора, преобразующего текст в речь. Конечный продукт был представлен 13 января 1976 во время пресс-конференции, возглавляемой Курцвейлом и руководителями национальной федерации слепых.

В 1978 году компания «Курцвейл Компьютер Продактс» начала продажи коммерческой версии компьютерной программы оптического распознавания символов. Два года спустя Курцвейл продал свою компанию корпорации «Ксерокс», которая была заинтересована в дальнейшей коммерциализации систем распознавания текста. «Курцвейл Компьютер Продактс» стала дочерней компанией «Ксерокс», известной как «Скансофт».

Первой коммерчески успешной программой, распознающей кириллицу, была программа «AutoR» российской компании «ОКРУС». Программа начала распространяться в 1992 году, работала под управлением операционной системы DOS и обеспечивала приемлемое по скорости и качеству распознавание даже на персональных компьютерах IBM PC/XT с процессором Intel 8088 при тактовой частоте 4,77 МГц. В начале 90-х компания Hewlett-Packard поставляла свои сканеры на российский рынок в комплекте с программой «AutoR». Алгоритм «AutoR» был компактный, быстрый и в полной мере «интеллектуальный», то есть по-настоящему шрифтонезависимый. Этот алгоритм разработали и испытали ещё в конце 60-х два молодых биофизика, выпускники МФТИ — Г. М. Зенкин и А. П. Петров. Свой метод распознавания они опубликовали в журнале «Биофизика» в номере 12, вып. 3 за 1967 год. В настоящее время алгоритм Зенкина-Петрова применяется в нескольких прикладных системах, решающих задачу распознавания графических символов. На основе алгоритма компанией Paragon Software Group в 1996 была создана технология PenReader. Г.М Зенкин продолжил работу над технологией PenReader в компании Paragon Software Group.[1] Технология используется в одноименном продукте компании.[2]

В 1993 году вышла технология распознавания текстов российской компании ABBYY. На её основе создан ряд корпоративных решений и программ для массовых пользователей. В частности, программа для распознавания текстов ABBYY FineReader, приложения для распознавания текстовой информации с мобильных устройств, система потокового ввода документов и данных ABBYY FlexiCapture. Технологии распознавания текстов ABBYY OCR лицензируют международные ИТ-компании, такие как Fujitsu, Panasonic, Xerox, Samsung[3], EMC и другие.

Текущее состояние технологии оптического распознавания текста

Точное распознавание латинских символов в печатном тексте в настоящее время возможно, только если доступны чёткие изображения, такие, как сканированные печатные документы. Точность при такой постановке задачи превышает 99 %, абсолютная точность может быть достигнута только путём последующего редактирования человеком. Проблемы распознавания рукописного «печатного» и стандартного рукописного текста, а также печатных текстов других форматов (особенно с очень большим числом символов) в настоящее время являются предметом активных исследований.

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

Распознавание символов онлайн иногда путают с оптическим распознаванием символов. Последний — это офлайн-метод, работающий со статической формой представления текста, в то время как онлайн-распознавание символов учитывает движения во время письма. Например, в онлайн-распознавании, использующем PenPoint OS или планшетный ПК, можно определить, с какой стороны пишется строка: справа налево или слева направо.

Онлайн-системы для распознавания рукописного текста «на лету» в последнее время стали широко известны в качестве коммерческих продуктов. Алгоритмы таких устройств используют тот факт, что порядок, скорость и направление отдельных участков линий ввода известны. Кроме того, пользователь научится использовать только конкретные формы письма. Эти методы не могут быть использованы в программном обеспечении, которое использует сканированные бумажные документы, поэтому проблема распознавания рукописного «печатного» текста по-прежнему остаётся открытой. На изображениях с рукописным «печатным» текстом без артефактов может быть достигнута точность в 80 % — 90 %, но с такой точностью изображение будет преобразовано с десятками ошибок на странице. Такая технология может быть полезна лишь в очень ограниченном числе приложений.

Ещё одной широко исследуемой задачей является распознавание рукописного текста. В данное время достигнутая точность даже ниже, чем для рукописного «печатного» текста. Более высокие показатели могут быть достигнуты только с использованием контекстной и грамматической информации. Например, в ходе распознания искать целые слова в словаре легче, чем пытаться выявить отдельные знаки из текста. Знание грамматики языка может также помочь определить, является ли слово глаголом или существительным. Формы отдельных рукописных символов иногда могут не содержать достаточно информации, чтобы точно (более 98 %) распознать весь рукописный текст.

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

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

Примечания

См. также

Ссылки

Распознавание текста с помощью OCR / Habr

Tesseract — это движок оптического распознавания символов (OCR) с открытым исходным кодом, является самой популярной и качественной OCR-библиотекой.

OCR использует нейронные сети для поиска и распознавания текста на изображениях.

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

На одном из проектов стояла задача распознать чеки с фотографий.

Инструментом для распознавания был использован Tesseract OCR. Плюсами данной библиотеки можно отметить обученные языковые модели (>192), разные виды распознавания (изображение как слово, блок текста, вертикальный текст), легкая настройка. Так как Tesseract OCR написан на языке C++, был использован сторонний wrapper c github.

Различиями между версиями являются разные обученные модели (версия 4 имеет большую точность, поэтому мы использовали её).

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

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

Также был найден способ обработки изображения для его дальнейшего распознавания путем использования библиотеки OpenCV. Так как OpenCV написан на языке C++, и не существует оптимального для нашего решения написанного wrapper’а, было решено написать собственный wrapper для этой библиотеки с необходимыми для нас функциями обработки изображения. Основной сложностью является подбор значений для фильтра для корректной обработки изображения. Также есть возможность нахождения контуров чеков/текста, но не изучено до конца. Результат получился лучше (на 5-10%).

Параметры:

language — язык текста с картинки, можно выбрать несколько путем их перечисления через «+»;

pageSegmentationMode — тип расположения текста на картинке;

charBlacklist — символы, которые будут игнорироваться ignoring characters.

Использование только Tesseract дало точность ~70% при идеальном изображении, при плохом освещении/качестве картинки точность была ~30%.


Vision + Tesseract OCR

Так как результат был неудовлетворителен, было решено использовать библиотеку от Apple — Vision. Мы использовали Vision для нахождения блоков текста, дальнейшего разделения изображения на отдельные блоки и их распознавания. Результат был лучше на ~5%, но и появлялись ошибки из-за повторяющихся блоков.

Недостатками этого решения были:


  1. Скорость работы. Скорость работы уменьшилась >4 раза (возможно, существует вариант распоточивания)
  2. Некоторые блоки текста распознавались более 1 раза
  3. Текст распознается справа налево, из-за чего текст с правой части чека распознавался раньше, чем текст слева.


MLKit

Еще одним из методов определения текста является MLKit от Google, развернутый на Firebase. Данный метод показал наилучшие результаты (~90%), но главным недостатком этого метода является поддержка только латинских символов и сложная обработка разделенного текста в одной строке (наименование — слева, цена — справа).

В итоге можно сказать, что распознать текст на изображениях — задача выполнимая, но есть некоторые трудности. Основной проблемой является качество (размер, освещенность, контрастность) изображения, которую можно решить путем фильтрации изображения. При распознавании текста при помощи Vision или MLKit были проблемы с неверным порядком распознавания текста, обработкой разделенного текста.

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

Отправить ответ

avatar
  Подписаться  
Уведомление о