Класифікація рукописних малюнків. Доповідь в Яндексі

Кілька місяців тому наші колеги з Google провели на Kaggle конкурс зі створення класифікатора зображень, отриманих у гучній грі "Quick, Draw!". Команда, у якій брав участь розробник Яндекса Роман Власов, посіла у конкурсі четверте місце. На січневому тренуванні з машинного навчання Роман поділився ідеями своєї команди, фінальною реалізацією класифікатора та цікавими практиками суперників.


- Всім привіт! Мене звуть Рома Власов, сьогодні я розповім вам про Quick, Draw! Doodle Recognition Challenge.

Класифікація рукописних малюнків. Доповідь в Яндексі

У нашій команді було XNUMX осіб. Я приєднався до неї прямо перед мерж-дедлайном. Нам не пощастило, нас трохи шийкапнуло, але нас шийкапнуло з money, а їх із позиції gold. І ми посіли почесне четверте місце.

(Під час змагання команди спостерігали себе у рейтингу, який формувався за результатами, показаними на одній частині запропонованого набору даних. Фінальний рейтинг, у свою чергу, формувався з іншої частини датасету. Так роблять, щоб учасники змагання не підлаштовували свої алгоритми під конкретні дані. Тому у фіналі, при перемиканні між рейтингами, позиції трохи «шийкаються» (від англ. shake up — перемішатися): на інших даних і результат може виявитися іншим Команда Романа спочатку була в трійці лідерів, у цьому випадку трійка — це money, грошова зона рейтингу, оскільки лише за перші три місця покладався грошовий приз. Після «шейк апа» команда опинилася вже на четвертому місці. Так само інша команда втратила перемогу, позицію gold. — Прим.

Класифікація рукописних малюнків. Доповідь в Яндексі

Також змагання було знаменним тим, що Євген Бабахнін отримав за нього грандмайстра, Іван Сосін — майстра, Роман Соловйов так і залишився грандмайстром, Алекс Парінов отримав майстра, я став експертом, а зараз я вже майстер.

Класифікація рукописних малюнків. Доповідь в Яндексі

Що це за Quick, Draw? Це сервіс від Google. Google мав на меті популяризувати ІІ і цим сервісом хотів показати, як нейронні мережі працюють. Ви туди заходите, натискаєте Let's draw, і вилазить нова сторінка, де вам кажуть: намалюйте зигзаг, у вас на це є 20 секунд. Ви намагаєтеся намалювати за 20 секунд зигзаг, як тут, наприклад. Якщо у вас все виходить, мережа каже, що це зигзаг і ви йдете далі. Таких картинок лише шість.

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

Цей сервіс зібрав досить багато користувачів, і всі картинки, які користувачі малювали, логувалися.

Класифікація рукописних малюнків. Доповідь в Яндексі

Вдалося зібрати майже 50 млн картинок. З цього формувався трейн та тест дата для нашого змагання. До речі, кількість даних у тесті та кількість класів не дарма виділено жирним шрифтом. Я про них розповім трохи згодом.

Формат даних був наступним. Це не просто RGB-картинки, а, грубо кажучи, лог всього, що робив користувач. Word - це наш таргет, countrycode - це те, звідки родом автор дудла, timestamp - час. Лейбл recognized показує те, розпізнала мережу від Google картинку чи ні. І сам drawing – послідовність, апроксимація кривої, яку користувач малює крапками. І таймінги. Це час від початку малювання картинки.

Класифікація рукописних малюнків. Доповідь в Яндексі

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

Дані були розподілені в такий спосіб. Все поступово, але є деякі викиди. Коли ми вирішували завдання, то цього не дивилися. Головне, що не було тих класів, яких реально мало, нам не доводилося робити weighted samplers та data oversampling.

Класифікація рукописних малюнків. Доповідь в Яндексі

Як виглядали картинки? Це клас «літак» та приклади з нього з мітками recognized та unrecognized. Співвідношення їх було десь 1 до 9. Як бачимо, дані досить галасливі. Я припустив би, що це літак. Якщо ж подивитися на not recognized, це в більшості випадків просто шум. Хтось навіть намагався написати «літак», але, мабуть, французькою.

Більшість учасників просто брали сітки, малювали дані з цієї послідовності ліній як RGB-картинки та закидали у мережу. Приблизно так само малював і я: брав палітру квітів, перший рядок малював одним кольором, який був на початку цієї палітри, останнім — іншим, який наприкінці палітри, а між ними скрізь робив інтерполяцію на цій палітрі. До речі, це давало кращий результат, ніж якщо ви малюватимете як на першому слайді — просто чорним кольором.

Інші учасники команди, наприклад Іван Сосін, пробували дещо інші підходи до малювання. Одним каналом він просто малював сіру картинку, іншим — малював кожен штрих градієнтом від початку до кінця, з 32 до 255, а третім каналом малював градієнт по всіх штрихах від 32 до 255.

Ще з цікавого - Алекс Парінов закидав інформацію в мережу по countrycode.

Класифікація рукописних малюнків. Доповідь в Яндексі

Метрика, яка використовувалася у змаганні, це Mean Average Precision. У чому суть цієї метрики для змагання? Ви можете віддати три предікшини, і якщо в цих трьох предикшинах немає правильного, то ви отримуєте 0. Якщо є правильний, то враховується його порядок. І результат за націленням буде вважатися 1, поділене на порядок вашого передбачення. Наприклад, ви зробили три предикшина, і правильний їх перший, то ви 1 ділите на 1 і отримуєте 1. Якщо предикшин вірний та її порядок 2, то 1 ділите на 2, отримуєте 0,5. Ну і т.д.

Класифікація рукописних малюнків. Доповідь в Яндексі

З передобробкою даних – як малювати картинки тощо – ми трохи визначилися. Які архітектури ми використали? Ми намагалися використовувати жирні архітектури, такі як PNASNet, SENet і такі вже класичні архітектури як SE-Res-NeXt, вони все більше заходять у нових змаганнях. Також були ResNet та DenseNet.

Класифікація рукописних малюнків. Доповідь в Яндексі

Класифікація рукописних малюнків. Доповідь в Яндексі

Класифікація рукописних малюнків. Доповідь в Яндексі

Як ми це навчали? Усі моделі, які ми брали, ми брали самі передвибраними на imagenet. Хоча даних багато, 50 млн картинок, але все одно, якщо ви берете мережу, передбачену на imatgeet, вона показувала кращий результат, ніж якщо ви просто навчатимете її від scratch.

Які техніки для навчання використовували? Це Cosing Annealing with Warm Restarts, про неї я поговорю трохи згодом. Це техніка, яку я використовую практично у всіх моїх останніх змаганнях, і з ними досить добре навчити сітки, досягти хорошого мінімуму.

Класифікація рукописних малюнків. Доповідь в Яндексі

Далі Reduce Learning Rate on Plateau. Ви починаєте навчати мережу, задаєте якийсь певний learning rate, далі її вчіть, у вас поступово loss сходиться до якогось певного значення. Ви це чекаєте, наприклад, протягом десяти епох loss не змінився. Ви зменшуєте ваш learning rate на якесь значення і продовжуєте навчати. Він у вас знову трохи падає, сходиться в якомусь мінімумі і ви знову знижуєте learning rate і так далі, поки ваша мережа остаточно не зійдеться.

Далі цікава техніка: Don't decay the learning rate, increase the batch size. Є стаття з однойменною назвою. Коли ви навчаєте мережу, вам необов'язково зменшувати learning rate ви можете просто збільшувати batch size.

Цю техніку, до речі, використав Алекс Парінов. Він починав з батча, що дорівнює 408, і коли мережа у нього приходила на якесь плато, він просто збільшував batch size вдвічі, і т.д.

Насправді, я не пам'ятаю, до якого значення у нього batch size доходив, але що цікаво, були команди на Kaggle, які використовували цю ж техніку, у них batch size був близько 10000. До речі, сучасні фреймворки для deep learning, такі як PyTorch, наприклад, дозволяють вам це просто робити. Ви генеруєте свій батч і подаєте його в мережу не як він є, повністю, а ділите його на чанки, щоб у вас це влазило у вашу відеокарту, вважаєте градієнти, і після того, як для всього батча порахували градієнт робите оновлення ваг.

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

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

Розмір картинок грав значення, але факт у тому, що у вас даних багато, потрібно довго навчати, і якщо у вас розмір картинки буде досить великим, то ви навчатимете дуже довго. Але це приносило якість вашого фінального класифікатора не так багато, так що варто було використовувати якийсь trade-off. І пробували тільки малюнки невеликого розміру.

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

Про оптимайзери. Ми використовували SGD та Adam. У такий спосіб можна було отримати single модель, яка давала швидкий 0,941-0,946 на паблік лідерборді, що досить непогано.

Якщо ви заансамблюєте моделі якимось чином, то ви отримаєте десь 0,951. Якщо застосувати ще одну техніку, то фінальний швидкий ви отримаєте на паблік борді 0,954, як ми отримали. Але про це трохи згодом. Далі я розповім, як ми асамблювали моделі, і як такого фінального швидко вдалося досягти.

Далі хотів би розповісти про Cosing Annealing with Warm Restarts або Stochastic Gradient Descent with Warm Restarts. Грубо кажучи, в принципі, оптимайзер ви можете засунути будь-який, але суть в наступному: якщо ви просто навчатимете одну мережу і поступово вона буде сходитися до якогось мінімуму, то все окей, у вас вийде одна мережа, вона робить певні помилки, але ви можете її навчати трохи інакше. Ви задаватимете якийсь початковий learning rate, і поступово його знижувати за цією формулою. Ви його занижуєте, у вас мережа приходить до якогось мінімуму, далі ви зберігаєте ваги, і знову ставите learning rate, який був на початку навчання, тим самим із цього мінімуму виходьте кудись нагору, і знову занижуєте ваш learning rate.

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

Класифікація рукописних малюнків. Доповідь в Яндексі

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

Роман Соловйов на основі цього вигадав метрику, ми її називали Proxy Score, яка досить добре корелювала з лідербордом. Суть у чому: ви робите предікшен, берете топ-1 ваших предиктів та вважаєте кількість об'єктів для кожного класу. Далі з кожного значення вичитаєте 330 і складаєте отримані абсолютні значення.

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

З ансамблем ви могли отримати такий швидкий. Що ще зробити? Припустимо, ви скористалися інформацією, що класи у тесті у вас збалансовані.

Балансування були різні. Приклад однієї з них - балансування від хлопців, які посіли перше місце.

Що ми робили? У нас балансування було досить простим, його запропонував Євген Бабахнін. Ми спочатку сортували наші передбачення з топ-1 і з них обирали кандидатів — таким чином, щоб кількість класів не перевищувала 330. Але для деяких класів у вас виходить так, що предиктів менше, ніж 330. Окей, давайте ще відсортуємо за топ-2 та топ-3, і так само оберемо кандидатів.

Чим наше балансування відрізнялося від балансування першого місця? Вони використовували ітеративний підхід, брали найпопулярніший клас і зменшували ймовірності для цього класу на якесь невелике число — доти, доки цей клас не ставав не найпопулярнішим. Брали наступний найпопулярніший клас. Так далі і знижували, поки кількість усіх класів не ставало рівною.

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

Як передпроцесувати дату? Всі передпроцесували дату плюс-мінус однаково - робила handcrafted-фічі, намагалися закодувати таймінги різним кольором штрихів і т.д. Саме про це говорив Олексій Ноздрін-Плотницький, який посів 8 місце.

Класифікація рукописних малюнків. Доповідь в Яндексі

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

Далі по координатах він брав різницю, а за таймінгами це все усереднював. І в нього виходила задоволена довга матриця. До неї він кілька разів застосовував 1D-згортку, щоб отримати матрицю розміром 64хn, де n - загальна кількість точок, а 64 зроблено для того, щоб подати отриману матрицю вже на шар будь-якої згорткової мережі, яка приймає кількість каналів - 64. його виходила матриця 64хn, далі з цього потрібно було скласти тензор якогось розміру, щоб кількість каналів дорівнювала 64. Він нормував всі точки Х, Y в діапазоні від 0 до 32, щоб скласти тензор розміром 32х32. Не знаю, чому він захотів 32х32, так вийшло. І в цю координату він клав фрагмент цієї матриці розміром 64хn. Таким чином, він просто отримував тензор 32х32х64, який можна було покласти далі у вашу нейронну мережу. У мене все.

Джерело: habr.com

Додати коментар або відгук