Evgenii Legotckoi
Evgenii Legotckoi13 травня 2020 р. 05:42

Розпізнавання зображень на Python за допомогою TensorFlow та Keras

Вступ

Одним з найпоширеніших застосувань TensorFlow та Keras є розпізнавання та класифікація зображень. Якщо ви хочете дізнатися, як використовувати Keras для класифікації або розпізнавання зображень, ця стаття навчить вас, як це робити.

Визначення

Якщо ви не розумієте основні концепції розпізнавання зображень, вам буде складно повністю зрозуміти основну частину цієї статті. Тому перш ніж ми продовжимо, давайте визначимося з термінологією.


TensorFlow / Keras

TensorFlow - це бібліотека з відкритим кодом, створена для Python командою Google Brain. TensorFlow компілює безліч різних алгоритмів та моделей, дозволяючи користувачеві реалізувати глибокі нейронні мережі для використання в таких завданнях, як розпізнавання та класифікація зображень, а також обробка природної мови. TensorFlow - це потужний фреймворк, який функціонує шляхом реалізації ряду вузлів обробки, кожен з яких представляє математичну операцію, а низка вузлів називається «графом».

Говорячи про Keras, це високорівневий API (інтерфейс прикладного програмування), який може використовувати функції TensorFlow (також інші бібліотеки ML, такі, як Theano). Keras був розроблений з зручністю та модульністю як керівні принципи. З практичної точки зору Keras дозволяє реалізувати безліч потужних, але найчастіше складних функцій TensorFlow максимально просто, до того ж він налаштований для роботи з Python без серйозних змін або налаштувань.

Розпізнавання зображень (класифікація)

Розпізнавання зображення відноситься до завдання введення зображення в нейронну мережу та присвоєння будь-якої мітки для цього зображення. Мітка, яку виводить мережа, відповідатиме заздалегідь певному класу. Може бути присвоєно як кілька класів, і лише один. Якщо є лише один клас, зазвичай застосовується термін «розпізнавання», тоді як завдання розпізнавання кількох класів часто називається «класифікацією».

Підмножина класифікацій зображень є вже визначенням об'єктів, коли певні екземпляри об'єктів ідентифікуються як такі, що належать до певного класу, наприклад, тварини, автомобілі або люди.

Яскравим прикладом такої класифікації є рішення найпоширенішої капчі — ReCaptcha v2 від Google, де з набору картинок необхідно вибрати ті, що належать до вказаного в описі класу.

Функція вилучення

Щоб виконати розпізнавання або класифікацію зображень, нейронна мережа повинна витягти ознаки. Ознаки - це елементи даних, які становлять максимальний інтерес і які будуть передаватися по нейромережі. У конкретному випадку розпізнавання зображень такими ознаками є групи пікселів, такі як лінії та точки, які мережа аналізуватиме на наявність патерну.

Розпізнавання ознак (або вилучення ознак) - це процес отримання відповідних ознак з вхідного зображення, щоб їх можна було проаналізувати. Багато зображень містять анотації або метадані, які допомагають нейромережі знаходити відповідні ознаки.

Як нейронні мережі вчаться розпізнавати зображення

Розуміння про те, як нейронна мережа розпізнає зображення, допоможе вам при реалізації моделі нейронної мережі, тому коротко розглянемо процес розпізнавання зображень у наступних розділах.

Вилучення ознак за допомогою фільтрів

Перший шар нейронної мережі приймає всі пікселі у зображенні. Після того як всі дані введені в мережу, до зображення застосовуються різні фільтри, які формують розуміння різних частин зображення. Це витяг ознак, що створює «карти ознак».

Цей процес отримання ознак із зображення виконується за допомогою «згорткового шару», і згортка просто формує уявлення частини зображення. Саме з цієї концепції згортки ми отримуємо термін "Згорткова нейронна мережа" (Convolutional Neural Network, CNN) - тип нейронної мережі, що найчастіше використовується в класифікації та розпізнаванні зображень.

Якщо ви хочете візуалізувати, як саме працює створення карт ознак, уявіть собі процес піднесення ліхтарика до зображення у темній кімнаті. Коли ви ковзаєте променем на картинці, ви дізнаєтеся про особливості зображення. Фільтр - це те, що мережа використовує для формування уявлення про зображення, і в цій метафорі світло від ліхтарика є фільтром.

Ширина променя ліхтарика визначає розмір фрагмента зображення, який ви переглядаєте за один раз, і нейронні мережі мають аналогічний параметр - розмір фільтра. Розмір фільтра впливає те, скільки пікселів перевіряється за один раз. Загальний розмір фільтра, використовуваного CNN, дорівнює 3, і він охоплює як висоту, так і ширину, тому фільтр перевіряє область пікселів 3 x 3.

У той час як розмір фільтра покриває висоту та ширину фільтра, глибина фільтра також має бути вказана.

Але як 2D зображення може мати глибину?

Справа в тому, що цифрові зображення відображаються у вигляді висоти, ширини і деякого значення RGB, яке визначає колір пікселя, тому «глибина», що відстежується, - це кількість колірних каналів, які має зображення. Зображення в градаціях сірого (не кольорові) мають лише 1 кольоровий канал, у той час як кольорові зображення мають глибину 3 канали.

Все це означає, що для фільтра розміром 3, застосованого до повнокольорового зображення, підсумкові розміри цього фільтра будуть 3 x 3 x 3. Для кожного пікселя, охоплюваного цим фільтром, мережа множить значення фільтра на значення самих пікселів, щоб отримати числове уявлення цього пікселя . Потім цей процес виконується для всього зображення, щоб отримати повне уявлення. Фільтр переміщається по решті зображення відповідно до параметра, званого «крок», який визначає, на скільки пікселів повинен бути переміщений фільтр після того, як він обчислить значення у своїй поточній позиції. Нормальний розмір кроку для CNN - 2.

Кінцевим результатом усіх цих розрахунків є карта ознак. Цей процес зазвичай виконується з кількома фільтрами, які допомагають зберегти складність зображення.

Функції активації

Після того, як карта ознак зображення була створена, значення, що представляють зображення передаються через функцію активації або шар активації. Функція активації приймає ці значення, які завдяки згортковому шару перебувають у лінійній формі (тобто список чисел) і збільшує їх нелінійність, оскільки самі зображення є нелінійними.

Типовою функцією активації, що використовується для досягнення цієї мети, є випрямлена лінійна одиниця (ReLU), хоча є деякі інші функції активації, які також іноді використовуються (ви можете прочитати про них тут .

Об'єднання шарів

Після активації дані відправляються через шар, що об'єднує. Об'єднання "спрощує" зображення: бере інформацію, яка представляє зображення, і стискає її. Процес об'єднання в пул робить мережу гнучкішою і здатною краще розпізнавати об'єкти та зображення на основі відповідних функцій.

Коли ми дивимося на зображення, нас зазвичай хвилює не вся інформація (наприклад, що на задньому плані зображення), а лише ознаки, які нас цікавлять — люди, тварини тощо.

Аналогічно, що об'єднує шар CNN позбавиться від непотрібних частин зображення, залишивши тільки ті частини, які він вважає релевантними, в залежності від заданого розміру об'єднуючого шару.

Оскільки мережа повинна приймати рішення щодо найважливіших частин зображення, розрахунок йде те що, що вона вивчить лише частини зображення, які справді представляють суть аналізованого об'єкта. Це допомагає запобігти “перенавченню” — коли мережа надто добре вивчає всі аспекти навчального прикладу і вже не може узагальнювати нові дані, оскільки враховує нерелевантні відмінності.

Існують різні способи поєднання значень, але найчастіше використовується максимальне об'єднання. Максимальне об'єднання має на увазі взяття максимального значення серед пікселів у межах одного фільтра (у межах одного фрагмента зображення). Це відсіює 3/4 інформації за умови використання фільтра розміром 2 x 2.

Максимальні значення пікселів використовуються для врахування можливих спотворень зображення, а кількість параметрів (розмір зображення) зменшено, щоб контролювати перенавчання. Існують інші принципи об'єднання, такі як середнє чи сумарне об'єднання, але вони використовуються не так часто, оскільки максимальне об'єднання дає більшу точність.

Стиснення

Останні шари нашої CNN – щільно пов'язані шари – вимагають, щоб дані були представлені у формі вектора для подальшої обробки. З цієї причини дані необхідно «звести докупи». Для цього значення стискаються у довгий вектор або стовпець послідовно впорядкованих чисел.

Повністю пов'язаний шар

Кінцеві шари CNN є щільно пов'язані шари або штучну нейронну мережу (Artificial neural networks (ANN)). Основною функцією ANN є аналіз вхідних ознак та об'єднання їх у різні атрибути, які допоможуть у класифікації. Ці шари утворюють набори нейронів, які представляють різні частини об'єкта, що розглядається, а набір нейронів може являти собою, наприклад, висячі вуха собаки або почервоніння яблука. Коли достатня кількість цих нейронів активується у відповідь вхідне зображення, воно буде класифіковано як об'єкт.

Помилка або різниця між розрахованими значеннями та очікуваним значенням у навчальному наборі розраховується за допомогою ANN. Потім мережа піддається методу зворотного поширення помилки, де розраховується вплив даного нейрона на нейрон у наступному шарі та потім його вплив (вага) коригується. Це зроблено для оптимізації продуктивності моделі. Цей процес повторюється знову і знову: так мережа навчається на даних та вивчає зв'язки між вхідними ознаками та вихідними класами.

Нейрони середніх пов'язаних шарах виводитимуть двійкові значення, які стосуються можливим класам. Якщо у вас є чотири різні класи (скажімо, собака, машина, будинок і людина), нейрон матиме значення "1" для класу, який, як він вважає, представляє зображення, і значення "0" для інших класів.

Кінцевий повністю пов'язаний шар, отримавши вихідні дані попереднього шару, надає можливість кожному з класів у межах одиниці (у сукупності). Якщо категорії «собака» надано значення 0,75 — це означає 75% ймовірність того, що зображення є собакою.

Робочий процес машинного навчання

Перш ніж ми перейдемо наприклад навчання класифікатора зображень, давайте приділимо трохи часу розумінню робочого процесу або "конвеєра" машинного навчання. Процес навчання моделі нейронної мережі є досить стандартним і може бути поділений на чотири різні етапи.

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

Підготовка данних

По-перше, вам потрібно буде зібрати свої дані та оформити їх так, щоб нейромережа смола навчатися на них. Це включає збір зображень і їх маркування. Навіть якщо ви завантажили набір даних, підготовлений кимось іншим, то швидше за все вам все одно буде потрібно попередня обробка або підготовка, перш ніж ви зможете використовувати його для навчання. Підготовка даних - це мистецтво саме собою, пов'язане з вирішенням таких проблем, як пропущені значення, пошкоджені дані, дані в неправильному форматі, неправильні мітки і т.д.

У цій статті ми використовуватимемо попередньо оброблений набір даних.

Створення моделі

Створення моделі нейронної мережі включає вибір різних параметрів та гіперпараметрів. Ви повинні прийняти рішення про кількість шарів, що використовуються у вашій моделі, про те, яким буде розмір вхідних та вихідних шарів, які функції активації ви використовуватимете, чи використовуватимете виняток (Dropout) і т.д.

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

Навчання моделі

Після того, як ваша модель створена, вам просто залишається створити екземпляр моделі та підігнати його до своїх даних для навчання. Найбільша увага під час навчання моделі приділяється кількості необхідного на навчання часу. Ви можете вказати тривалість навчання мережі, задавши кількість епох навчання. Чим довше ви тренуєте модель, тим вища її ефективність, але якщо використовувати занадто багато епох навчання – ви ризикуєте перенавчити модель.

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

Оцінка моделі

Існує кілька кроків для оцінки моделі. Першим кроком є порівняння продуктивності моделі з набором перевірочних даних: тих даних, у яких модель була навчена. Таким чином, ви перевірите роботу моделі з цим новим набором даних та проаналізуєте її ефективність за допомогою різних показників.

Існують різні метрики для визначення продуктивності моделі нейронної мережі, але найпоширенішою є «точність», тобто кількість правильно класифікованих зображень, поділена на загальну кількість зображень у вашому наборі даних.

Після того, як ви побачите точність моделі в перевірочному наборі даних, ви, ймовірно, знову повернетеся і до-навчите мережу, використовуючи злегка підправлені параметри, оскільки навряд чи будете задоволені ефективністю своєї мережі при першому тренуванні. Ви будете продовжувати налаштовувати параметри своєї мережі, повторно навчати її та вимірювати ефективність, доки не будете задоволені точністю мережі.

Нарешті ви перевірите ефективність мережі на тестовому наборі. Це ще один набір даних, що ваша модель ніколи не бачила раніше.

Можливо вам цікаво: навіщо потрібен ще один тестовий набір даних? Адже ви вже отримали уявлення про точність вашої моделі, хіба це не було метою “перевірочного набору”?

Вся справа в тому, що всі зміни параметрів, які ви виробляли, доналаштовуючи мережу під час роботи з “перевірним набором даних” у поєднанні з багаторазовим повторним тестуванням цього набору, могли призвести до того, що ваша мережа вивчила деякі особливості набору, але при цьому вона не буде так само узагальнювати дані поза вибіркою. Саме тому слід надати мережі абсолютно нові тестові дані.

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

Розпізнавання зображень з CNN

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

Спочатку нам знадобиться набір даних для навчання. У цьому прикладі ми будемо використовувати відомий набір даних CIFAR-10. CIFAR-10 - це великий набір даних, що містить понад 60 000 зображень, що представляють 10 різних класів об'єктів, таких як кішки, літаки та автомобілі.

Зображення є повнокольоровими RGB, але вони досить малі, всього 32 x 32. Відмінною особливістю набору даних CIFAR-10 є те, що він постачається в комплекті з Keras, тому завантажити набір даних дуже просто, а самі зображення потребують лише мінімальної попередньої обробки.

Перше, що ми маємо зробити, це імпортувати необхідні бібліотеки. Ви ще побачите, як саме цей імпорт відбувається по ходу справи, а поки що просто майте на увазі, що ми будемо використовувати Numpy та різні модулі, пов'язані з Keras:

import numpy
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, BatchNormalization, Activation
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.constraints import maxnorm
from keras.utils import np_utils

Ми збираємося використовувати випадковий SEED (симетричний блоковий криптоалгоритм на основі Мережі Фейстеля), щоб результати, отримані в цій статті, могли бути відтворені вами, тому нам потрібен numpy:

# Set random seed for purposes of reproducibility
seed = 21

Підготовка данних

Тепер нам потрібно зробити ще один імпорт: сам набір даних.

from keras.datasets import cifar10

Тепер завантажимо набір даних. Ми можемо зробити це просто вказавши, які змінні ми хочемо завантажити дані, а потім використовувати функцію load_data():

# loading in the data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()

У більшості випадків вам потрібно виконати деяку попередню обробку даних, щоб підготувати їх до використання, але оскільки ми використовуємо вже готовий і упакований набір даних, то така обробка зведена до мінімуму. Однією з дій, які хочемо зробити, буде нормалізація вхідних даних.

Якщо значення вхідних даних знаходяться в широкому діапазоні, це може негативно вплинути на роботу мережі. У нашому випадку вхідними значеннями є пікселі у зображенні, які мають значення від 0 до 255.

Таким чином, щоб нормалізувати дані, ми можемо просто розділити значення зображення на 255. Для цього нам спочатку потрібно перевести дані у формат з плаваючою комою, оскільки вони є цілими числами. Ми можемо зробити це, використовуючи Numpy команду astype(), а потім оголосити бажаний тип даних:

# normalize the inputs from 0-255 to between 0 and 1 by dividing by 255
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train = X_train / 255.0
X_test = X_test / 255.0

Наступна річ, яку нам потрібно зробити, щоб підготувати дані для мережі - перевести їх в унітарний код. Не будемо вдаватися до подробиць унітарного кодування, але знайте, що зображення не можуть використовуватися нейромережею у тому вигляді, в якому вони є — їх потрібно спочатку кодувати, а найкраще при проведенні двійкової класифікації використовувати саме унітарне кодування.

Ми успішно застосовуємо тут двійкову класифікацію, тому що зображення або належить одному певному класу, або ні: воно не може бути посередині. Для унітарного кодування використається команда Numpy to_categorical(). Саме тому ми імпортували функцію np_utils з Keras, оскільки вона містить to_categorical().

Нам також потрібно задати кількість класів у наборі даних, щоб ми зрозуміли, до скільки нейронів стискати кінцевий шар:

# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
class_num = y_test.shape[1]

Проектування моделі

Ми досягли стадії проектування моделі CNN. Перше, що потрібно зробити, це визначити формат, який хотіли б використовувати для моделі. У Keras є кілька різних форматів (планів) для побудови моделей, але найчастіше використовується Sequential – тому ми імпортували його з Keras.

Створення моделі

model = Sequential()

Перший шар нашої моделі – це згортковий шар. Він прийматиме вхідні дані та пропускатиме їх через згорткові фільтри.

При реалізації цього в Keras, ми повинні вказати кількість каналів (фільтрів), які нам потрібні (а це 32), розмір фільтра (3 x 3 у нашому випадку), форму входу (при створенні першого шару), функцію активації та відступи.

Як згадувалося, relu є найпоширенішою функцією активації, а відступи ми визначимо через padding = 'same', тобто, ми змінюємо розмір зображення:

model.add(Conv2D(32, (3, 3), input_shape=X_train.shape[1:], padding='same'))
model.add(Activation('relu'))

Примітка: Ви також можете об'єднати в один рядок потрібні команди, наприклад:

model.add(Conv2D(32, (3, 3), input_shape=(3, 32, 32), activation='relu', padding='same'))

Тепер ми створимо виключний шар для запобігання перенавченню, який випадково усуває з'єднання між шарами (0,2 означає, що він відкидає 20% існуючих з'єднань):

model.add(Dropout(0.2))

Також ми можемо здійснити пакетну нормалізацію. Пакетна нормалізація нормалізує вхідні дані, що надходять у наступний шар, гарантуючи, що мережа завжди створює функції активації з тим самим розподілом, який нам потрібний:

model.add(BatchNormalization())

Тепер слід ще один згортковий шар, але розмір фільтра збільшується, так що мережа вже може вивчати складніші уявлення:

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))

А ось і шар, що об'єднує, який, як обговорювалося раніше, допомагає зробити класифікатор зображень коректнішим, щоб він міг вивчати релевантні шаблони. Також опишемо виняток (Dropout) та пакетну нормалізацію:

model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(BatchNormalization())

Це основа робочого процесу у першій частині реалізації CNN: згортка, активація, виняток, об'єднання. Тепер ви розумієте, навіщо ми імпортували Dropout, BatchNormalization, Activation, Conv2d та MaxPooling2d.

Ви можете варіювати кількість згорткових шарів на свій смак, але кожен з них збільшує обчислювальні витрати. Зверніть увагу, що при додаванні згорткових шарів ви зазвичай збільшуєте і кількість фільтрів, щоб модель могла вивчити складніші уявлення. Якщо числа, вибрані для цих шарів, здаються дещо довільними, то просто знайте, що рекомендується збільшувати фільтри поступово, встановлюючи значення 2 ступенем (2^n), що може дати невелику перевагу при навчанні моделі на GPU.

Важливо не мати занадто багато рівнів, що об'єднують, тому що кожен з них відкидає частину даних. Занадто часто об'єднання призведе до того, що щільно пов'язані шари майже нічого не дізнаються, коли дані досягнуть їх.

Необхідна кількість шарів, що об'єднують, залежить від виконуваного завдання - це те, що ви визначите з часом. Оскільки зображення в нашому наборі вже досить малі, ми не об'єднуватимемо їх більше двох разів.

Тепер ви можете повторити ці шари, щоб дати вашій мережі більше уявлень для роботи:

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Conv2D(128, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())

Після того, як ми закінчили з шарами згортки, нам потрібно стиснути дані, тому ми імпортували функцію Flatten вище. Ми також додамо шар виключення знову:

model.add(Flatten())
model.add(Dropout(0.2))

Тепер ми використовуємо імпортовану функцію Dense та створюємо перший щільно пов'язаний шар. Нам потрібно вказати кількість нейронів у щільному шарі. Зверніть увагу, що кількість нейронів у наступних шарах зменшується, в кінцевому підсумку наближаючись до того ж числа нейронів, що і класи в наборі даних (в даному випадку 10). Обмеження ядра може впорядкувати дані в процесі навчання, що також допомагає запобігти перенавченню. Ось чому ми імпортували maxnorm раніше.

model.add(Dense(256, kernel_constraint=maxnorm(3)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(128, kernel_constraint=maxnorm(3)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())

У цьому останньому шарі ми зрівнюємо кількість класів із числом нейронів. Кожен нейрон представляє клас, тому на виході цього шару буде вектор з 10 нейронів, кожен з яких зберігає певну ймовірність того, що зображення, що розглядається, належить його класу.

Нарешті, функція активації softmax вибирає нейрон з найбільшою ймовірністю як своє вихідне значення, припускаючи, що зображення належить саме цьому класу:

model.add(Dense(class_num))
model.add(Activation('softmax'))

Тепер коли ми розробили модель, яку хочемо використовувати, залишається лише скомпілювати її. Вкажемо кількість епох для навчання, а також оптимізатор, який ми хочемо використати.

Оптимізатор - це те, що налаштує ваги у вашій мережі так, щоб наблизитись до точки з найменшими втратами. Алгоритм Адама є одним з найчастіше використовуваних оптимізаторів, тому що він дає високу продуктивність у більшості завдань:

epochs = 25
optimizer = 'adam'

Тепер скомпілюємо модель із вибраними параметрами. Давайте вкажемо також метрику для оцінки.

model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])

Ми також можемо роздрукувати зведення за моделлю, щоб отримати уявлення про модель в цілому.

print(model.summary())

Роздрукування зведення дасть нам деяку інформацію:

Results:

Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 32, 32, 32) 896
_________________________________________________________________
activation_1 (Activation) (None, 32, 32, 32) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 32, 32, 32) 0
_________________________________________________________________
batch_normalization_1 (Batch (None, 32, 32, 32) 128
_________________________________________________________________
conv2d_2 (Conv2D) (None, 32, 32, 64) 18496
_________________________________________________________________
activation_2 (Activation) (None, 32, 32, 64) 0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 64) 0
_________________________________________________________________
dropout_2 (Dropout) (None, 16, 16, 64) 0
_________________________________________________________________
batch_normalization_2 (Batch (None, 16, 16, 64) 256
_________________________________________________________________
conv2d_3 (Conv2D) (None, 16, 16, 64) 36928
_________________________________________________________________
activation_3 (Activation) (None, 16, 16, 64) 0
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64) 0
_________________________________________________________________
dropout_3 (Dropout) (None, 8, 8, 64) 0
_________________________________________________________________
batch_normalization_3 (Batch (None, 8, 8, 64) 256
_________________________________________________________________
conv2d_4 (Conv2D) (None, 8, 8, 128) 73856
_________________________________________________________________
activation_4 (Activation) (None, 8, 8, 128) 0
_________________________________________________________________
dropout_4 (Dropout) (None, 8, 8, 128) 0
_________________________________________________________________
batch_normalization_4 (Batch (None, 8, 8, 128) 512
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
_________________________________________________________________
dropout_5 (Dropout) (None, 8192) 0
_________________________________________________________________
dense_1 (Dense) (None, 256) 2097408
_________________________________________________________________
activation_5 (Activation) (None, 256) 0
_________________________________________________________________
dropout_6 (Dropout) (None, 256) 0
_________________________________________________________________
batch_normalization_5 (Batch (None, 256) 1024
_________________________________________________________________
dense_2 (Dense) (None, 128) 32896
_________________________________________________________________
activation_6 (Activation) (None, 128) 0
_________________________________________________________________
dropout_7 (Dropout) (None, 128) 0
_________________________________________________________________
batch_normalization_6 (Batch (None, 128) 512
_________________________________________________________________
dense_3 (Dense) (None, 10) 1290
_________________________________________________________________
activation_7 (Activation) (None, 10) 0
=================================================================
Total params: 2,264,458
Trainable params: 2,263,114
Non-trainable params: 1,344

Тепер ми розпочинаємо навчання моделі. Для цього нам потрібно викликати функцію fit() для моделі та передати вибрані параметри.

Ось де використовується SEED, вибраний для відтворення.

numpy.random.seed(seed)
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=64)

Візьмемо тренувальний набір 50000 зразків і перевірочний 10000 зразків.

Запуск цього шматка коду дасть:

Epoch 1/25

64/50000 [..............................] - ETA: 16:57 - loss: 3.1479 - acc: 0.0938
128/50000 [..............................] - ETA: 10:12 - loss: 3.0212 - acc: 0.0938
192/50000 [..............................] - ETA: 7:57 - loss: 2.9781 - acc: 0.1250
256/50000 [..............................] - ETA: 6:48 - loss: 2.8830 - acc: 0.1484
320/50000 [..............................] - ETA: 6:07 - loss: 2.8878 - acc: 0.1469
384/50000 [..............................] - ETA: 5:40 - loss: 2.8732 - acc: 0.1458
448/50000 [..............................] - ETA: 5:20 - loss: 2.8842 - acc: 0.1406

...
...
...

49664/50000 [============================>.] - ETA: 1s - loss: 1.5160 - acc: 0.4611
49728/50000 [============================>.] - ETA: 1s - loss: 1.5157 - acc: 0.4612
49792/50000 [============================>.] - ETA: 1s - loss: 1.5153 - acc: 0.4614
49856/50000 [============================>.] - ETA: 0s - loss: 1.5147 - acc: 0.4615
49920/50000 [============================>.] - ETA: 0s - loss: 1.5144 - acc: 0.4617
49984/50000 [============================>.] - ETA: 0s - loss: 1.5141 - acc: 0.4617
50000/50000 [==============================] - 262s 5ms/step - loss: 1.5140 - acc: 0.4618 - val_loss: 1.0715 - val_acc: 0.6195

End of Epoch 1

Зверніть увагу, що в більшості випадків вам потрібно мати перевірочний набір, відмінний від набору для тестування, тому ви повинні вказати відсоток даних навчання, які будуть використовуватися як набір для перевірки. У цьому випадку ми просто передаємо тестові дані, щоб переконатися, що тестові дані відкладені і не використовувалися для навчання. У цьому прикладі ми матимемо лише тестові дані, щоб усе було простіше.

Тепер ми можемо оцінити модель та подивитися, як вона працює. Просто викличте model.evaluate():

# Model evaluation
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

І ось ми отримуємо результат:

Accuracy: 83.01%

Ну от і все! Тепер у нас є навчена розпізнавання зображень CNN. Непогано для першого запуску, але ви, ймовірно, захочете поекспериментувати зі структурою моделі та параметрами, щоб спробувати досягти кращої ефективності.

Практичне застосування нейромереж для розпізнавання капч

Теоретичні та експериментальні роботи з CNN закономірно підводять до варіантів використання нейромереж для вирішення практичних повсякденних завдань. Найбільш актуальним у сфері розпізнавання та класифікації зображень є завдання щодо вирішення капчі, зокрема найпопулярнішою на сьогоднішній день Google ReCaptcha v2.

Незважаючи на схожість з нашим прикладом, на практиці реалізувати робочу нейромережу для вирішення капчі є вкрай витратним і неефективним рішенням через постійно змінний набір даних (картинок у капчі). Настільки часте і непередбачуване оновлення вхідних даних тягне за собою цілу низку проблем:

  • необхідність регулярно збирати та обробляти нові дані
  • необхідність постійного контролю процесу з боку людини та внесення правок у модель по ходу роботи (включаючи експерименти з параметрами)
  • Необхідність потужного обладнання для навчання моделі 24/7
  • і т.д.

Універсальне вирішення проблеми обходу різних капч онлайн

Для вирішення капч у безперервному режимі, з високою швидкістю та порівняно низькою вартістю — великим попитом користуються онлайн сервіси розпізнавання капч, які приваблюють для цього реальних користувачів. На вітчизняному ринку лідером є сервіс RuCaptcha.com, який вигідно відрізняється від конкурентів:
Висока точність (до 99%) і швидкість рішень (12 секунд для звичайних текстових капч і 24 секунди для ReCaptcha)
прийнятними фіксованими цінами (ціна не зростає при збільшенні навантаження на сервери сервісу): 35 рублів за 1000 рішень звичайних капч і 160 рублів за 1000 рішень ReCaptcha
поверненням коштів за рідкісні неуспішні розпізнавання
технічною можливістю вирішувати величезні обсяги капч (більше 10,000 за хвилину)
простим та функціональним API
готовими бібліотеками та зразками коду для різних мов програмування
* привабливою партнерської програмою, що дозволяє розробникам та рефоводам отримувати до 15% від витрат залучених клієнтів і 10% від доходів залучених у обслуговування працівників.

Будь-які питання щодо роботи сервісу — оперативно вирішуються службою підтримки через систему тикетів.

Висновок

Що ж, тепер, коли ви реалізували свою першу мережу розпізнавання зображень в Keras, було б непогано пограти з моделлю і подивитися, як зміна її параметрів впливає на ефективність.

Це дасть вам деяке інтуїтивне розуміння оптимальних значень різних параметрів моделі. Ви повинні також вивчити різні варіанти параметрів та гіперпараметрів, працюючи над своєю моделлю. Після того, як ви ґрунтовно освоїтеся, ви можете спробувати реалізувати власний класифікатор зображень вже на іншому наборі даних.

Що ж до рутинних практичних робочих завдань, як, наприклад, розпізнавання капчі — створення та навчання нейромережі навряд чи є гнучким та ефективним рішенням. Значно швидше, дешевше та зручніше використовувати для таких цілей онлайн-сервіс RuCaptcha.com .

Сервис распознавания капчи Rucaptcha
Сервис распознавания капчи Rucaptcha
Качественный и быстрый сервис по приемлемым ценам

Вам це подобається? Поділіться в соціальних мережах!

Vladimir Sergeevich
  • 14 травня 2020 р. 04:37

Собственно, а что исходников то нет?

Evgenii Legotckoi
  • 14 травня 2020 р. 04:51
  • (відредаговано)

Большая кнопка GITHUB РЕПОЗИТОРИЙ ни о чём не говорит?

Vladimir Sergeevich
  • 14 травня 2020 р. 06:58

Окей, нашел (возможно глаза привыкают к тому, что на сайтах мелькают объявления и большие яркие кнопки автоматически игнорируются). Но не нашел данные на которых обучалась нейросеть. Без них повторить "это" я все равно не смогу ведь...

Evgenii Legotckoi
  • 14 травня 2020 р. 07:17

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

Что касается исходных данных, то извини, тут не помогу, есть причины, почему они не приложены. Ок?

Vladimir Sergeevich
  • 14 травня 2020 р. 07:21

Ок :)

BG
  • 26 травня 2020 р. 21:24

Спасибо за Ваш труд, очень крутой у вас ресурс, особенно нравятся статьи по Django!

Evgenii Legotckoi
  • 27 травня 2020 р. 01:19

Не тому написали, ну да ладно )) Спасибо за отзыв :D

BG
  • 28 травня 2020 р. 04:38

будем считать что авторы статьи по django примут на свой счет :D

progammist
  • 05 червня 2020 р. 11:52
  • (відредаговано)

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

R
  • 15 квітня 2021 р. 11:55

R
  • 15 квітня 2021 р. 11:56

почему то вместо 50000 обрабатывает по 782 картинки кажду. эпоху

4X_Pro
  • 25 серпня 2021 р. 09:39
  • (відредаговано)

"может ли бесплатный ресурс жить без рекламных сетей?"

А в чём проблема-то? Если не жалко тратить пару-тройку сотен рублей на хостинг/VDS в месяц, то любой сайт прекрасно существует без всякой рекламы сколь угодно долго.

Статья очень понравилась! Как раз искал пример, где работа с изображениями с помощью нейросети расписана по шагам для начинающих.

Evgenii Legotckoi
  • 25 серпня 2021 р. 10:20

Время на развитие, трудозатраты на разработку, ответы на специализированные вопросы и т.д. вы видимо в расчёт не берёте.

4X_Pro
  • 25 серпня 2021 р. 12:02

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

Evgenii Legotckoi
  • 25 серпня 2021 р. 15:26

Собственное время не бесплатно, поскольку бесценно и не возобновимо. И не все это понимают, а Вы понимаете?
А поддержание подобного ресурса со временем становится накладным, сколько бы удовольствия он не приносил, это не личный бложик обо всём и ни о чём. Я много раз порывался писать статьи обо всякой ерунде, но останавливал себя, поскольку это не то место, чтобы устраивать здесь свой дневник. Это специализированный ресурс, а подготовка специализированной статьи порой занимает много времени.
И при всём своём желании его развивать, у меня нет желания делать это в ущерб личной жизни. Поэтому со временем такой ресурс либо монетизируется и все силы бросаются на него, либо застывает без новых статей и нового материала, как сейчас.
Так что делайте выводы сами. Но далее обсуждать это не буду, это оффтоп и пустое столкновение мнений.

4X_Pro
  • 26 серпня 2021 р. 07:32

Понимаю. А ещё понимаю, что не потратить время нельзя. День всё равно пройдёт, и вопрос только в том, на что он будет потрачен: на то, что приносит в жизни удовольствие или нет.
Насчёт застывает — ничего страшного в этом нет (кроме негативного влияния на SEO). Я, например, у себя на сайте в некоторые разделы пишу 2—3 раза в год, когда есть идеи, вдохновение и желание поделиться информацией, и считаю это совершенно нормальным.
Впрочем, похоже, мы и правда не поймём друг друга. Слишком разная система жизненных ценностей. Так что оставлю вас в покое.

МА
  • 26 жовтня 2022 р. 13:16

А что собственно выводит программа, как вывести то что она смогла распознать?

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
г
  • ги
  • 24 квітня 2024 р. 01:51

C++ - Тест 005. Структуры и Классы

  • Результат:41бали,
  • Рейтинг балів-8
l
  • laei
  • 23 квітня 2024 р. 19:19

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:10бали,
  • Рейтинг балів-10
l
  • laei
  • 23 квітня 2024 р. 19:17

C++ - Тест 003. Условия и циклы

  • Результат:50бали,
  • Рейтинг балів-4
Останні коментарі
k
kmssr09 лютого 2024 р. 05:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 12:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 21:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 19:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 грудня 2023 р. 08:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
Gar22 квітня 2024 р. 15:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 квітня 2024 р. 17:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 квітня 2024 р. 16:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 12:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex04 квітня 2024 р. 14:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Слідкуйте за нами в соціальних мережах