Аугментація даних

Повернути зображення — це не фокус, щоб було більше картинок. Це твердження про світ: «клас не залежить від кута». Іноді воно істинне, іноді хибне — і вся тема про те, як їх розрізнити.

Попередня тема закінчилась незручним фактом. Мережа зібрана, форми зійшлись, 24 774 параметри на місці — а навчальних прикладів у нас сто двадцять, по 784 пікселі кожен. Мережа з такою місткістю не мусить розуміти, що таке коло: їй значно дешевше запамʼятати сто двадцять картинок разом із відповідями. І вона це робить.

Даних більше не буде — розмітка коштує грошей, і її завжди менше, ніж хочеться. Але в зображення є властивість, якої немає в таблиці з цінами: його можна зсунути, повернути, притемнити — і предмет на ньому лишиться тим самим. Саме на цьому будується аугментація (augmentation).

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

Головна думка теми. Аугментація — це спосіб сказати мережі, що саме не має значення. Повертаючи зображення, ти стверджуєш: «клас не залежить від кута». Це твердження може бути хибним — і тоді аугментація не допомагає, а псує. Тому питання теми не «які бувають перетворення», а яке перетворення зберігає мітку саме в цій задачі.
Наскрізний приклад теми. Той самий датасет, що й у попередніх темах блоку: зображення 28×28 у відтінках сірого, шість класів фігур — коло, квадрат, ромб, кільце, хрест, трикутник. Нічого не завантажуємо, усе малюється формулами. Проти теми 09 розкид більший: центр гуляє на ±4 пікселі, радіус від 5 до 8, шум 0.20 — інакше задача занадто легка й аугментації нема чого рятувати. Усі числа нижче заміряні на цьому датасеті.

МежаДаних скінченна кількість

Почнемо з того, щоб побачити проблему числом, а не на словах. Беремо мережу з теми 09 без жодних змін, беремо 120 навчальних зображень (по двадцять на кожен із шести класів) і навчаємо 250 кроків. Після кожних 25 кроків міряємо дві точності: на навчальній вибірці, яку мережа бачить, і на окремій перевірочній із 600 зображень, яку вона не бачила ніколи.

крокна навчальнійна перевірочнійрозрив
250.4080.3530.055
750.8920.8070.085
1501.0000.8800.120
2501.0000.8800.120

Читається це так. На навчальній вибірці точність доходить до 1.000 — мережа відповідає правильно на кожному зображенні, яке бачила, без винятку. На перевірочній вона зупиняється на 0.880 і далі не росте. Різниця між цими двома числами — 0.120 — і є ціна запамʼятовування: стільки мережа «знає» про конкретні картинки понад те, що вона знає про фігури взагалі.

Причина в співвідношенні. У 120 зображеннях 120 × 784 = 94 080 чисел, і більшість із них — однаковий фон; у мережі 24 774 параметри. Місткості цілком вистачає, щоб для кожного зображення завести кілька прикмет, які є тільки в ньому: пляма шуму отут, край фігури отам. На навчальній вибірці вони бездоганні, на новому зображенні не варті нічого.

Це не нова хвороба. Перенавчання ти вже бачив у курсі машинного навчання на таблицях. Нового тут лише те, чим його лікувати: у таблиці рядок не можна «трохи посунути» й лишити тим самим рядком, а зображення — можна. Регуляризація ваг, дропаут і рання зупинка теж працюють, але вони приборкують мережу; аугментація натомість працює з даними, тому розбирається окремо і раніше. Про решту засобів — у темі 11 «Навчання CNN».

ІдеяОдне зображення — багато прикладів

Візьмемо одне зображення кола й зсунемо його на три пікселі вправо. Це досі коло. Повернемо на десять градусів — досі коло. Притемнимо на чверть — досі коло. Мітка не змінилась, а числа в масиві змінились усі до єдиного.

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

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

Аугментація не додає даних. Зсунуте коло не несе про світ жодної нової інформації — воно зроблене з того самого зображення й нічого нового про класи не розповідає. Що воно несе — це обмеження: «ось ці два масиви чисел мусять дістати одну відповідь». Ти не збільшуєш вибірку, ти вкладаєш у мережу власне знання про задачу у формі, яку мережа розуміє — у формі прикладів.

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

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

ЗаяваАугментація — це заява про інваріантність

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

y( T(x) ) = y(x)   для всіх x у цій задачі

Словами: що б перетворення не зробило з пікселями, правильна відповідь лишається тією самою. Символ T(x) читається «перетворення, застосоване до зображення»; y — це функція «яка тут насправді фігура». Слова «для всіх x у цій задачі» — найважливіша частина запису: твердження мусить бути істинним не для однієї вдалої картинки, а для кожної, яку мережа побачить.

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

І звідси головний наслідок. Якщо рівність y(T(x)) = y(x) хибна, то ти показуєш мережі зображення з неправильною міткою. Не «слабко корисний приклад», а буквально брехню: ось ромб, і написано, що це квадрат. Такі приклади називаються шумом у мітках — і ти згенерував його власноруч, своїм же конвеєром.

Яке припущення ти щойно зробив

Одне перетворення, три різні задачі. Ліворуч — оригінал, посередині — після перетворення, праворуч — до чого це найближче. Мітка визначається не на око, а виміряним числом: для фігур і цифр — перекриттям із шаблоном класу (IoU; цифра вважається впізнаною від 0.70), для знімка — правилом «ущільнення є, якщо десь яскравість вища за 0.70».

задача
перетворення
було—
стало—
збіг із класом «стало»—
Постав задачу «цифри», перетворення «поворот» і доведи силу до кінця: на 180° шістка стає девʼяткою зі збігом 1.000. Дзеркало натомість істинне для фігур і хибне для цифр, а яскравість — навпаки: фігурам байдуже, а на знімку саме яскравість і є діагнозом. Одне й те саме перетворення в одній задачі безпечне, а в іншій — генератор хибних міток.

Ось той самий список словами. Перетворення ліворуч, твердження, яке ти робиш, — праворуч. Останній стовпчик — де це твердження ламається.

перетвореннятвердження про світде воно хибне
Дзеркало по горизонталіКлас не залежить від того, ліва це чи права версіяТекст, цифри, дорожні знаки з напрямком, «ліва / права рука», медична латеральність
Поворот на довільний кутКлас не залежить від орієнтації предметаЦифри 6 і 9, літери, наш квадрат і ромб, будь-яка задача, де «догори дриґом» — окремий клас
ЗсувКлас не залежить від того, де в кадрі предметЗадачі, де важлива позиція: розмітка документа, положення дефекту на деталі
Масштаб і обрізкаКлас не залежить від розміру предмета в кадріКоли розмір і є ознакою: відрізнити монету від тарілки, дитину від дорослого
Яскравість і контрастКлас не залежить від освітленняМедичні знімки, де щільність тканини видно саме як яскравість; контроль якості за відтінком
Колірний тонКлас не залежить від кольоруСтиглий чи зелений плід, колір світлофора, індикаторні смужки тестів
Шум і розмиттяКлас не залежить від якості знімкаЗадача «оцінити різкість» або «виявити підробку за артефактами»

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

ГеометріяГеометричні перетворення

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

Дві деталі, про які згадують після першої поламаної моделі

Краї. Поверни квадратне зображення на 20° — і в кутах утворюється порожнеча, якої в оригіналі не було. Чим її заповнити, вирішує аргумент fill: нулями (чорне), середнім кольором, віддзеркаленням країв. Вибір не косметичний: якщо всі аугментовані зображення мають чорні кути, а неаугментовані ні, мережа може навчитись розрізняти саме кути — і на перевірочній вибірці все розсиплеться.

Інтерполяція. Поворот на не кратний 90° кут не переводить піксель у піксель: нове значення доводиться інтерполювати, і тонкі лінії від цього бліднуть. На фігурах завтовшки в три пікселі це помітно, на фото 512×512 — ні.

Конструктор аугментації

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

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

ФотометріяФотометричні перетворення

Друга група нічого не рухає, а міняє самі значення пікселів: яскравість, контраст, насиченість, тон, шум, розмиття. У torchvision перші чотири зібрані в один ColorJitter, шум зазвичай додають руками, розмиття — GaussianBlur.

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

«Майже» тут стоїть не для краси. Є цілі галузі, де яскравість і є сигнал:

Порядок має значення. Фотометричні перетворення застосовують до нормалізації (віднімання середнього й ділення на стандартне відхилення), а не після. Після нормалізації числа вже не є яскравістю, і «збільшити яскравість на 20 %» перетворюється на беззмістовну арифметику. У torchvision.transforms.v2 це виходить само собою, якщо Normalize стоїть останнім у Compose.

СтиранняСтирання шматка

Третя група стоїть окремо, бо не імітує жодного явища зі зйомки. RandomErasing (у літературі — cutout) просто затирає випадковий прямокутник зображення суцільним кольором або шумом. Ніяка камера так не знімає. Навіщо тоді?

Затим, що мережа завжди шукає найкоротший шлях. Якщо всі собаки в датасеті зняті з нашийником, найдешевша ознака «собаки» — нашийник, і на собаці без нашийника мережа помилиться. Стирання ламає цю стратегію: коли вирішальна ділянка час від часу зникає, доводиться впізнавати предмет ще й по решті.

Формально це теж заява, тільки хитріша: «клас видно більш ніж з одного місця зображення». Для кота це правда — вуха, лапи, хвіст, шерсть. Для нашого кільця — ні: кільце відрізняється від кола рівно однією деталлю, дірою посередині. Затри її — і залишиться коло з міткою «кільце». Тому сила стирання добирається так, щоб прямокутник рідко накривав вирішальну частину предмета; типові значення — від 2 % до 15 % площі.

Сусідні прийоми, які ми не розбираємо. З тієї самої родини — mixup (два зображення змішують по прозорості, і мітка стає дробовою: 0.7 кота й 0.3 собаки) і CutMix (шматок одного зображення вклеюють в інше). Обидва працюють, обидва вимагають, щоб функція втрат приймала дробові мітки, і обидва належать радше до режиму навчання, ніж до підготовки даних. Знай, що вони існують.

ШкодаКоли аугментація шкодить

Тепер найцікавіше. У нашому датасеті є пара класів, яка перетворює абстрактну обережність на конкретну катастрофу: квадрат і ромб. Ромб — це квадрат, повернутий на 45°. Не «схожий на», а буквально він: обидва класи задані формулами, і одна формула переходить в іншу поворотом.

Це означає, що перетворення «поворот на випадковий кут до 45°» у цьому датасеті гарантовано генерує зображення з чужою міткою. Не іноді, не в поганому випадку — кожного разу, коли кут наближається до 45°, а клас — квадрат або ромб.

Перевіримо це не на око. Візьмемо квадрат, повернемо його на кут θ і порівняємо з шаблонами всіх шести класів за мірою перекриття IoU (Intersection over Union — площа спільної частини, поділена на площу обʼєднання; ти зустрічав її в темі 02). Найближчий шаблон і є тим, чим фігура тепер виглядає. Перед порівнянням фігуру зсуваємо в центр і беремо шаблон із найближчою площею — інакше ми міряли б не форму, а положення й розмір.

Чому сітка вдвічі дрібніша. У цьому й наступних розділах фігури намальовані тими самими формулами, але на сітці 56×56 замість 28×28. Причина суто технічна: на грубому растрі поворот лишає зубці, і збіг падає через них, а не через форму. Нас цікавить геометрія класів, тож растр беремо дрібніший. Класи, формули й висновки — ті самі.

Квадрат проти ромба

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

збіг із квадратом—
збіг із ромбом—
найближчий клас—
На 45° збіг із ромбом дорівнює 1.000 — це той самий масив пікселів. Мітка «квадрат» перестає бути правильною значно раніше: вже на 16° найближчим стає коло. Від 0 до 15° поворот безпечний, далі — генератор брехні.

Той самий рахунок для решти класів на 45° дає повну картину датасету:

класпісля повороту на 45° найближчийзбігмітка
колоколо0.987ціла
кільцекільце0.978ціла
квадратромб1.000зламана
ромбквадрат0.980зламана
хрестквадрат0.622зламана
трикутникквадрат0.689зламана

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

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

Скільки це коштує в точності

Геометрія показала, що мітка ламається. Тепер поміряймо, у що це обходиться мережі. Беремо той самий набір із 120 зображень і той самий конвеєр аугментації — дзеркало, зсув на 20 %, масштаб 0.85-1.15 — і міняємо в ньому рівно одне число: максимальний кут повороту.

аугментаціямітка цілана навчальнійна перевірочній
немає100 %1.0000.880
поворот до 8°100 %0.9420.965
поворот до 20°84 %0.9580.982
поворот до 45°57 %0.6920.688
Як читати колонку «мітка ціла». Це не частка класів, які переживають поворот на вказаний кут, а частка прикладів: кут в аугментації береться випадково з усього проміжку від нуля до вказаного, тож дрібні кути в цьому проміжку теж рахуються. Тому в рядку «до 45°» ціла більш ніж половина міток (57 %), хоча на рівно 45° таблиця класів із попереднього розділу лишає цілими тільки два класи з шести. Порахувати цю частку можна по кожному класу окремо, і саме там видно, коли перетворення псує мітку: коло й кільце круглі й не ламаються ніколи, а решта чотири перестають бути собою рано й майже одночасно — ромб із 13°, квадрат із 16°, хрест і трикутник із 17°. До 10° цілі всі 100 % прикладів, бо жоден клас ще не перейшов свою межу.

Числа виявились не такими простими, як обіцяла геометрія, і це найцінніше місце теми. Слабкий поворот до 8°, де мітку зберігають усі приклади, підняв точність із 0.880 до 0.965. Поворот до 20°, де мітку зберігають лише 84 %, дав ще більше — 0.982. І тільки поворот до 45°, де брехнею стає майже половина прикладів, обвалив точність до 0.688 — нижче, ніж узагалі без аугментації.

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

Що з цього робити на практиці. Геометричний рахунок — це не заборона, а попередження: він каже, скільки прикладів стануть брехливими, але не каже, чи буде від цього шкода. Тому силу перетворення добирають замірами, а геометрію використовують, щоб знати, де взагалі є сенс шукати і де точно не варто. Без геометричного рахунку ти шукав би наосліп; спираючись тільки на нього — зупинився б на 15° і втратив би найкращий результат.

Сила перетворення

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

мітка вціліла—
точність—
без аугментації було—
До 10° мітку зберігають усі 100 % прикладів; на 20° — 84 %, на 45° — 57 %. Точність за цією кривою не йде: найкращий вимір — саме на 20°, де мітки вже частково зіпсовані. Обвал настає на 45°, коли брехнею стає майже половина прикладів.

Класичні випадки, які варто знати напамʼять

ВиграшСкільки це дає

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

навчальнихбез аугментаціїз аугментацієювиграш
1200.8800.965+0.085
3600.9720.985+0.013
12000.9900.970-0.020

Три числа й один чіткий висновок. На 120 прикладах аугментація дає +0.085 — це велика різниця, майже десята частка точності. На 360 лишається +0.013. На 1200 виграш не просто зникає, а стає відʼємним: -0.020.

Останнє число варто пояснити, бо на перший погляд воно суперечить усьому попередньому. Аугментований набір важче вивчити: мережа щоразу бачить нову картинку й за ті самі 250 кроків встигає менше — на навчальній вибірці 0.960 проти 1.000 без аугментації. Коли даних мало, ця ціна окупається з надлишком, бо альтернатива — завчити сто двадцять картинок напамʼять. Коли даних досить, окупати вже нема чого: мережа й так бачить достатньо різних фігур, а сповільнення нікуди не зникає.

Чесна осторога до цього заміру. Бюджет навчання тут фіксований — 250 кроків на кожен дослід. Якби ми вчили довше, мережа з аугментацією на 1200 прикладах найімовірніше наздогнала б, а може, й обігнала б. Висновок точний саме у своїй постановці: при однаковій кількості обчислень користь від аугментації падає зі зростанням даних. Це і є та постановка, у якій опиняється більшість практичних задач, де час навчання обмежений.

Розрив між навчальною й перевірочною

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

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

Скільки даних, стільки й користі

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

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

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

МежаТільки на навчальній вибірці

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

Чому це руйнівно, найкраще видно, якщо згадати, навіщо взагалі потрібна перевірочна вибірка. Вона відповідає на одне питання: наскільки добре модель працюватиме на даних, які їй трапляться насправді. Аугментувавши її, ти міняєш питання на інше — «наскільки добре модель працює на випадково спотворених даних» — і робиш це мовчки.

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

Дослід поставимо так. Візьмемо дві моделі, які на чистій перевірочній вибірці показують майже однакову якість: А — навчена на 1200 прикладах без аугментації (0.990), Б — навчена на 360 прикладах із нею (0.985). Різниця між ними 0.005, і вона повторюється від запуску до запуску. Тепер поміряємо обидві вісім разів на аугментованій перевірочній вибірці, міняючи лише зерно.

Що стається, коли аугментувати перевірку

Модель А навчена на 1200 прикладах без аугментації, модель Б — на 360 з нею. Перемикач міняє спосіб перевірки: на чистій вибірці кожна дає одне число, на аугментованій — хмару з восьми прогонів із різними зернами.

перевірочна вибірка
модель А—
модель Б—
розкид проти різниці—
На чистій вибірці кращою виходить модель А, різниця 0.005 — і вона повторювана. Перемкни на аугментовану: кожне число починає стрибати, а «кращою» стає Б — у всіх вісьмох прогонах. Відповідь змінилася разом зі способом перевірки, а не з якістю моделей.

Результат вийшов різкіший, ніж очікувалось. По-перше, число справді плаває: у моделі А воно гуляє в межах 0.085 від самого лише зерна, у моделі Б — 0.036. Одна модель, одна вибірка, різні відповіді.

По-друге — і це важливіше — аугментована перевірка не шумить нейтрально, вона міняє відповідь. На чистій вибірці кращою була модель А: 0.990 проти 0.985. На аугментованій виграє Б — у всіх вісьмох прогонах без винятку, і з відривом 0.134 замість 0.005. Моделі ті самі, дані ті самі; змінився лише спосіб перевірки — і відповідь на питання «яка модель краща» перевернулась.

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

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

TTAАугментація на прогнозі — це інше

Сказане вище не означає, що на етапі прогнозу перетворення заборонені взагалі. Існує окремий прийом, який називається TTA (test-time augmentation, аугментація під час перевірки), і він робить принципово інше.

Ідея: спитати мережу не про одне зображення, а про кілька його варіантів — оригінал, дзеркало, злегка зсунуту копію — і усереднити прогнози. Різниця з помилкою з розділу 09 в одному слові: усереднення. Там випадковий варіант заміняв оригінал, і число стрибало; тут усі варіанти враховуються разом, а результат детермінований, поки набір варіантів фіксований.

Але працює це не завжди, і наш дослід показує, коли саме. Ми взяли ті самі дві моделі з розділу 09 і дали кожній TTA з пʼяти варіантів — оригінал плюс чотири аугментовані копії:

модельзвичайноз TTAрізниця
А · 1200 без аугментації0.9900.958-0.032
Б · 360 з аугментацією0.9850.990+0.005

Читається однозначно. Моделі А, яка під час навчання цих перетворень не бачила, TTA зашкодив: 0.990 впало до 0.958. Модель Б, навчена саме з ними, дістала невеликий, але справжній виграш: 0.985 → 0.990.

Один і той самий TTA двом моделям

Ліворуч — звичайний прогін на чистому зображенні, праворуч — середнє по пʼятьох варіантах. Набір варіантів однаковий для обох моделей; різне в них лише те, що вони бачили під час навчання.

Стрілки дивляться в різні боки, хоча перетворення однакові. Моделі А, яка цих перетворень під час навчання не бачила, усереднення по пʼятьох копіях коштувало 0.032 — кожна копія додає в середнє впевнену помилку. Моделі Б, навченій саме з ними, воно дало 0.005. Тому TTA не покращує будь-яку мережу: воно міряє, чи звикла вона до твого набору перетворень.

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

Дві умови, без яких TTA не працює. Перша: набір варіантів має складатися з перетворень, які зберігають мітку — тих самих, що пройшли перевірку з розділу 03. Якщо серед варіантів опиниться поворот на 45°, мережа побачить ромб замість квадрата й упевнено додасть у середнє неправильну відповідь. Друга: модель має бути навчена з цими ж перетвореннями. Інакше TTA підсовує їй картинки з розподілу, якого вона не бачила, — і псує відповідь замість того, щоб її уточнити.

Ціна в обох випадках однакова: пʼять прогонів мережі замість одного на кожне зображення. У змаганнях, де важлива десята частка відсотка, це вигідно; у сервісі, який відповідає за 50 мілісекунд, — рідко.

КодЯк це виглядає в коді

У torchvision перетворення описуються списком, який застосовується до кожного зображення на льоту — щоразу з новими випадковими параметрами. Сучасний варіант живе в модулі transforms.v2.

from torchvision.transforms import v2

train_transform = v2.Compose([
    v2.RandomHorizontalFlip(p=0.5),                       # геометрія
    v2.RandomAffine(degrees=8, translate=(0.2, 0.2),
                    scale=(0.85, 1.15)),
    v2.ColorJitter(brightness=0.2, contrast=0.2),          # фотометрія
    v2.Normalize(mean=[0.5], std=[0.5]),                   # нормалізація
    v2.RandomErasing(p=0.25, scale=(0.02, 0.15)),          # стирання — після неї
])

test_transform = v2.Compose([
    v2.Normalize(mean=[0.5], std=[0.5]),                   # і більше нічого
])

Порядок у цьому списку не довільний, і кожен рядок стоїть саме там, де стоїть:

  1. Геометрія — першою. Вона працює з розташуванням пікселів, і чим менше до неї встигли змінити значення, тим передбачуваніший результат інтерполяції.
  2. Фотометрія — після геометрії, але до нормалізації. Причина в розділі 05: після Normalize числа вже не яскравість.
  3. Нормалізація — передостання.
  4. Стирання — останнє. RandomErasing у torchvision затирає ділянку нулем, а нуль після нормалізації означає «середня яскравість», що якраз і потрібно. Постав його перед Normalize — і затерта пляма стане чорною, тобто помітною ознакою.

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

Про сумісність бібліотек. Найпопулярніша бібліотека аугментації — albumentations: у ній більше перетворень, вона швидша й уміє синхронно перетворювати зображення разом із масками та рамками. У середовищі цього курсу вона не працює: встановлена версія тягне за собою scikit-image, зібраний під старий numpy, і будь-який імпорт падає з ValueError: numpy.dtype size changed. Це типова, а не рідкісна ситуація: пакет із скомпільованими розширеннями звʼязаний із версією numpy, під яку його збирали. Тому перевіряй сумісність до того, як побудуєш на бібліотеці половину проєкту — одним рядком import у чистому середовищі. Нам вистачає torchvision.transforms.v2, і всі числа теми отримані на ньому.
Відтворюваність. Перетворення v2 беруть випадковість із генератора PyTorch, тому torch.manual_seed(0) на початку програми робить усю аугментацію повторюваною: другий запуск дає ті самі картинки й ті самі числа. Без зафіксованого зерна твої результати не збіжаться ні з лекцією, ні з твоїм же вчорашнім прогоном.

ПідсумокЩо винести з теми

І місток далі. Дані ми підготували: тепер мережа бачить кожне зображення щоразу трохи інакше й не може його завчити. Але подивись іще раз на криві з інтерактиву 5 — навіть із аугментацією навчання виглядає нерівно, точність стрибає, і незрозуміло, коли зупинятись. Це вже не про дані, а про сам режим навчання: яку швидкість навчання брати, чи ставити батчнорм, коли вмикати дропаут, як зрозуміти, що далі вчити немає сенсу. Про це — наступна тема.