Jedi tehnika za smanjivanje konvolucijskih mreža – pruning
Pred vama je ponovno zadatak otkrivanja objekata. Prioritet je brzina rada uz prihvatljivu točnost. Uzimate YOLOv3 arhitekturu i dalje je trenirate. Točnost (mAp75) je veća od 0.95. Ali stopa trčanja je još uvijek niska. Sranje.
Danas ćemo zaobići kvantizaciju. I ispod reza ćemo pogledati Model Obrezivanje — skraćivanje suvišnih dijelova mreže kako bi se ubrzalo zaključivanje bez gubitka točnosti. Jasno je gdje, koliko i kako rezati. Hajde da shvatimo kako to učiniti ručno i gdje to možete automatizirati. Na kraju je spremište na kerasu.
Uvod
Na prethodnom radnom mjestu, Macroscopu u Permu, stekao sam jednu naviku - uvijek pratiti vrijeme izvršavanja algoritama. I uvijek provjerite mrežno vrijeme rada kroz filtar adekvatnosti. Obično najsuvremenije u proizvodnji ne prolaze ovaj filter, što me dovelo do rezidbe.
Orezivanje je stara tema o kojoj se raspravljalo u Predavanja na Stanfordu u 2017. godini. Glavna ideja je smanjiti veličinu uvježbane mreže bez gubitka točnosti uklanjanjem različitih čvorova. Zvuči cool, ali rijetko čujem o njegovoj upotrebi. Vjerojatno nema dovoljno implementacija, nema članaka na ruskom jeziku ili jednostavno svi to smatraju znanjem rezidbe i šute.
Ali rastavimo ga
Pogled u biologiju
Volim kad Deep Learning razmatra ideje koje dolaze iz biologije. Njima se, kao i evoluciji, može vjerovati (jeste li znali da je ReLU vrlo sličan funkcija aktivacije neurona u mozgu?)
Model rezidbe također je blizak biologiji. Odgovor mreže ovdje se može usporediti s plastičnošću mozga. U knjizi ima par zanimljivih primjera. Norman Doidge:
Mozak žene koja je rođena samo s jednom polovicom reprogramirao se da obavlja funkcije polovice koja nedostaje.
Tip mu je pucao u dio mozga odgovoran za vid. S vremenom su drugi dijelovi mozga preuzeli te funkcije. (ne pokušavamo ponavljati)
Isto tako, možete izrezati neke od slabih zavoja iz svog modela. U krajnjem slučaju, preostali snopovi pomoći će zamijeniti odrezane.
Volite li Transfer Learning ili učite od nule?
Opcija broj jedan. Koristite Transfer Learning na Yolov3. Retina, Mask-RCNN ili U-Net. Ali većinu vremena ne trebamo prepoznati 80 klasa objekata kao u COCO. U mojoj praksi sve je ograničeno na razrede 1-2. Moglo bi se pretpostaviti da je arhitektura za 80 razreda ovdje suvišna. To sugerira da arhitekturu treba smanjiti. Štoviše, želio bih to učiniti bez gubitka postojećih prethodno treniranih utega.
Opcija broj dva. Možda imate puno podataka i računalnih resursa ili vam je samo potrebna super-prilagođena arhitektura. Nije važno. Ali učite mrežu od nule. Uobičajeni postupak je pogledati strukturu podataka, odabrati arhitekturu koja ima PREVIŠE snage i pogurati osobe koje su napustile školovanje. Vidio sam 0.6 odustajanja, Karl.
U oba slučaja, mreža se može smanjiti. Motivirano. Sada idemo shvatiti kakva je vrsta obrezivanja obrezivanja
Opći algoritam
Odlučili smo da možemo ukloniti svežnjeve. Izgleda prilično jednostavno:
Uklanjanje bilo kakve konvolucije stresno je za mrežu, što obično dovodi do određenog povećanja pogreške. S jedne strane, ovo povećanje pogreške pokazatelj je koliko ispravno uklanjamo vijuge (na primjer, veliko povećanje ukazuje na to da radimo nešto pogrešno). Ali malo povećanje je sasvim prihvatljivo i često se eliminira naknadnim laganim dodatnim treningom s malim LR. Dodajte dodatni korak obuke:
Sada moramo shvatiti kada želimo zaustaviti našu petlju učenja<->obrezivanja. Ovdje mogu postojati egzotične opcije kada trebamo smanjiti mrežu na određenu veličinu i brzinu (na primjer, za mobilne uređaje). Međutim, najčešća opcija je nastavak ciklusa dok pogreška ne postane veća od prihvatljive. Dodajte uvjet:
Dakle, algoritam postaje jasan. Ostaje shvatiti kako odrediti izbrisane vijuge.
Potražite izbrisane pakete
Moramo ukloniti neke zavoje. Žuriti naprijed i "upucavati" bilo koga je loša ideja, iako će uspjeti. Ali budući da imate glavu, možete razmisliti i pokušati odabrati "slabe" vijuge za uklanjanje. Postoji nekoliko opcija:
Svaka od opcija ima pravo na život i svoje značajke implementacije. Ovdje razmatramo opciju s najmanjom L1-mjerom
Ručni postupak za YOLOv3
Izvorna arhitektura sadrži zaostale blokove. Ali koliko god bili cool za duboke mreže, donekle će nas ometati. Poteškoća je u tome što ne možete izbrisati usklađivanja s različitim indeksima u ovim slojevima:
Stoga, odaberimo slojeve iz kojih možemo slobodno brisati usklađivanja:
Sada napravimo radni ciklus:
Prijenos aktivacija
Smišljanje koliko smanjiti
Izrezati
Učenje 10 epoha s LR=1e-4
Testiranje
Istovar vijuga je koristan za procjenu koliko dijelova možemo ukloniti u određenom koraku. Primjeri istovara:
Vidimo da gotovo posvuda 5% vijuga ima vrlo nisku L1-normu i možemo ih ukloniti. U svakom koraku ponavljalo se ovo istovaranje i procjenjivalo se koji se slojevi i koliko mogu izrezati.
Cijeli proces je dovršen u 4 koraka (brojevi ovdje i posvuda za RTX 2060 Super):
Korak
mAp75
Broj parametara, milijun
Veličina mreže, mb
Od početka, %
Vrijeme izvođenja, ms
Stanje obrezivanja
0
0.9656
60
241
100
180
-
1
0.9622
55
218
91
175
5% od svih
2
0.9625
50
197
83
168
5% od svih
3
0.9633
39
155
64
155
15% za slojeve s 400+ zavoja
4
0.9555
31
124
51
146
10% za slojeve s 100+ zavoja
Koraku 2 dodan je jedan pozitivan učinak - veličina serije 4 stala je u memoriju, što je znatno ubrzalo proces dodatne obuke.
U koraku 4 proces je zaustavljen jer čak ni dugotrajna dodatna obuka nije podigla mAp75 na stare vrijednosti.
Kao rezultat toga, uspjeli smo ubrzati zaključivanje za 15%, smanjite veličinu za 35% a ne izgubiti točno.
Automatizacija za jednostavnije arhitekture
Za jednostavnije mrežne arhitekture (bez uvjetnog dodavanja, spajanja i rezidualnih blokova), sasvim je moguće usredotočiti se na obradu svih zavojnih slojeva i automatizirati proces izrezivanja zavoja.
Implementirao sam ovu opciju здесь.
Jednostavno je: potrebna vam je samo funkcija gubitka, optimizator i batch generatori:
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)
Ako je potrebno, možete promijeniti konfiguracijske parametre:
{
"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
}
Osim toga, provodi se ograničenje temeljeno na standardnoj devijaciji. Cilj je ograničiti dio koji se uklanja, isključujući zavoje s već "dovoljnim" mjerama L1:
Stoga vam dopuštamo uklanjanje samo slabih zavoja iz distribucija sličnih desnoj i ne utječemo na uklanjanje iz distribucija sličnih lijevoj:
Kada se distribucija približi normalnoj, koeficijent pruning_standart_deviation_part može se odabrati između:
Preporučujem pretpostavku od 2 sigme. Ili možete zanemariti ovu značajku, ostavljajući vrijednost < 1.0.
Izlaz je grafikon veličine mreže, gubitaka i vremena rada mreže za cijeli test, normaliziran na 1.0. Na primjer, ovdje je veličina mreže smanjena gotovo 2 puta bez gubitka kvalitete (mala konvolucijska mreža s težinama od 100k):
Brzina vožnje je podložna normalnim fluktuacijama i ostaje gotovo nepromijenjena. Za to postoji objašnjenje:
Broj zavoja mijenja se od prikladnog (32, 64, 128) do ne najprikladnijeg za video kartice - 27, 51 itd. Možda griješim, ali najvjerojatnije ima učinka.
Arhitektura nije široka, ali dosljedna. Smanjenjem širine ne utječemo na dubinu. Dakle, smanjujemo opterećenje, ali ne mijenjamo brzinu.
Stoga je poboljšanje izraženo u smanjenju CUDA opterećenja tijekom rada za 20-30%, ali ne iu smanjenju vremena rada.
Rezultati
Razmislimo. Razmotrili smo 2 mogućnosti rezanja - za YOLOv3 (kada morate raditi rukama) i za mreže s jednostavnijom arhitekturom. Može se vidjeti da je u oba slučaja moguće postići smanjenje veličine mreže i ubrzanje bez gubitka točnosti. Rezultati:
Smanjenje veličine
Trčanje za ubrzanje
Smanjenje CUDA opterećenja
Kao rezultat, prihvatljivost okoliša (Optimiziramo buduću upotrebu računalnih resursa. Negdje je netko sretan Greta Thunberg)
Dodatak
Nakon koraka rezanja, možete dodati kvantizaciju (na primjer, s TensorRT)