Увеличаване на данни | Как да използвате задълбочено обучение, когато имате ограничени данни - част 2

Тази статия представлява изчерпателен преглед на техниките за увеличаване на данни за задълбочено обучение, специфични за изображенията. Това е част 2 от това как да използвате задълбочено обучение, когато имате ограничени данни. Checkout Част 1 тук.

Всички сме били там. Имате звездна концепция, която може да бъде реализирана с помощта на модел на машинно обучение. Чувствайки се бурно, отваряте уеб браузъра си и търсите подходящи данни. Вероятно е да намерите набор от данни, който има около няколкостотин изображения.

Спомняте си, че повечето популярни набори от данни имат изображения от порядъка на десетки хиляди (или повече). Спомняте си също, че някой споменава, че има голям набор от данни е от решаващо значение за доброто представяне. Чувствате се разочарован, чудите се; мога ли моята "най-съвременна" невронна мрежа да се представя добре с оскъдния обем данни, който имам?

Отговорът е, да! Но преди да се впуснем в магията да направим това, трябва да помислим върху някои основни въпроси.

Защо има нужда от голямо количество данни?

Брой параметри (в милиони) за популярни невронни мрежи.

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

Най-модерните невронни мрежи обикновено имат параметри от порядъка на милиони!

Естествено, ако имате много параметри, ще трябва да покажете на модела си за машинно обучение пропорционално количество примери, за да получите добри резултати. Също така, броят на необходимите параметри е пропорционален на сложността на задачата, която вашият модел трябва да изпълни.

Как да получа повече данни, ако нямам „повече данни“?

Не е нужно да търсите нови изображения, които могат да бъдат добавени към вашия набор от данни. Защо? Защото невронните мрежи не са умни за начало. Например, лошо обучена невронна мрежа би помислила, че тези три тенис топки, показани по-долу, са различни, уникални изображения.

Същата топка за тенис, но преведена.

Така че, за да получим повече данни, просто трябва да направим незначителни промени в съществуващия ни набор от данни. Незначителни промени като обръщане или преводи или ротации. Нашата невронна мрежа така или иначе смята, че това са различни изображения.

Увеличаване на данните в игра

Конволюционната невронна мрежа, която може категорично да класифицира обектите, дори ако се поставя в различни ориентации, има свойството, наречено инвариантност. По-конкретно, CNN може да бъде инвариантна за превод, гледна точка, размер или осветеност (Или комбинация от горното).

Това по същество е предпоставката за увеличаване на данните. В реалния свят може да имаме набор от данни, направени в ограничен набор от условия. Но нашето целево приложение може да съществува в различни условия, като различни ориентация, местоположение, мащаб, яркост и т.н. Ние отчитаме тези ситуации, като обучаваме нашата невронна мрежа с допълнителни синтетично модифицирани данни.

Може ли увеличаването да помогне, дори ако имам много данни?

Да. Това може да помогне за увеличаване на количеството на съответните данни във вашия набор от данни. Това е свързано с начина, по който научават невронните мрежи. Нека го илюстрирам с пример.

Двата класа в нашата хипотетична база данни. Този вляво представлява марка A (Ford), а този вдясно представлява марка B (Chevrolet).

Представете си, че имате набор от данни, състоящ се от две марки автомобили, както е показано по-горе. Да допуснем, че всички автомобили от марка А са подравнени точно като картината вляво (т.е. всички автомобили са обърнати вляво). По същия начин всички автомобили от марка B са подравнени точно като на снимката вдясно (т.е. с лице къмдясно). Сега вие захранвате този набор от данни към вашата най-модерна невронна мрежа и се надявате да получите впечатляващи резултати, след като бъде обучен.

Автомобил Ford (марка A), но с лице вдясно.

Нека да кажем, че е свършила обучение, и вие захранвате изображението по-горе, което е автомобил с марка A. Но невронната ви мрежа извежда, че това е автомобил с марка B! Объркани сте. Не сте ли получили 95% точност на вашия набор от данни, използвайки вашата "най-съвременна" невронна мрежа? Не преувеличавам, в миналото са се случвали подобни инциденти и нарушения.

Защо това се случва? Това се случва, защото така работят повечето алгоритми за машинно обучение. Той намира най-очевидните характеристики, които отличават един клас от друг. Тук особеността беше, че всички автомобили от марка A са обърнати вляво, а всички автомобили от марка B са обърнати надясно.

Невронната ви мрежа е толкова добра, колкото и данните, които я захранвате.

Как да предотвратим това да се случи? Трябва да намалим количеството на неподходящи функции в набора от данни. За нашия класификатор на модели на автомобили по-горе, просто решение би било да добавите снимки на автомобили от двата класа, обърнати в другата посока към оригиналния ни набор от данни. Още по-добре, можете просто да преобърнете изображенията в съществуващия набор от данни хоризонтално, така че да са обърнати към другата страна! Сега, когато тренирате невронната мрежа на този нов набор от данни, получавате ефективността, която сте възнамерявали да постигнете.

Чрез извършване на уголемяване може да попречи на невронната ви мрежа да се научи на неподходящи модели, като по същество повиши цялостната производителност.

Приготвяме се да започнем

Преди да се потопим в различните техники за увеличаване, има един проблем, който трябва да разгледаме предварително.

Къде да увеличаваме данни в нашия ML тръбопровод?

Отговорът може да изглежда доста очевиден; правим уголемяване, преди да подадем данните в модела нали? Да, но тук имате две възможности. Една от възможностите е предварително да извършите всички необходими трансформации, като съществено увеличите размера на вашия набор от данни. Другият вариант е да извършите тези трансформации на мини партида, точно преди да ги подадете на вашия модел на машинно обучение.

Първата опция е известна като офлайн увеличаване. Този метод е предпочитан за сравнително по-малки набори от данни, тъй като в крайна сметка ще увеличите размера на набора от данни с коефициент, равен на броя на извършените от вас трансформации (Например, като прелиствате всичките ми изображения, бих увеличил размера на моя набор от данни чрез коефициент 2).

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

Популярни техники за увеличаване

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

Какво би се случило, ако използваме техника, която ни принуждава да гадаем какво се намира отвъд границата на изображението? В този случай трябва да интерполираме някаква информация. Ще обсъдим подробно това, след като обхванем видовете увеличения.

За всяка от тези техники ние също така определяме фактора, с който размерът на вашия набор от данни ще се увеличи (известен също като фактор за увеличаване на данните).

1. Флип

Можете да преобръщате изображения хоризонтално и вертикално. Някои рамки не осигуряват функция за вертикални обръщания. Но вертикалният флип е еквивалентен на завъртане на изображение на 180 градуса и след това извършване на хоризонтален флип. По-долу са примери за изображения, които са обърнати.

Отляво имаме оригиналното изображение, последвано от изображението, обърнато хоризонтално, а след това изображението обърнато вертикално.

Можете да изпълнявате обръщания, като използвате някоя от следните команди от любимите си пакети. Фактор за увеличаване на данните = 2 до 4 пъти

# NumPy.'img '= Единично изображение.
flip_1 = np.fliplr (img)
# TensorFlow. 'x' = Заместител на място за изображение.
форма = [височина, ширина, канали]
x = tf.placeholder (dtype = tf.float32, форма = форма)
flip_2 = tf.image.flip_up_down (x)
flip_3 = tf.image.flip_left_right (x)
flip_4 = tf.image.random_flip_up_down (x)
flip_5 = tf.image.random_flip_left_right (x)

2. Въртене

Едно ключово нещо, което трябва да се отбележи при тази операция, е, че размерите на изображението не могат да бъдат запазени след завъртане. Ако вашето изображение е квадрат, завъртането му под прав ъгъл ще запази размера на изображението. Ако е правоъгълник, завъртането му на 180 градуса ще запази размера. Завъртането на изображението под по-фини ъгли също ще промени окончателния размер на изображението. Ще видим как можем да се справим с този проблем в следващия раздел. По-долу са примери на квадратни изображения, завъртени под прав ъгъл.

Изображенията се завъртат на 90 градуса по посока на часовниковата стрелка спрямо предходното, докато се движим отляво надясно.

Можете да извършвате завъртания, като използвате някоя от следните команди, от любимите си пакети. Фактор за увеличаване на данните = 2 до 4 пъти

# Заместители: 'x' = Единично изображение, 'y' = Пакет от изображения
# 'k' обозначава броя на завъртанията срещу часовниковата стрелка на 90 градуса
форма = [височина, ширина, канали]
x = tf.placeholder (dtype = tf.float32, форма = форма)
rot_90 = tf.image.rot90 (img, k = 1)
rot_180 = tf.image.rot90 (img, k = 2)
# За завъртане под който и да е ъгъл. В примера по-долу „ъгли“ е в радиани
форма = [партида, височина, ширина, 3]
y = tf.placeholder (dtype = tf.float32, форма = форма)
rot_tf_180 = tf.contrib.image.rotate (y, ъгли = 3.1415)
# Scikit-изображение. 'ъгъл' = градуси. 'img' = Въведено изображение
# За подробности относно „режим“, проверете секцията за интерполация по-долу.
rot = skimage.transform.rotate (img, ъгъл = 45, режим = 'отражение')

3. Мащаб

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

Отляво имаме оригиналното изображение, изображението мащабирано навън с 10%, а изображението мащабирано навън с 20%

Можете да извършите мащабиране, като използвате следните команди, като използвате scikit-изображение. Фактор за увеличаване на данните = произволен.

# Scikit изображение. 'img' = входно изображение, 'мащаб' = коефициент на мащаб
# За подробности относно „режим“, проверете секцията за интерполация по-долу.
scale_out = skimage.transform.rescale (img, мащаб = 2.0, режим = 'константа')
scale_in = skimage.transform.rescale (img, мащаб = 0.5, режим = 'константа')
# Не забравяйте да изрежете изображенията до оригиналния размер (за
# scale_out)

4. Отрязване

За разлика от мащабирането, ние просто произволно изваждаме участък от оригиналното изображение. След това преоразмеряваме този раздел до оригиналния размер на изображението. Този метод е известен като случайно изрязване. По-долу са дадени примери за произволно изрязване. Ако погледнете внимателно, можете да забележите разликата между този метод и мащабирането.

Отляво имаме оригиналното изображение, квадратно сечение, изрязано от горе вляво, и след това квадратно сечение, изрязано от долу вдясно. Изрязаните секции бяха преоразмерени до оригиналния размер на изображението.

Можете да извършите произволни култури, като използвате някоя от следните команди за TensorFlow. Фактор за увеличаване на данните = произволен.

# TensorFlow. 'x' = Заместител на място за изображение.
original_size = [височина, ширина, канали]
x = tf.placeholder (dtype = tf.float32, shape = original_size)
# Използвайте следните команди за изпълнение на произволни култури
crop_size = [new_height, new_width, канали]
seed = np.random.randint (1234)
x = tf.random_crop (x, size = crop_size, seed = семе)
изход = tf.images.resize_images (x, размер = original_size)

5. Превод

Преводът просто включва преместване на изображението по посока X или Y (или и двете). В следващия пример приемаме, че изображението има черен фон отвъд неговата граница и е преведено по подходящ начин. Този метод за увеличаване е много полезен, тъй като повечето обекти могат да бъдат разположени почти навсякъде в изображението. Това принуждава вашата конволюционна невронна мрежа да търси навсякъде.

Отляво имаме оригиналното изображение, изображението преведено отдясно и изображението преведено нагоре.

Можете да извършите преводи в TensorFlow, като използвате следните команди. Фактор за увеличаване на данните = произволен.

# pad_left, pad_right, pad_top, pad_bottom означават пиксела
# изместване. Задайте един от тях на желаната стойност и починете на 0
форма = [партида, височина, ширина, канали]
x = tf.placeholder (dtype = tf.float32, форма = форма)
# Използваме две функции, за да получим желаното увеличение
x = tf.image.pad_to_bounding_box (x, pad_top, pad_left, височина + pad_bottom + pad_top, ширина + pad_right + pad_left)
изход = tf.image.crop_to_bounding_box (x, pad_bottom, pad_right, височина, ширина)

6. Гаусов шум

Прекаленото прилягане обикновено се случва, когато невронната ви мрежа се опитва да научи високочестотни характеристики (модели, които се срещат много), които може да не са полезни. Гаусският шум, който има нулева средна стойност, по същество има точки от данни във всички честоти, ефективно изкривявайки високочестотните характеристики. Това също означава, че компонентите с по-ниска честота (обикновено, предвидените от вас данни) също са изкривени, но вашата невронна мрежа може да се научи да гледа миналото. Добавянето на точното количество шум може да подобри способността за учене.

Тонизирана версия на това е солта и черния пипер, който се представя като случайни черни и бели пиксели, разпространени през изображението. Това е подобно на ефекта, който се получава чрез добавяне на гаусов шум към изображение, но може да има по-ниско ниво на изкривяване на информацията.

Отляво имаме оригиналното изображение, изображението с добавен шум от Гаус, изображение с добавен шум от сол и пипер

Можете да добавите гаусов шум към изображението си, като използвате следната команда на TensorFlow. Фактор за увеличаване на данните = 2х.

#TensorFlow. 'x' = Заместител на място за изображение.
форма = [височина, ширина, канали]
x = tf.placeholder (dtype = tf.float32, форма = форма)
# Добавяне на гаусов шум
шум = tf.random_normal (форма = tf.shape (x), средно = 0.0, stddev = 1.0,
dtype = tf.float32)
изход = tf.add (x, шум)

Разширени техники за увеличаване

В реалния свят природните данни все още могат да съществуват при различни условия, които не могат да бъдат отчетени по горните прости методи. Например, нека вземем задачата да идентифицираме пейзажа във фотографията. Пейзажът може да бъде всичко: замръзване на тундри, тревни площи, гори и т.н. Звучи като доста права задача за класификация, нали? Ще бъдете прави, с изключение на едно нещо. Пренебрегваме една важна характеристика на фотографиите, която би повлияла на представянето - Сезонът, в който е направена снимката.

Ако нашата невронна мрежа не разбира факта, че определени ландшафти могат да съществуват при различни условия (сняг, влажна, ярка и т.н.), тя може фалшиво да обозначи замръзналите езера като ледници или мокрите полета като блата.

Един от начините за смекчаване на тази ситуация е да добавим още снимки, така че да отчитаме всички сезонни промени. Но това е трудна задача. Разширявайки концепцията ни за увеличаване на данните, представете си колко готино би било да се генерират изкуствени ефекти като различни сезони?

Условни GANs за спасяването!

Без да навлизат в детайли, условни GANs могат да трансформират изображение от един домейн в изображение в друг. Ако смятате, че звучи твърде неясно, не е; това е буквално колко мощна е тази невронна мрежа! По-долу е даден пример на условни GANs, използвани за преобразуване на снимки на летни пейзажи в зимни пейзажи.

Промяна на сезоните с използване на CycleGAN (Източник: https://junyanz.github.io/CycleGAN/)

Горният метод е здрав, но изчислително интензивен. По-евтина алтернатива би била нещо, наречено трансфер на невронни стилове. Той грабва текстурата / атмосферата / външния вид на едно изображение (известен още като „стил“) и го смесва със съдържанието на друго. Използвайки тази мощна техника, ние произвеждаме ефект, подобен на този на нашия условен GAN (Всъщност този метод е въведен преди изобретяването на cGAN!).

Единственият недостатък на този метод е, че резултатът изглежда по-скоро артистичен, отколкото реалистичен. Съществуват обаче някои подобрения като Deep Photo Style Style, показани по-долу, които имат впечатляващи резултати.

Дълбоко прехвърляне на стил на снимки. Забележете как бихме могли да генерираме ефекта, който желаем върху нашата база данни. (Източник: https://arxiv.org/abs/1703.07511)

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

Кратка бележка за интерполация

Ами ако искате да преведете изображение, което няма черен фон? Ами ако искате да увеличите мащаба си навътре? Или се върти в по-фини ъгли? След като извършим тези трансформации, трябва да запазим оригиналния си размер на изображението. Тъй като изображението ни няма информация за неща извън неговата граница, трябва да направим някои предположения. Обикновено пространството отвъд границата на изображението се приема като постоянното 0 във всяка точка. Следователно, когато правите тези трансформации, получавате черна зона, където изображението не е дефинирано.

Отляво - изображение, завъртено на 45 градуса обратно на часовниковата стрелка, изображение, преведено отдясно, и изображение, мащабирано навътре.

Но това правилно предположение ли е? В сценария на реалния свят това е най-вече не. Обработката на изображения и ML рамките имат някои стандартни начини, с които можете да решите как да запълните непознатото пространство. Те се дефинират по следния начин.

Отляво имаме постоянния, ръб, отразяващ, симетричен и режим на увиване.

1. Постоянен

Най-простият метод за интерполация е да се запълни неизвестният регион с някаква постоянна стойност. Това може да не работи за естествени изображения, но може да работи за изображения, направени в монохроматичен фон

2. Край

Стойностите на ръба на изображението се разширяват след границата. Този метод може да работи за леки преводи.

3. Отразете

Стойностите на пиксела на изображението се отразяват по границата на изображението. Този метод е полезен за непрекъснат или естествен фон, съдържащ дървета, планини и т.н.

4. Симетричен

Този метод е подобен на отразяване, с изключение на факта, че на границата на отражение се прави копие на крайните пиксели. Обикновено отразяването и симетричността могат да се използват взаимозаменяемо, но разликите ще бъдат видими, когато се работи с много малки изображения или модели.

5. Увийте

Изображението просто се повтаря отвъд нейната граница, сякаш е облицовано с плочки. Този метод не се използва толкова популярно, колкото останалите, тъй като няма смисъл за много сценарии.

Освен тях, можете да създадете свои собствени методи за справяне с неопределено пространство, но обикновено тези методи биха се справили добре за повечето проблеми с класификацията.

Така че, ако използвам ВСИЧКИ тези техники, моят ML алгоритъм ще бъде надежден нали?

Ако го използвате по правилния начин, тогава да! Кой е правилният начин, който питате? Е, понякога не всички техники за увеличаване имат смисъл за набор от данни. Помислете отново за нашия пример за кола. По-долу са някои от начините, по които можете да променяте изображението.

Първото изображение (отляво) е оригиналното, второто е обърнато хоризонтално, третото се завърта на 180 градуса, а последното се завърта на 90 градуса (по посока на часовниковата стрелка).

Разбира се, това са снимки на един и същ автомобил, но вашето целево приложение може никога да не вижда автомобили, представени в тези насоки.

Например, ако просто ще класифицирате случайни автомобили на пътя, само второто изображение би имало смисъл да бъде в набора от данни. Но ако притежавате застрахователна компания, която се занимава с автомобилни катастрофи и искате да идентифицирате и модели на обърнати, счупени автомобили, третото изображение има смисъл. Последното изображение може да няма смисъл и за горните сценарии.

Въпросът е, че докато използваме техниките за увеличаване, трябва да се уверим, че не увеличаваме несъответстващите данни.

Наистина ли си струва усилията?

Вероятно очаквате някои резултати да ви мотивират да изминете допълнителната миля. Достатъчно честно; И аз също се покривам. Позволете ми да докажа, че увеличението наистина работи, използвайки пример за играчка. Можете да копирате този експеримент, за да потвърдите.

Нека създадем две невронни мрежи, за да класифицираме данни в един сред четири класа: котка, лъв, тигър или леопард. Уловът е, че единият няма да използва увеличаване на данните, докато другият ще. Можете да изтеглите набора от данни от тук връзка.

Ако сте проверили набора от данни, ще забележите, че има само 50 изображения на клас както за обучение, така и за тестване. Ясно е, че не можем да използваме увеличение за един от класификаторите. За да направим шансовете по-справедливи, използваме трансферно обучение, за да дадем на моделите по-добър шанс с оскъдния обем данни.

Четирите класа в нашата база данни.

За този без увеличение, нека използваме VGG19 мрежа. Тук написах реализация на TensorFlow, която се основава на това изпълнение. След като клонирате моето репо, можете да получите данните от тук и vgg19.npy (използван за трансферно обучение) от тук. Вече можете да стартирате модела, за да проверите производителността.

Бих се съгласил обаче, че писането на допълнителен код за увеличаване на данни наистина е малко усилие. И така, за да изградя нашия втори модел, се обърнах към Нанонец. Те използват вътрешно обучение за трансфер и увеличаване на данни, за да осигурят най-добри резултати, като използват минимални данни. Всичко, което трябва да направите, е да качите данните на уебсайта им и да изчакате, докато се обучат на сървърите им (Обикновено около 30 минути). Какво знаете, той е идеален за нашия експеримент за сравнение.

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

Резултати
VGG19 (без увеличение) - 76% точност на теста (най-висока)
Нанонети (с увеличение) - 94,5% точност на теста

Впечатляващо нали? Факт е, че повечето модели се представят добре с повече данни. За да осигуря конкретно доказателство, споменах таблицата по-долу. Показва честотата на грешките на популярните невронни мрежи в наборите от данни Cifar 10 (C10) и Cifar 100 (C100). C10 + и C100 + колоните са степента на грешки с увеличаване на данните.

Коефициент на грешки на популярните невронни мрежи в наборите данни Cifar 10 и Cifar 100. (Източник: DenseNet)

Благодаря ви, че прочетохте тази статия! Натиснете този бутон, ако сте го направили! Надявам се да хвърли малко светлина за увеличаване на данните. Ако имате някакви въпроси, можете да ми ударите в социалните медии или да ми изпратите имейл (bharathrajn98@gmail.com).

Всичко за Nanonets: Nanonets изгражда API, за да опрости задълбоченото обучение за разработчиците. Посетете ни на https://www.nanonets.com за повече)