Телефонуйте » (+38) 096 227 41 41

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

Заняття передбачає покрокове виконання фрагментів коду, для чого будемо використовувати розглянуте в попередньому занятті середовище Jupyter Notebook, хоча можна просто скористатися інтерпретатором Python.

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

Визначимося з методикою підготовки даних і обговоримо структуру проекта.

Для початку відзначимо, що відомі набори даних MNIST і CIFAR-10 не будуть для нас цікавими прикладами. Вказані набори не дозволяють навчитися працювати зі своїми даними, а лише вчать, як користуватися вбудованими утилітами Keras, в яких навіть тренувальну і тестову виборку вже зроблено до нас.

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

- звідки завантажують дані додаткові функції?
- в якому форматі повинні бути зображення на диску?
- як завантажити власний набір даних в пам’ять?
- яке попереднє оброблення даних необхідно виконати?

Розберемося з усім цим.

Для початку, візьмемо готовий набір даних тварих, який складається з фотографій собак, котів і панд (рис.1).

Фрагменти набору зображень
Рис.1. Фрагменти набору зображень тварин для проекта

Мета - правильно класифікувати зображення кожної з тварин: кота, собаку чи панду.

Набір має 3000 зображень і буде первинним матеріалом, за допомогою якого ми зможемо швидко навчити модель Deep Learning (DL), використовуючи процесор комп’ютера (CPU) або відеокарту (GPU), і при цьому отримати прийнятну точність.

В процесі роботи з цим набором даних нам необхідно вивчити, як виконати наступні дії:

- упорядкувати свій набір зображень на диску;
- завантажити зображення і мітки класу з диска;
- розділити дані на тренувальну і тестову виборки;
- навчити свою першу нейромережу з Keras;
- оцінити свою модель на тестовій виборці;
- використати свою навчену модель в подальшому для зовсім нових даних.

Примітка. Якщо хочемо створити набір даних з доступних в Інтернеті зображень, то зробити це можна, наприклад, за допомогою пошуковика Google.

Структура проекта

Розкривши zip-архів до цього заняття (розмір архіва близько 246 МБ), ми отримаємо наступну структуру файлів і папок (рис. 2):

Структура файлів і папок навчального набору
Рис.2. Структура файлів і папок навчального набору

Як згадувалось раніше, ми працюємо з набором даних Animals. Зверніть увагу, як він розміщений в дереві проекта. Всередині animals/ знаходяться каталоги трьох класів: cats/, dogs/, panda/. В кожному з них є 1000 зображень, які відносяться до відповідного класу.

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

Далі йде каталог images/. В ньому три зображення для тестування моделі, які використаємо, щоб продемонструвати, як:

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

Папка output/ має три типа файлів, які створюються під час тренування:

⦁    .model: серіалізований файл моделі Keras, створений після навчання і який може використовуватися в подальших сценаріях виходу.
⦁    .pickle: серіалізований файл бінаризатора міток. Включає в себе об’єкт, до складу якого входять назви класів, і він пов'язаний з файлом моделі.
⦁    .png: в цій папці краще вcього завжди зберігати свої графіки тренування/тестування, оскільки вони відображають результат процесу.

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

Ми розглянемо чотирі .py файли:

⦁    Почнемо з навчання простої моделі за допомогою сценарію train_simple_nn.py.
⦁    В наступному занятті перейдемо до навчання SmallVGGNet, використовуючи сценарій train_vgg.py.
⦁    SmallVGGNet.py  - до нього входить клас SmallVGGNet (згорткова нейронна мережа - CNN).
⦁    В predict.py знаходиться зразок коду для завантаження моделі і файла мітки для розпізнавання зображень. Цей сценарій знадобиться лише після того, як ми успішно навчимо модель з достатньою точністю. Завжди корисно запускати його для перевірки моделі на зображеннях, яких немає у вхідних даних.

Установка Keras

Для роботи над проектом треба встановити Keras, TensorFlow і OpenCV.

Якщо у нас ще немає цього ПЗ, можемо скористатися простими кервництвами зі встановлення:

- керівництво з установки OpenCV (для Ubuntu, MacOS або Raspberry Pi).
- установка Kerasз TensorFlow. За допомогою pip можемо встановити Keras і TensorFlow швидше, ніж за дві хвилини. Наш комп’ютер або пристрій повинні бути достатньо продуктивними. Тому не рекомендується встановлювати ці пакети на Raspberry Pi, хоча на такому мінікомп’ютері можуть добре працювати вже навчені і не занадто об’ємні моделі.
- встановлення imutil, scikit-learn и matplotlib:

Код 1

Завантаження даних з диску

Завантаження даних в оперативну пам’ять
Рис.3 Завантаження даних в оперативну пам’ять

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

Код 2

Розглянемо інструменти, які використовуються в сценарії:

- matplotlib: готовий пакет для Python. В рядку 3 підключаємо бекенд “Agg”, який дозволяє зберігати графіки на диск.
- sklearn: бібліотека scikit-learn допоможе бінарізувати наші мітки, розділити дані на навчальну і тестову виборки та згенерувати звіт про навчання в терміналі.
- keras: високорівневий фронтенд для TensorFlow та інших бекендів глубокого навчання.
- imutils: пакет зі зручними функціями, модуль path буде використовуватися для генерування списку шляхів до файлів зображень.
- numpy: пакет для роботи з числами в Python. Якщо встановлені OpenCV і scikit-learn, то у нас вже є NumPy, як залежний від них пакет.
- cv2: це OpenCV. На даний час треба використовувати версію 2, навіть якщо ви зазвичай використовуєте OpenCV 3 або вище.

Все решта вже вбудовано в наш Python.

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

Розглянемо детальніше аргументи командного рядка за допомогою argparse:

Код 3

Наш сценарій буде динамічно обробляти з командного рядка інформацію, яка поступає під час виконання, за допомогою вбудованого в Python модуля argparse.

У нас є чотири аргумента командного рядка:

--dataset: шлях до набору зображень на диску.
--model: наша модель буде серіалізована і записана на диск. Даний аргумент вказує шлях до вихідного файла моделі.
--label-bin: мітки набору даних серіалізуются на диск для можливості їх виклику в інших сценаріях. Це шлях до вихідного бінарізованого файла мітки.
--plot: шлях до вихідного файла графіка навчання. Ми розглянемо цей графік, щоб перевірити недонавчання чи перенавчання наших даних.

Маючи інформацію про набір даних, давайте завантажимо зображення і мітки класів:

Код 4

Тут ми:

1.    Ініціалізуємо списки для наших даних (data) і міток (labels) (рядки 35 і 36). Пізніше це будуть масиви NumPy.
2.    Випадковим чином зображення перемішуємо imagePaths (рядки 39-41). Функція paths.list_images знайде шляхи до всіх вхідних зображень в каталозі нашого набору даних перед тим, як виконуємо сортування і перемішуємо (shuffle) їх. Встановимо постійне значення seed таким, щоб випадкове перевпорядкування було відновлюваним.
3.    Починаємо цикл по всім imagePaths в наборі даних (рядок 44).

Для кожного imagePath:

а) Завантажуємо зображення image в пам’ять (рядок 48).
б) Змінюємо його розмір на 32x32 пікселі (без врахування співвідношення сторін) і згладжуємо його (flatten) (рядок 49). Дуже важливо правильно змінити розмір зображень (resize), оскільки це необхідно для даної нейронної мережі. Кожна нейромережа вимагає різної роздільної здатності зображень, тому просто пам’ятайте про це. Згладжування даних дозволяє легко передавати необроблені інтенсивності пікселів в нейрони вхідного шару. Пізніше побачимо, що для VGGNet будемо передавати в мережу відразу всі дані, оскільки ця мережа є згортковою. Але в даному прикладі, поки що, розглядається проста незгорткова мережа.
в) Додаємо змінене зображення до масиву даних (рядок 50).
г) Витягуємо мітку класу зображення з його шляху (рядок 54) і додаємо до решти міток (рядок 55). Список міток зберігає класи, які відповідають кожному зображенню в масиві даних.

Тепер ми легко можемо застосувати операції з масивами до наших даних і міток:

Код 5

В рядку data відображаємо інтенсивність пікселя з діапазону цілих чисел [0, 255] в безперервний натуральний діапазон [0, 1] (звичайний етап попереднього оброблення).

Також конвертуємо мітки в масив NumPy (рядок 59).

Створення навчальної і тестової виборок

Розділення набору на два
Рис.4. Розділення набору на два: навчальну та тестову вибірки

Тепер, когда завантажили дані з диска, треба їх розділити на навчальну і тестову виборки:

Код 6

Зазвичай, більша частина даних виділяється для навчання, і близько 20-30%  - для тестування. Scikit-learn надає зручну функцію train_test_split, яка розділить для нас дані.
trainX і testX - це зображення, а trainY і testY - відповідні мітки.

Наші мітки класів зараз представлені у вигляді рядків, однак Keras буде вважати, що:

1.    Мітки кодуються цілими числами.
2.    Для цих міток виконується One-Hot Encoding, в результаті чого кожна мітка представляється у вигляді вектора, а не цілого числа.

Для того, щоб виконати це кодування, можна використати клас LabelBinarizer із scikit-learn:

Код 7

В рядку 70 ініціалізуємо об’єкт LabelBinarizer.

Виклик fit_transform знаходить всі унікальні мітки класу в testY, а потім перетворює їх в мітки One-Hot Encoding.
Виклик .transform виконує лише один крок One-Hot Encoding - унікальний набір можливих міток класів уже був визначений викликом fit_transform.

Приклад:

Код 8

Визначення архітектури моделі Keras

Проста нейронна мережа
Рис. 5. Проста нейронна мережа, створена за допомогою Keras

Наступний крок - визначення архітектури нашої нейронної мережі з використанням Keras. Будемо використовувати мережу з одним вхідним шаром, одним вихідним і двома схованими:

Код 9

Оскільки наша модель дуже проста, визначимо її прямо в сценарії (зазвичай для архітектури моделі доводиться створювати окремий клас).
Вхідний шар і перший схований шар визначені в рядку 76. input_shape буде рівний 3072, тому що маємо 32x32x3=3072 пікселів в згладженому вхідному зображенні.
Перший схований шар буде мати 1024 вузла.
Другий схований шар має 512 вузлів (рядок 77).
І, нарешті, кількість вузлів вихідного шару (рядок 78) буде рівна числу можливих міток класів - в нашому випадку, вихідний шар буде мати три вузла: один для кожної мітки класу (“cats”, “dogs” і “panda”, відповідно).

Компіляція моделі

Модель з оптимізатором та функцією втрат
Рис.6. Keras вимагає, щоб модель була зкомпілювана з оптимізатором та функцією втрат

Після того, як ми визначили архітектуру нашої нейронної мережі, треба зкомпілювати її:

Код 10

Спочатку ініціалізуємо швидкість навчання і загальне число епох (повних проходів по виборці) (рядки 81 і 82).

Потім зкомпілюємо модель, використовуючи метод стохастичного градієнтного спуску (SGD) і "categorical_crossentropy" (категорійну крос-ентропію) в якості функції втрат.
Категорійна крос-ентропія використовується майже для всіх нейромереж, навчених виконувати класифікацію. Єдиний виняток, коли маємо лише два класи і дві можливі мітки. В цьому випадку використовується бінарна крос-ентропія ("binary_crossentropy").

Тренування моделі

Тренування моделі глибокого навчання
Рис.7. Тренування моделі глибокого навчання з навчальними даними

Тепер, коли наша модель Keras зкомпільована, можемо “підігнати” (fit) (тобто. навчити) її:

Код 11

Тут нам відомо про все, крім batch_size (розмір пакета). Параметр batch_size контролює розмір кожної групи даних для передавання мережею. Потужні GPU можуть обробляти більші пакети, але рекомендується стартувати від розмірів 32 і 64.

Оцінювання моделі

 Використання даних тестування для прогнозуванн
Рис.8. Використання даних тестування для прогнозування та створення звіту

Ми навчили модель, тепер треба її оцінити за допомогою тестової виборки.

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

Для оцінювання моделі Keras можно використати комбінацію методів .predict і classification_report із scikit-learn:

Код 12

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

Процес тестування навченої моделі
Рис.9. Процес тестування навченої моделі

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

Можно побачити, що наша нейромережа точна на 61%.

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

- втрати при навчанні;
- втрати при оцінюванні;
- точність навчання;
- точність оцінювання.

З їх допомогою можемо визначити перенавчена чи недонавчена модель.

Графік точності/втрат
Рис.10. Сценарій тренувань генерує графік точності/втрат, щоб допомогти виявити недоліки

На графіку можно побачити невелике перенавчання, яке починається після кроку ~45, коли між втратами при навчанні і оцінкою з’являється явний розрив.

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

Код 13

Розпізнавання зображень з використанням навченої моделі

Зараз наша модель навчена - а якщо нам треба буде знову класифікувати нові зображення?
Як завантажити модель з диска?
Як обробити зображення для класифікації?

Для початку відкриємо сценарій predict.py і вставимо туди наступний код:

Код 14

Спочатку імпортуємо необхідні пакети і модулі.

load_model дозволяє завантажити модель Keras з диска. OpenCV буде використовуватися для виведення зображень. Модуль pickle завантажує бінаризатор міток.

Далі, знову розберемо аргументи командного рядка:

--image: шлях до вхідного зображення.
--model: шлях до нашої навченої і серіалізованої моделі.
--label-bin: шлях до бінаризатора міток.
--width: ширина зображення для CNN.
              Запам’ятайте, що тут не можна просто щось вказати. Необхідно вказати ширину, для якої призначена модель.
--height: висота вхідного зображення, яка також повинна відповідати конкретній моделі.
--flatten: чи потрібно згладжувати зображення (за замовчуванням ми цього робити не будемо).

Завантажимо зображення і змінимо його розмір, виходячи з аргументів командного рядка:

Код 15

Якщо необхідно, зображення можно згладити:

Код 16

У випадку з CNN ми вказуємо розмір пакета, але не виконуємо згладжування (рядки 39-41). Приклад з CNN розглядається в наступному занятті.

Тепер завантажимо нашу модель і бінаризатор міток в пам’ять і спробуємо розпізнати зображення:

Код 17

Модель і бінаризатор завантажуються в рядках 45 і 46.

Розпізнавання зображень (прогнозування належності об’єкта до одного з класів) здійснюється за допомогою метода model.predict (рядок 49).

Як же виглядає масив preds?

Двомірний масив має (1) індекс зображення в пакеті (тут він лише один, оскільки було передане одне зображення) і (2) відсотки, які відповідають ймовірності належності зображення до кожної мітки класу:

- cats: 54.6%
- dogs: 45.4%
- panda: ~0%

Тобто, наша нейромережа «думає», що, найімовірніше, бачить кота, і однозначно не бачить панду.

В рядку 53 знаходимо індекс найбільшого значення (в даному випадку нульовий).

А в рядку 54 витягуємо рядкову мітку “cats” із бінаризатора міток.

Все просто.

Тепер відобразимо результати:

Код 19

Форматуємо текстовий вивід в рядку 57 (мітку класа і прогнозоване значення у відсотках).
Потім розміщуємо текст на вихідне зображення (рядки 58 і 59).
Нарешті, виводимо картинку на екран і чекаємо, поки користувач не натисне будь яку клавішу (рядки 62 і 63).
Наш сценарій для розпізнавання зображень виявився досить простим.
Тепер можемо відкрити термінал і спробувати запустити навчену нейромережу на власних фотографіях:

Код 20

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

Кіт правильно класифікований за допомогою простої нейронної мережі
Рис.11. Кіт правильно класифікований за допомогою простої нейронної мережі

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

Примітка: Зверніть увагу, що отримані результати можуть відрізнятися від приведених в даному занятті. Швидше всього, це відбувається тому, що процес навчання щоразу може проходити по-різному навіть для одних і тих же вхідних даних. Наприклад, в нашому експерименті точність нейромережі зменшилась до 60%, і зображення з котом класифікувалось як “dogs” з ймовірністю 45.34%. Можливо, це залежить від послідовності перебору зображень при тренуванні, адже їх порядок носить випадковий характер.

Література

1. https://www.reg.ru/blog/keras/
2. https://www.pyimagesearch.com/2018/09/10/keras-tutorial-how-to-get-started-with-keras-deep-learning-and-python/

Попереднє заняття - Наступне заняття

Новини

  • SDR в IoT

    iotSDR пропонує платформу розробок для IoT-радіо та мережевих доменів. На платі два передавачі Microchip AT86RF215, для вводу-виводу модему на Xilinx ZYNQ SoC, приймач GNSS MAX2769 для GPS, Galileo, BieDou та Glonass. Плата сумісна з ПЗ GNURadio SDR. Дозволяє розробити протоколи фізичного рівня LoRa, SigFox, WightLess, Bluetooth, BLE, 802.15.4, ZigBee тощо для IoT, або шлюз IoT через TheThingsNetwork, LPWAN або Google Thread. Пам'ять EEPROM: 1x AT24MAC602 , flash-пам'ять: 1x QSPI 128 Мб, RAM: 256 MБ DDR3,слот для Micro SD карти, входи/виходи: 2x 8-бітних інтерфейси PL, інтерфейс 8-бітного PS, Gigabit Ethernet, USB 2.0 (USB3310), USB 2.0 (CP2104), 2x SMA RF-роз'єми для приймача діапазонів IoT, 2x SMA RF-роз'єми для приймача 2,4 ГГц , RF-роз'єм приймач GNSS, FPGA-роз'єм JTAG для програмування. Розміри плати: 76,2 мм x 101,6 мм.

     

    in Новини

Записатися на курс