Jedi tehnika za smanjenje konvolucionih mreža - orezivanje
Pred vama je ponovo zadatak otkrivanja objekata. Prioritet je brzina rada uz prihvatljivu preciznost. Uzimate YOLOv3 arhitekturu i dalje je obučavate. Preciznost (mAp75) je veća od 0.95. Ali stopa rada je još uvijek niska. Sranje.
Danas ćemo zaobići kvantizaciju. A ispod reza ćemo pogledati Model Obrezivanje — odsecanje suvišnih delova mreže radi ubrzanja zaključivanja bez gubitka tač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 se nalazi spremište na kerasu.
Uvod
Na prethodnom radnom mestu, Macroscop u Permu, stekao sam jednu naviku - da uvek pratim vreme izvršavanja algoritama. I uvijek provjerite vrijeme rada mreže kroz filter adekvatnosti. Obično najsavremenije u proizvodnji ne prođu ovaj filter, što me je dovelo do Obrezivanja.
Orezivanje je stara tema o kojoj se raspravljalo Stanford predavanja u 2017. Glavna ideja je smanjiti veličinu obučene mreže bez gubitka preciznosti uklanjanjem različitih čvorova. Zvuči super, ali rijetko čujem za njegovu upotrebu. Vjerovatno nema dovoljno implementacija, nema članaka na ruskom jeziku, ili jednostavno svi smatraju da to skraćuje znanje i šuti.
Ali hajde da ga rastavite
Pogled u biologiju
Sviđa mi se kada duboko učenje razmatra ideje koje dolaze iz biologije. Njima se, kao i evoluciji, može vjerovati (da li ste znali da je ReLU vrlo sličan funkcija aktivacije neurona u mozgu?)
Proces modelne rezidbe je također blizak biologiji. Odgovor mreže ovdje se može uporediti sa plastičnošću mozga. U knjizi ima nekoliko zanimljivih primjera. Norman Doidge:
Mozak žene koja je rođena sa samo jednom polovinom reprogramirao se da obavlja funkcije polovice koja nedostaje.
Tip mu je odbio dio mozga odgovoran za vid. Vremenom su te funkcije preuzeli drugi dijelovi mozga. (ne pokušavamo da ponovimo)
Isto tako, možete izrezati neke od slabih konvolucija iz vašeg modela. U krajnjem slučaju, preostali snopovi pomoći će zamijeniti izrezane.
Volite li transfer učenja ili učite od nule?
Opcija broj jedan. Koristite Transfer Learning na Yolov3. Retina, Mask-RCNN ili U-Net. Ali većinu vremena ne moramo 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 klasa ovdje suvišna. Ovo sugerira da arhitekturu treba smanjiti. Štaviše, želio bih to učiniti bez gubljenja postojećih prethodno uvježbanih tegova.
Opcija broj dva. Možda imate puno podataka i računarskih resursa, ili vam je samo potrebna super prilagođena arhitektura. Nije bitno. Ali učite mrežu od nule. Uobičajena procedura je da se pogleda struktura podataka, odabere arhitektura koja je PREKRASNA u snazi i potisne odustajanje od preobuke. Video sam 0.6 odustajanja, Karl.
U oba slučaja, mreža se može smanjiti. Motivisan. Hajde sada da shvatimo kakva je vrsta obrezivanja
Opći algoritam
Odlučili smo da možemo ukloniti snopove. Izgleda prilično jednostavno:
Uklanjanje bilo koje konvolucije je stresno za mrežu, što obično dovodi do određenog povećanja greške. S jedne strane, ovo povećanje greške je pokazatelj koliko ispravno uklanjamo konvolucije (na primjer, veliko povećanje ukazuje 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 Learning<->Obrezivanje. 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 sve dok greška ne postane veća od prihvatljive. Dodajte uslov:
Dakle, algoritam postaje jasan. Ostaje shvatiti kako odrediti izbrisane konvolucije.
Potražite izbrisane pakete
Moramo ukloniti neke zavoje. Juriti naprijed i "pucati" u bilo koga je loša ideja, iako će uspjeti. Ali budući da imate glavu, možete razmišljati i pokušati odabrati "slabe" konvolucije za uklanjanje. Postoji nekoliko opcija:
Svaka od opcija ima pravo na život i svoje karakteristike implementacije. Ovdje razmatramo opciju s najmanjom L1-mjerom
Ručni proces za YOLOv3
Originalna arhitektura sadrži preostale blokove. Ali koliko god da su cool za duboke mreže, donekle će nas ometati. Poteškoća je u tome što ne možete izbrisati usaglašavanja s različitim indeksima u ovim slojevima:
Stoga, izaberimo slojeve iz kojih možemo slobodno brisati usaglašavanja:
Sada napravimo ciklus rada:
Učitavanje aktivacija
Smišljanje koliko treba smanjiti
Sečenje
Učenje 10 epoha sa LR=1e-4
Testiranje
Rasterećenje konvolucija je korisno za procjenu koliko dijela možemo ukloniti u određenom koraku. Primjeri istovara:
Vidimo da skoro svuda 5% konvolucija ima vrlo nisku L1-normu i možemo ih ukloniti. U svakom koraku, ovo rasterećenje se ponavljalo i procjenjivalo se koji slojevi i koliko ih je moguće izrezati.
Ceo proces je završen u 4 koraka (brojevi ovde i svuda za RTX 2060 Super):
Korak
mAp75
Broj parametara, milion
Veličina mreže, mb
Od početnog, %
Vrijeme rada, 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 sa 400+ konvolucija
4
0.9555
31
124
51
146
10% za slojeve sa 100+ konvolucija
Korak 2 dodan je jedan pozitivan efekat - veličina serije 4 se uklapa 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 15%, smanjite veličinu za 35% i ne izgubiti tačno.
Automatizacija za jednostavnije arhitekture
Za jednostavnije mrežne arhitekture (bez uvjetnog dodavanja, spajanja i rezidualnih blokova) sasvim je moguće fokusirati se na obradu svih konvolucijskih slojeva i automatizirati proces izrezivanja konvolucija.
Ja sam implementirao ovu opciju ovdje.
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
}
Dodatno, implementirano je ograničenje zasnovano na standardnoj devijaciji. Cilj je ograničiti dio koji se uklanja, isključujući konvolucije s već "dovoljnim" L1 mjerama:
Stoga vam omogućavamo da uklonite samo slabe konvolucije iz distribucija sličnih desnoj i ne utičete na uklanjanje iz distribucija sličnih lijevoj:
Kada se distribucija približi normalnoj, koeficijent pruning_standart_deviation_part se može odabrati između:
Preporučujem pretpostavku od 2 sigma. Ili možete zanemariti ovu funkciju, ostavljajući vrijednost < 1.0.
Izlaz je graf veličine mreže, gubitka i vremena rada mreže za cijeli test, normaliziran na 1.0. Na primjer, ovdje je veličina mreže smanjena za skoro 2 puta bez gubitka kvalitete (mala konvolucijska mreža sa 100k težine):
Brzina trčanja je podložna normalnim fluktuacijama i ostaje gotovo nepromijenjena. Za ovo postoji objašnjenje:
Broj konvolucija se mijenja od pogodnih (32, 64, 128) do ne najprikladnijih za video kartice - 27, 51, itd. Možda grešim, ali najverovatnije ima efekta.
Arhitektura nije široka, ali konzistentna. Smanjenjem širine ne utičemo na dubinu. Tako smanjujemo opterećenje, ali ne mijenjamo brzinu.
Dakle, poboljšanje je izraženo u smanjenju opterećenja CUDA tokom trčanja za 20-30%, ali ne i u smanjenju vremena rada
Ishodi
Hajde da razmislimo. Razmotrili smo 2 opcije za smanjenje - za YOLOv3 (kada morate raditi rukama) i za mreže sa 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
Ubrzanje
Smanjenje CUDA opterećenja
Kao rezultat, ekološka prihvatljivost (Optimiziramo buduću upotrebu računarskih resursa. Negdje je neko zadovoljan Greta Thunberg)
dodatak
Nakon koraka rezanja, možete dodati kvantizaciju (na primjer, sa TensorRT)