Джедайская тэхніка памяншэння згортачных сетак - pruning

Джедайская тэхніка памяншэння згортачных сетак - pruning

Перад табой зноў задача дэтэктавання аб'ектаў. Прыярытэт - хуткасць працы пры прымальнай дакладнасці. Бярэш архітэктуру YOLOv3 і данавучаеш. Дакладнасць(mAp75) большая за 0.95. Але хуткасць прагону ўсё яшчэ нізкая. Чорт.

Сёння абыдзем бокам квантызацыю. А пад катом разгледзім Model Pruning - Абразанне залішніх частак сеткі для паскарэння Inference без страты дакладнасці. Наглядна - адкуль, колькі і як можна выразаць. Разбяром, як зрабіць гэта ўручную і дзе можна аўтаматызаваць. У канцы рэпазітар на keras.

Увядзенне

На мінулым месцы працы, пермскім Macroscop, я здабыў адну звычку - заўсёды сачыць за часам выканання алгарытмаў. А час прагону сетак заўсёды правяраць праз фільтр адэкватнасці. Звычайна state-of-the-art у продзе не праходзяць гэты фільтр, што і прывяло мяне да Pruning.

Pruning – тэма старая, пра якую расказвалі ў cтэндфардскіх лекцыях у 2017 годзе. Асноўная ідэя - памяншэнне памеру навучанай сеткі без страты дакладнасці шляхам выдалення розных вузлоў. Гучыць клёва, але я рэдка чую аб яго ўжыванні. Мусіць, бракуе імплементацый, няма рускамоўных артыкулаў ці проста ўсё лічаць pruning ноў-гаў і маўчаць.
Але га разбіраць

Погляд у біялогію

Кахаю, калі ў Deep Learning зазіраюць ідэі, якія прыйшлі з біялогіі. Ім, як і эвалюцыі, можна давяраць (а ты ведаў, што ReLU вельмі падобная на функцыю актывацыі нейронаў у мозгу?)

Працэс Model Pruning таксама блізкі да біялогіі. Рэакцыю сеткі тут можна параўнаць з пластычнасцю мозга. Пара цікавых прыкладаў ёсць у кнізе Нормана Дойджа:

  1. Мозг жанчыны, якая мела ад нараджэння толькі адну палову, перапраграмаваў сам сябе для выканання функцый адсутнай паловы.
  2. Хлопец адстрэліў сабе частку мозгу, якая адказвае за зрок. З часам іншыя часткі мозгу ўзялі на сябе гэтыя функцыі. (паўтарыць не спрабуем)

Так і з вашай мадэлі можна выразаць частку слабых скрутак. У крайнім выпадку, пакінутыя скруткі дапамогуць замяніць выразаныя.

Любіш Transfer Learning ці вучыш з нуля?

Варыянт нумар адзін. Ты выкарыстоўваеш Transfer Learning на Yolov3. Retina, Mask-RCNN ці U-Net. Але часцей за ўсё нам не трэба распазнаваць 80 класаў аб'ектаў, як у COCO. У маёй практыцы ўсё абмяжоўваецца 1-2 класамі. Можна меркаваць, што архітэктура для 80 класаў тут залішняя. Напрошваецца думка, што архітэктуру трэба зменшыць. Прычым, хацелася б зрабіць гэта без страты наяўных прадугледжаных вагаў.

Варыянт нумар два. Можа быць, у цябе шмат дадзеных і вылічальных рэсурсаў ці проста патрэбна звышкастомная архітэктура. Не важна. Але ты вучыш сетку з нуля. Звычайны парадак - глядзім на структуру дадзеных, падбіраем залішнюю па магутнасці архітэктуру і пушым дропауты ад перанавучання. Я бачыў драпаўты 0.6, Карл.

У абодвух выпадках сетку можна памяншаць. Праматывавалі. Цяпер ідзем разбірацца, што за абразанне pruning

Агульны алгарытм

Мы вырашылі, што можам выдаляць скруткі. Выглядае гэта вельмі проста:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Выдаленне любой скруткі - гэта стрэс для сеткі, які звычайна вядзе за сабой і некаторы рост памылкі. З аднаго боку, гэты рост памылкі з'яўляецца паказчыкам таго, наколькі правільна мы выдаляем скруткі (напрыклад, вялікі рост кажа аб тым, што мы робім нешта не так). Але невялікі рост суцэль дапушчальны і часцяком ухіляецца наступным лёгкім данавучаннем з невялікім LR. Дадаем крок данавучання:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Цяпер нам трэба зразумець, калі ж мы жадаем спыніць наш цыкл Learning<->Pruning. Тут могуць быць экзатычныя варыянты, калі нам трэба памяншаць сетку да вызначанага памеру і хуткасці прагону (напрыклад, для мабільных прылад). Аднак, самы часты варыянт - гэта працяг цыклу, пакуль памылка не стане вышэй дапушчальнай. Дадаем ўмову:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Такім чынам, алгарытм становіцца зразумелым. Застаецца разабраць, як вызначыць выдаленыя скруткі.

Пошук выдаляных скрутак

Нам трэба выдаліць нейкія скруткі. Ірвацца напралом і "адстрэльваць" любыя - дрэнная ідэя, хоць і будзе працаваць. Але раз ёсць галава, можна падумаць і паспрабаваць вылучыць для выдалення "слабыя" скруткі. Варыянтаў ёсць некалькі:

  1. Найменшая L1-мера або low_magnitude_pruning. Ідэя, якая гаворыць аб тым, што скруткі з малымі значэннямі вагаў, уносяць малы ўклад у выніковае прыняцце рашэння
  2. Найменшая L1-мера з улікам сярэдняга і стандартнага адхіленні. Дапаўняем ацэнкай характару размеркавання.
  3. Маскіраванне скрутак і выключэнне найменш якія ўплываюць на выніковую дакладнасць. Больш дакладнае вызначэнне малазначных скрутак, але вельмі затратнае па часе і рэсурсам.
  4. Іншыя

Кожны варыянт мае права на жыццё і свае асаблівасці рэалізацыі. Тут разгледзім варыянт з найменшай L1-мерай

Ручны працэс для YOLOv3

У зыходнай архітэктуры змяшчаюцца рэшткавыя блокі. Але якімі б крутымі яны ні былі для глыбокіх сетак, нам яны некалькі перашкодзяць. Складанасць у тым, што нельга выдаляць зверкі з рознымі азначнікамі ў гэтых пластах:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Таму вылучым пласты, з якіх мы можам вольна выдаляць зверкі:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Цяпер пабудуем цыкл працы:

  1. Выгружаем актывацыі
  2. Прыкідваем, колькі выразаць
  3. Выразаем
  4. Вучым 10 эпох з LR=1e-4
  5. Тэстуем

Выгружаць скруткі карысна, каб ацаніць, якую частку мы можам выдаліць на вызначаным кроку. Прыклады выгрузкі:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Бачым, што практычна ўсюды 5% скрутак маюць вельмі нізкую L1-норму і мы можам іх выдаліць. На кожным кроку такая выгрузка паўтаралася і праводзілася ацэнка, з якіх пластоў і колькі можна выразаць.

Увесь працэс уклаўся ў 4 кроку (тут і ўсюды лікі для RTX 2060 Super):

Крок mAp75 Колькасць параметраў, млн Памер сеткі, мб Ад першапачатковай,% Час прагону, мс Умова абразання
0 0.9656 60 241 100 180 -
1 0.9622 55 218 91 175 5% ад усіх
2 0.9625 50 197 83 168 5% ад усіх
3 0.9633 39 155 64 155 15% для пластоў з 400+ скрутак
4 0.9555 31 124 51 146 10% для пластоў з 100+ скрутак

Да 2 кроку дадаўся адзін станоўчы эфект - у памяць улез батч-сайз 4, што вельмі паскорыла працэс данавучання.
На 4 этапе працэс быў спынены, т.я. нават працяглае данавучанне не паднімала mAp75 да старых значэнняў.
У выніку атрымалася паскорыць інферэнс на 15%, паменшыць памер на 35% і не страціць у дакладнасці.

Аўтаматызацыя для больш простых архітэктур

Для прасцейшых архітэктур сетак(без умоўных add, concaternate і residual блокаў) суцэль можна арыентавацца на апрацоўку ўсіх згортачных пластоў і аўтаматызаваць працэс выразання скрутак.

Такі варыянт я заімплементаваў тут.
Усё проста: з вас толькі функцыя страт, аптымізатар і батч-генератары:

import pruning
from keras.optimizers import Adam
from keras.utils import Sequence

train_batch_generator = BatchGenerator...
score_batch_generator = BatchGenerator...

opt = Adam(lr=1e-4)
pruner = pruning.Pruner("config.json", "categorical_crossentropy", opt)

pruner.prune(train_batch, valid_batch)

Пры неабходнасці можна змяніць параметры канфігі:

{
    "input_model_path": "model.h5",
    "output_model_path": "model_pruned.h5",
    "finetuning_epochs": 10, # the number of epochs for train between pruning steps
    "stop_loss": 0.1, # loss for stopping process
    "pruning_percent_step": 0.05, # part of convs for delete on every pruning step
    "pruning_standart_deviation_part": 0.2 # shift for limit pruning part
}

Дадаткова рэалізавана абмежаванне на падставе стандартнага адхілення. Мэта - абмежаваць частка выдаляных, выключаючы скруткі з ужо дастатковымі L1-мерамі:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Тым самым, мы дазваляем выдаліць толькі слабыя скруткі з размеркаванняў падобных праваму і не ўплываць на выдаленне з размеркаванняў падобных да левага:

Джедайская тэхніка памяншэння згортачных сетак - pruning

Пры набліжэнні размеркавання да нармальнага каэфіцыент pruning_standart_deviation_part можна падабраць з:

Джедайская тэхніка памяншэння згортачных сетак - pruning
Я рэкамендую дапушчэнне ў 2 сігма. Ці можна не арыентавацца на гэтую асаблівасць, пакінуўшы значэнне <1.0.

На выхадзе атрымліваецца графік памеру сеткі, страты і часу прагону сеткі па ўсім тэсце, аднарміраваныя да 1.0. Напрыклад, тут памер сеткі быў паменшаны амаль у 2 разы без страты ў якасці (невялікая згортачная сетка на 100к шаляў):

Джедайская тэхніка памяншэння згортачных сетак - pruning

Хуткасць прагону схільная нармальным флуктуацыі і практычна не змянілася. Гэтаму ёсць тлумачэнне:

  1. Лік скрутак змяняецца з зручнага (32, 64, 128) на не самыя зручныя для відэакартай - 27, 51 і тд. Тут магу памыліцца, але хутчэй за ўсё гэта ўплывае.
  2. Архітэктура не шырокая, але паслядоўная. Памяншаючы шырыню, мы не чапаем глыбіню. Тым самым памяншаем загрузку, але не мяняем хуткасць.

Таму паляпшэнне выявілася ў памяншэнні загрузкі CUDA пры прагоне на 20-30%, але не ў памяншэнні часу прагону

Вынікі

Парэфлексуем. Мы разгледзелі 2 варыянты pruning – для YOLOv3 (калі даводзіцца працаваць рукамі) і для сетак з архітэктурамі прасцей. Відаць, што ў абодвух выпадках можна дамагчыся памяншэнні памеру сеткі і паскарэнні без страты дакладнасці. Вынікі:

  • Памяншэнне памеру
  • Паскарэнне прагону
  • Памяншэнне загрузкі CUDA
  • Як следства, экалагічнасць (Мы аптымізуем будучае выкарыстанне вылічальных рэсурсаў. Дзесьці цешыцца адна Грэта Тунберг)

Дадатак

  • Пасля кроку pruning можна дакруціць і квантызацыю (напрыклад з TensorRT)
  • Tensorflow дае магчымасці для low_magnitude_pruning. Працуе.
  • Рэпазітар хачу развіваць і буду рады дапамогі

Крыніца: habr.com

Дадаць каментар