- Как обойти капчу: нейросеть на Tensorflow,Keras,python v числовая зашумленная капча
- Плясать от печки. Вместо вступления
- Собираем данные по капчам
- Нейросеть. Тестовая
- Нейросеть — собственные данные
- Запускаем
- Быстрее, выше, сильнее. Улучшаем результаты
- Попробуем другие методы
- Текстовые капчи легко распознаются нейронными сетями глубокого обучения
- Что такое текстовая капча?
- Полносверточная нейронная сеть
- Тренировка на генераторе
- Тренировка на реальном датасете
- Более глубокая сеть
- Улучшения
- Неудачные идеи
- Результат
- Что еще можно было бы улучшить
Как обойти капчу: нейросеть на Tensorflow,Keras,python v числовая зашумленная капча
Тема капч не нова, в том числе для Хабра. Тем не менее, алгоритмы капч меняются, как и алгоритмы их решения. Поэтому, предлагается помянуть старое и прооперировать следующий вариант капчи:
попутно понять работу простой нейросети на практике, а также улучшить ее результаты.
Сразу оговоримся, что не будем погружаться в размышления о том, как работает нейрон и что с этим всем делать, статья не претендует на научность, а только предоставляет небольшой туториал.
Плясать от печки. Вместо вступления
Возможно повторятся чьи-то слова, но большинство книг по Deep Learning действительно начинаются с того, что читателю предлагаются заранее заготовленные данные, с которыми он начинает работать. Как-то MNIST — 60 000 рукописных цифр, CIFAR-10 и т.п. После прочтения человек выходит подготовленным… к этим наборам данных. Совершенно не ясно, как использовать свои данные и главное, как что-то улучшить при построении своей собственной нейросети.
Поэтому очень кстати вышла статья на pyimagesearch.com о том как работать со своими собственными данными, а также ее перевод.
Но, как говорится, хрен редьки не слаще: даже с переводом разжеваной статьи по keras осталось много слепых мест. Опять же предлагается заранее подготовленный датасет, только уже с котами, собаками и пандами. Придется заполнить пустоты самостоятельно.
Однако за базу будет взята эта статья и код.
Собираем данные по капчам
Здесь нет ничего нового. Нам нужны капчи-образцы, т.к. сеть будет учиться по ним под нашим руководством. Можете намайнить капч самостоятельно, а можете взять немного здесь — 29 000 капч. Теперь необходимо нарезать цифр из каждой капчи. Необязательно резать все 29 000 капч, тем более, что 1 капча дает 5 цифр. 500 капч будет более чем достаточно.
Как резать? Можно в photoshopе, но лучше иметь нож получше.
Поэтому вот код ножа на python — скачать. (для Windows. Предварительно создать папки C:\1\test и C:\1\test-out).
На выходе получится свалка из цифр от 1 до 9 (нулей в капче нет).
Далее надо разобрать этот завал из цифр по папкам от 1 до 9 и разложить в каждую папку по соответствующей цифре. Так себе занятие. Но за день можно разобрать до 1000 цифр.
Если при выборе цифры возникает сомнение какая из цифр, лучше удалить этот образец. И ничего страшного если цифры будут зашумлены или неполностью входить в «кадр»:
Набрать в каждую папку надо штук по 200 образцов каждой цифры. Можно эту работу поручить сторонним сервисам, но лучше сделать все самим, чтобы потом не искать неправильно соотнесенные цифры.
Нейросеть. Тестовая
Тятя, тятя, наши сети притащили мертвеца
Перед тем как начать работать с собственными данными лучше пройтись по вышеуказанной статье и запустить код, чтобы понять, что все компоненты (keras, tensorflow и т.п.) установлены и работают корректно.
Будем использовать простую сеть, синтаксис запуска которой из командной (!) строки:
*Tensorflow может писать при работе об ошибках в собственных файлах и устаревших методах, можно это исправить руками, а можно просто игнорировать.
Главное, чтобы на выходе после отработки программы в папке проекта output появились два файла: simple_nn_lb.pickle и simple_nn.model, а на экран будет выведено изображение животного с надписью и процентом распознавания, например:
Нейросеть — собственные данные
Теперь, когда тест работоспособности сети проверен, можно подключить собственные данные и начать обучать сеть.
Поместим в папку dat папки с цифрами, содержащими отобранные образцы по каждой цифре.
Папку dat для удобства разместим в папке с проектом (например рядом c папкой animals).
Теперь синтаксис запуска обучения сети будет таким:
Однако пока рано запускать обучение.
Необходимо поправить файл train_simple_nn.py.
1. В самый конец файла:
Это добавит информативности.
Здесь мы изменяем размер входной картинки. Почему именно такой размер? Потому как большинство из нарезанных цифр имеют такой размер либо приводятся к нему. Если масштабировать до 32×32 пикселя, картинка будет искажена. Да и зачем это делать?
Кроме того, загоняем это изменение в try:
Т.к. некоторые картинки программа не может переварить и выдает None, поэтому они пропускаются.
3.Теперь самое важное. Там где комментарий в коде
определим архитектуру 3072-1024-512-3 с помощью Keras
Архитектура сети в статье определена как 3072-1024-512-3. Это означает, что сеть получает на вход 3072 (32 пикселя * 32 пикселя * 3), далее слой 1024, слой 512 и на выходе 3 варианта — кот, собака или панда.
В нашем случае вход 1776 (16 пикселей*37 пикселей*3), далее слой 1024, слой 512, на выходе 9 вариантов цифр.
Поэтому наш код:
*9 выходов дополнительно указывать не нужно, т.к. программа сама определяет количество выходов по количеству папок в датасете.
Запускаем
Так как картинки с цифрами маленькие, сеть обучается очень быстро (5-10 мин) даже на слабом железе, используя только CPU.
После прогона программы в командой строке посмотрим результаты:
Это означает, что на обучающем наборе достигнута верность — 82,19%, на контрольном — 75,6 % и на тестовом — 75,59 %.
Нам надо ориентироваться на последний показатель большей частью. Почему остальные также важны будет пояснено далее.
Посмотрим также графическую часть работы нейросети. Она в папке output проекта simple_nn_plot.png:
Быстрее, выше, сильнее. Улучшаем результаты
Совсем коротко о настройке нейросети можно посмотреть здесь.
Вариант подлиннее следующий.
Добавим эпох.
В коде меняем
Увеличим «количество раз», которое сеть пройдет обучение.
Таким образом, 93,5%, 92,6%, 92,6%.
Здесь заметно, что синяя и красные линии после 130 эпохи начинают разъезжаться друг от друга и это говорит, что дальнейшее увеличение числа эпох ничего не даст. Проверим это.
и снова прогоняем.
Что ж, увеличение числа эпох, явно пошло сети на пользу. Однако этот результат обманчив.
Проверим работу сети на реальном примере.
Для этих целей в папке проекта есть скрипт predict.py. Перед запуском подготовимся.
В папку images проекта положим файлы с изображениями цифр с капчи, ранее не попадавшиеся сети в процессе обучения. Т.е. надо взять цифры не из набора датасета dat.
В самом файле поправим две строки для размера изображений по умолчанию:
Запускаем из коммандной строки:
И видим результат:
Однако не со всеми зашумленными цифрами работает:
Что здесь можно сделать?
- Увеличить количество экземпляров цифр в папках для обучения.
- Попробовать другие методы.
Попробуем другие методы
Как видно из последнего графика, синяя и красная линии расходятся примерно на 130 эпохе. Это означает, что, обучение после 130 эпохи неэффективно. Зафиксируем результат на 130 эпохе: 89,3%,88%,88% и посмотрим, работают ли другие методы улучшения работы сети.
Снизим скорость обучения.
Дабавим дополнительный скрытый слой.
Однако, если увеличить количество эпох до 250:
84%,83%,83%
При этом красная и синяя линия не отрываются друг от друга после 130 эпохи:
Сохраним 250 эпох и применим прореживание:
Между слоями вставим прореживание:
Первое значение ниже остальных, это говорит о том, что сеть не обучается. Для этого рекомендуют увеличить количество эпох.
С 1 дополнительным слоем, прореживанием и 500 эпохами:
Несмотря на более низкий процент по сравнению с простым увеличением эпох до 500, график выглядит более ровным:
И сеть обрабатывает изображения, которые ранее выпадали:
Соберем теперь все в один файл, который нарежет изображение с капчей на входе на 5 цифр, прогонит каждую цифру через нейросеть и выдаст результат в интерпретатор python.
Здесь попроще. В файл, который нарезал нам цифры из капчи добавим файл, который занимается предсказаниями.
Теперь программа не только нарежет капчу на 5 частей, но и выведет все распознанные цифры в интерпретатор:
Опять же надо иметь в виду, что программа не дает 100% результата и зачастую одна из 5 цифр неверна. Но и это неплохой результат, если учесть, что в обучающем наборе всего по 170-200 экземпляров для каждого числа.
Распознавание капчи длится 3-5 сек на компьютере средней мощности.
Как еще можно попытаться улучшить работу сети можно почитать в книге «Библиотека Keras — инструмент глубокого обучения» А. Джулли, С.Пала.
Итоговый скрипт, который режет капчу и распознает — здесь.
Запускается без параметров.
Переработанные скрипты для тренировки и теста сети.
Капчи для теста, в том числе с ложным срабатыванием — здесь.
Модель для работы — здесь.
Цифры, разложенные по папкам — здесь.
Источник
Текстовые капчи легко распознаются нейронными сетями глубокого обучения
Нейронные сети глубокого обучения достигли больших успехов в распознавании образов. В тоже время текстовые капчи до сих пор используются в некоторых известных сервисах бесплатной электронной почты. Интересно смогут ли нейронные сети глубоко обучения справится с задачей распознавания текстовой капчи? Если да то как?
Что такое текстовая капча?
Капча (англ. “CAPTCHA”) — это тест на “человечность”. То есть задача, которую легко решает человек, в то время как для машины эта задача должна быть сложной. Зачастую используется текст со слипшимися буквами, пример на картинке ниже, также картинку дополнительно подвергают оптическим искажениям.
Капча, как правило, используется на странице регистрации для защиты от ботов рассылающих спам.
Полносверточная нейронная сеть
Количество карт центров равно длине алфавита символов использованных в определенной капче. На картах центров отмечаются центры букв. Масштабное преобразование, которое в сети происходит из-за наличия пуллинг слоев, учитывается. Ниже показан пример карты символа для символа “D”
В данном случае используются сверточные слои с паддингом так, чтобы размер изображений на выходе сверточного слоя равнялся размеру изображений на входном слое. Профиль пятна на карте символа задается двумерной гауссовой функцией с ширинами 1.3 и 2.6 пикселей.
Первоначально полносверточная сеть была проверена на символе “R”:
Для проверки применялась небольшая сеть с 2мя пуллингами, натреннированная на CPU. Убедившись, что идея хоть как то работает, я приобрел б/у видеокарту Nvidia GTX 760, 2GB. Это дало мне возможность тренировать более крупные сети для всех символов алфавита, а также ускорило обучение (примерно в 10 раз). Для тренировки сети использовалась библиотека Theano, на текущий момент уже не поддерживаемая.
Тренировка на генераторе
Финальная точность тренировки на сгенерированных капчах, как оказалось, в 2 раза ниже, по сравнению с тренировкой на реальных капчах. Вероятно, такие нюансы как степень пересечения символов, масштаб, толщина линий символов, параметры искажения и т. п., важны, и в генераторе эти нюансы воспроизвести не удалось. Сеть тренированная на сгенерированных капчах давала точность на реальных капчах около 10%, точность — какой процент капч распознался правильно. Капча считается распознанной, если все символы в ней распознаны правильно. В любом случае этот эксперимент показал, что метод рабочий, и требуется повысить точность распознавания.
Тренировка на реальном датасете
Для ручной разметки датасета реальных капч был написан скрипт на Matlab с графическим интерфейсом:
Здесь кружочки можно расставлять и двигать мышкой. Кружочком отмечается центр символа. Ручная разметка занимала 5-15 часов, однако есть сервисы, где за не большую плату размечают вручную датасеты. Однако, как оказалось, сервис Amazon Mechanical Turk не работает с российскими заказчиками. Разместил заказ на разметку датасета на известном сайте фриланса. К сожалению, качество разметки было не идеальным, поправлял разметку самостоятельно. Кроме того, поиск исполнителя занимает время (1 неделя) и также это показалось дорого: 30 долларов за 560 размеченных капч. От данного способа отказался, в итоге пришел к использованию сайтов ручного распознавания капч, где самая низкая стоимость 1 доллар за 2000 капч. Но полученный ответ там — это строка. Таким образом, ручной расстановки центров избежать не удалось. Более того, исполнители в таких сервисах допускают ошибки или вовсе действуют недобросовестно, печатая произвольную строку в ответе. В итоге приходилось проверять и исправлять ошибки.
Более глубокая сеть
Очевидно точность распознавания была недостаточна, поэтому возник вопрос подбора архитектуры. Меня интересовал вопрос “видит” ли один пиксель на выходном изображении весь символ на входном изображении:
Таким образом, мы рассматриваем один пиксель на выходном изображении, и есть вопрос: значения каких пикселей на входном изображении влияют на значения этого пикселя? Я рассуждал так: если пиксель видит не весь символ, то используется не вся информация о символе и точность хуже. Для определения размера этой области видимости (будем называть ее так), я провел следующий эксперимент: установил все веса сверточных слоев равным 0.01, а смещения равным 0, на вход сети подается изображение, в котором значения всех пикселей равны 0 кроме центрального. В результате на выходе сети получается пятно:
Форма данного пятна близка к форме гауссовой функции. Форма получившегося пятна вызывает вопрос, почему пятно круглое, тогда как ядра сверток в сверточных слоях квадратные? (В сети использовались ядра сверток 3×3 и 5×5). Мое объяснение такое: это похоже на центральную предельную теорему. В ней, как и здесь, присутствует стремление к гауссовому распределению. Центральная предельная теорема утверждает, что для случайных величин, даже с разными распределениями, распределение их суммы равно свертке распределений. Таким образом, если мы сворачиваем любой сигнал сам с собой много раз, то по центральной предельной теореме результат стремится к гауссовой функции, а ширина гауссовской функции растет как корень из количества сверток (слоев). Если для такой же сети с константными весами посмотреть, где в выходном изображении значения пикселей больше нуля, то получается все таки квадратная область (см. рисунок ниже), размер этой области пропорционален сумме размеров сверток в сверточных слоях сети.
Раньше думал, что из-за ассоциативного свойства свертки две последовательные свертки 3×3 эквивалентны свертке 5×5 и потому, если свернуть 2 ядра 3×3 получится одно ядро 5×5. Однако, потом пришел к выводу, что это не эквивалентно хотя бы потому, что у двух сверток 3×3 9*2=18 параметров, а у одной 5×5 25 параметров, таким образом, у свертки 5×5 больше степеней свободы. В итоге, на выходе сети получается гауссова функция с шириной меньше суммы размеров сверток в слоях. Здесь ответил на вопрос какие пиксели на выходе подвержены влиянию одного пикселя на входе. Хотя изначально вопрос ставился обратный. Но оба вопросы эквивалентны, что можно понять из рисунка:
На рисунке можно представить, что это вид на изображения с боку или, что у нас высота изображений равна 1. Каждый из пикселей A и B имеет свою зону влияния на выходном изображении (обозначены синим цветом): для А это D-C, для B это C-E, на значения пикселя C влияют значения пикселей A и B и значения всех пикселей между A и B. Расстояния равны: AB = DC = CE (с учетом масштабирования: в сети присутствуют пуллинг слои, поэтому входное и выходное изображения имеют разные разрешения). В итоге, получается следующий алгоритм нахождения размера области видимости:
- задаем константные веса в сверточных слоях, весам-смещениям задаем значения 0
- на вход подаем изображения с одним ненулевым пикселем
- получаем размер пятна на выходе
- умножаем этот размер на коэффициент учитывающий разное разрешение входного и выходного слоя (например, если у нас 2 пулинга в сети, то разрешение на выходе в 4 раза меньше, чем на входе, значит этот размер надо умножать на 4).
Чтобы посмотреть какие признаки сеть использует, провел следующий эксперимент: в тренированную сеть подаем изображение капчи, на выходе получаем изображения с отмеченными центрами символов, из них выбираем какой-нибудь задетектированный символ, на изображениях-картах центров оставляем ненулевой только ту карту, которая соответствует рассматриваемому символу. Такой выход сети запоминаем как , затем градиентным спуском минимизируем функцию:
Здесь — входное изображение сети,
— выходные изображения сети,
— некоторая константа, которая подбирается экспериментально (
). При такой минимизации вход и выход сети считаются переменными, а веса сети константами. Начальное значение переменной
это изображение капчи, является начальной точкой оптимизации алгоритма градиентного спуска. При такой минимизации мы уменьшаем значения пикселей на входе изображения, при этом сдерживаем значения пикселей на выходном изображении, в результате оптимизации на входном изображении остаются только те пиксели, которые сеть использует в распознавании символа.
Что получилось:
Для символа “2”:
Для символа “5”:
Для символа “L”:
Для символа “u”:
Изображения слева — исходные изображения капч, изображения справа — это оптимизированное изображение . Квадратом на изображениях обозначена область видимости output>0, окружности на рисунке — это линии уровня Гауссовой функции области видимости. Малая окружность — уровень 35% от максимального значения, большая окружность — уровень 3%. Примеры показывают, что сеть видит в пределах своей области видимости. Однако, у символа “u” наблюдается выход за область видимости, возможно это частичное ложное срабатывание на символ “n”.
Было проведено много экспериментов с архитектурой сети, чем более глубокая и широкая сеть, тем более сложные капчи она может распознавать, самой универсальной архитектурой оказалась следующая:
Синим цветом, поверх стрелок, показано количество изображений (feature maps). c- сверточный слой, p — max-pooling слой, зеленым цветом внизу показаны размеры ядер. В сверточных слоях используются ядра 3×3 и 5×5 без strade, пуллинг слой имеет патч 2×2. После каждого сверточного слоя есть ReLU слой (на рисунке не показан). На вход подается одно изображение, на выходе получется 24 (количество символов в алфавите). В сверточных слоях паддинг подобран таким образом, чтобы на выходе слоя размер изображения был таким же как и на входе. Паддинг добавляет нули, однако это никак не влияет на работу сети, потому что значение фонового пикселя капчи — 0, так как всегда берется негативное изображение (белые буквы по черному фону). Паддинг лишь незначительно замедляет работу сети. Так как в сети 2 пуллинг слоя, то разрешение изображения на выходе в 4 раза меньше разрешения изображения на входе, таким образом каждый пуллинг уменьшает разрешение в 2 раза, например, если на входе у нас капча размером 216×96 то на выходе будет 24 изображения размером 54×24.
Улучшения
Переход от решателя SGD к решателю ADAM дал заметное ускорение обучения, и финальное качество стало лучше. Решатель ADAM импортировал из модуля lasagne и использовал внутри theano-кода, параметр learning rate ставил 0.0005, регуляризация L2 была добавлена через градиент. Было замечено, что от тренировки к тренировке результат получается разный. Объясняю это так: алгоритм градиентного спуска застревает в недостаточно оптимальном локальном минимуме. Частично поборол это следующим образом: запускал тренировку несколько раз и выбирал несколько самых лучших результатов, затем продолжал их тренировать еще несколько эпох, после из них выбирал один лучший результат и уже этот единственный лучший результат долго тренировал. Таким образом удалось избежать застревания в недостаточно оптимальных локальных минимумах и финальное значение функции ошибок (loss) получалась достаточно малым. На рисунке показан график — эволюция значения функции ошибок:
По оси x — число эпох, по оси y — значение функции ошибок. Разными цветами показаны разные тренировки. Порядок обучения примерно такой:
1) запускаем 20 тренировок по 10 эпох
2) выбираем 10 лучших результатов (по наименьшему значению loss) и тренируем их еще 100 эпох
3) выбираем один лучший результат и продолжаем тренировать его еще 1500 эпох.
Это занимает около 12 часов. Конечно, для экономии памяти, данные тренировки проводились последовательно, например, в пункте 2) 10 тренировок проводились последовательно одна за другой, для этого провел модификацию решателя ADAM от Lasagne, чтобы иметь возможность сохранять и загружать состояние решателя в переменные.
Разбиение датасета на 3 части позволяло отслеживать переобучение сети:
1 часть: тренировочный датасет — исходный, на котором сеть обучается
2 часть: тестовый датасет, на котором сеть проверяется в процессе тренировки
3 часть: отложенный датасет, на нем проверяется качество обучения после тренировки
Датасеты 2 и 3 небольшие, в моем случае было по 160 капч в каждом, также по датасету 2 определяется оптимальный порог срабатывания, порог который устанавливается на выходное изображение. Если значение пикселя превышает порог, то в данном месте обнаружен соответствующий символ. Обычно оптимальное значение порога срабатывания находится в диапазоне 0.3 — 0.5. Если точность на тестовом датасете значительно ниже, чем точность на тренировочном датасете — это значит что произошло переобучение и тренировочный датасет необходимо увеличить. В случае, если эти точности примерно одинаковы, но не высокие, то архитектуру нейронной сети нужно усложнять, а тренировочный датасет увеличивать. Усложнять архитектуру сети можно двумя путями: увеличивать глубину или увеличивать ширину.
Предварительная обработка изображений также повышала точность распознавания. Пример предобработки:
В данном случае методом наименьших квадратов найдена средняя линия повернутой строки, производится поворот и масштабирование, масштабирование проводится по средней высоте строки. Сервис Hotmail часто делает разнообразные искажения:
Эти искажения необходимо компенсировать.
Неудачные идеи
Всегда интересно почитать про чужие неудачи, опишу их здесь.
Существовала проблема малого датасета: для качественного распознавания требовался большой датасет, который требовалось разметить вручную (1000 капч). Мной предпринимались различные попытки каким-то образом обучить сеть качественно на малом датасете. Делал попытку обучать сеть на результатах распознавания другой сети. при этом выбирал только те капчи и те места изображений, в которых сеть была уверена. Уверенность определял по значению пикселя на выходном изображении. Таким образом можно увеличить датасет. Однако идея не сработала, после нескольких итераций обучения качество распознавания сильно ухудшилось: сеть не распознавала некоторые символы, путала их, то есть ошибки распознавания накапливались.
Другая попытка обучиться на малом датасете — использовать сиамские сети, сиамская сеть на входе требует пару капч, если у нас датасет из N капч, то пар будет N 2 , получаем гораздо больше обучающих примеров. Cеть преобразует капчу в карту векторов. В качестве метрики сходства векторов выбрал скалярное произведение. Предполагалось что сиамская сеть будет работать следующим образом. Сеть сравнивает часть изображения на капче с некоторым эталонным изображением символа, если сеть видит, что символ тот же с учетом искажения, то считается, что в данном месте качи есть соответствующий символ. Сиамская сеть тренировалась с трудом, часто застревала в неоптимальном локальном минимуме, точность была заметно ниже точности обычной сети. Возможно проблема была в неправильном выборе метрики сходства векторов.
Также была идея использовать автоэнкодер для предварительного обучения нижней части сети (та, что ближе к входу), чтобы ускорить обучение. Автоэнкодер — это сеть, которая обучается выдавать на выходном изображении то же что и подается на вход, при этом в архитектуре автоэнкодера организуют узкий участок. Тренеровка автоэнкодера есть обучение без учителя.
Пример работы автоэкодера:
Первое изображение — входное, второе — выходное.
У обученного автоэнкодера берут нижнюю часть сети, добавляют новых необученных слоев, все это дотренировывают на требуемую задачу. В моем случае применение автоэнкодера никак не ускоряло обучение сети.
Также был пример капчи, которая использовала цвет:
На данной капче описанный метод с полносверточной нейронной сетью не давал результата, он не появился даже после различных предобработок изображения повышающих контрастность. Предполагаю что, полносверточные сети плохо справляются с неконтрастными изображениями. Тем не менее, данную капчу удалось распознать обычной сверточной сетью с полносвязным слоем, получена точность около 50%, определение координат символов осуществлялось специальным эвристическим алгоритмом.
Результат
Примеры | Точность | Коментарий |
---|---|---|
| 42 % | Капча Микрософт , jpg |
61 % | ||
63 % | ||
93 % | капча mail.ru, 500×200, jpg | |
87 % | капча mail.ru, 300×100, jpg | |
65 % | Капча Яндекс, русские слова, gif | |
70 % | капча Steam, png | |
82 % | капча World Of Tanks, цифры, png |
Что еще можно было бы улучшить
Можно было бы сделать автоматическую разметку центров символов. Сервисы ручного распознавания капч выдают лишь распознанные строки, поэтому автоматическая разметка центров помогла бы полностью автоматизировать разметку тренировочного датасета. Идея такова: выбрать только те капчи, в которых каждый символ встречается один раз, на каждый символ натренировать отдельную обычную сверточную сеть, такая сеть будет отвечать лишь на вопрос: есть ли в данной капче символ или нет? Затем посмотреть какие признаки использует сеть, используя метод минимизация значений пикселей входной картинки (описано выше). Полученные признаки позволят локализовать символ, далее тренируем полносверточную сеть на полученных центрах символов.
Источник