Jedi tehnika konvolutsiooniliste võrkude vähendamiseks – pügamine
Teie ees on jälle objektide tuvastamise ülesanne. Prioriteet - töö kiirus vastuvõetava täpsusega. Võtate YOLOv3 arhitektuuri ja treenite seda edasi. Täpsus (mAp75) on suurem kui 0.95. Kuid jooksukiirus on endiselt madal. Jama.
Täna läheme kvantiseerimisest mööda. Ja lõike all, kaaluge Mudeli pügamine - võrgu üleliigsete osade katkestamine, et kiirendada järelduste tegemist täpsust kaotamata. Selge – kus, kui palju ja kuidas lõigata. Mõelgem välja, kuidas seda käsitsi teha ja kus saab automatiseerida. Lõpus on hoidla kerasel.
Sissejuhatus
Viimases töökohas Macroscopis Permis omandasin ühe harjumuse – jälgida alati algoritmide täitmise aega. Ja võrgu tööaega tuleks alati kontrollida adekvaatsusfiltri kaudu. Tavaliselt tootmises olev tipptehnoloogia ei läbi seda filtrit, mis viis mind Pügamise juurde.
Pügamine on vana teema, mida arutati Stanfordi loengud aastal 2017. Põhiidee on vähendada koolitatud võrgu suurust täpsust kaotamata, eemaldades erinevaid sõlme. Kõlab lahedalt, aga kuulen selle kasutamisest harva. Tõenäoliselt pole rakendusi piisavalt, pole venekeelseid artikleid või lihtsalt kõik kaaluvad pügamisoskust ja vaikivad.
Aga lahti võtta
Pilk bioloogiasse
Mulle meeldib, kui bioloogiast pärinevad ideed uurivad süvaõpet. Neid, nagu ka evolutsiooni, saab usaldada (kas teadsite, et ReLU on väga sarnane aju neuronite aktiveerimise funktsioon?)
Mudeli pügamise protsess on samuti bioloogiale lähedane. Võrgu reaktsiooni saab siin võrrelda aju plastilisusega. Raamatus on paar huvitavat näidet. Norman Doidge:
Ainult ühe poolega sündinud naise aju programmeeris end ümber, et täita puuduva poole funktsioone
Mees tulistas oma aju nägemise eest vastutava osa maha. Aja jooksul võtsid need funktsioonid üle teised ajuosad. (ärge proovige korrata)
Nii et saate oma mudelist välja lõigata mõned nõrgad konvolutsioonid. Äärmuslikel juhtudel aitavad ülejäänud kimbud lõigatud kimbud asendada.
Kas teile meeldib ülekandeõpe või õpite nullist?
Variant number üks. Kasutate Yolov3-s ülekandeõpet. Retina, Mask-RCNN või U-Net. Kuid enamasti ei pea me tuvastama 80 objektiklassi nagu COCO-s. Minu praktikas piirdub kõik 1-2 klassiga. Võib oletada, et 80 klassi arhitektuur on siin üleliigne. Tekib mõte, et arhitektuuri on vaja vähendada. Pealegi tahaksin seda teha olemasolevaid eeltreenitud raskusi kaotamata.
Variant number kaks. Võib-olla on teil palju andmeid ja arvutusressursse või vajate lihtsalt ülikohandatud arhitektuuri. Vahet pole. Kuid te õpite võrku nullist. Tavaline järjekord - vaatame andmestruktuuri, valime võimsuse poolest ÜLILIIGSE arhitektuuri ja lükkame ümberõppest väljalangejaid. Ma nägin 0.6 väljalangejat, Carl.
Mõlemal juhul saab võrku vähendada. Edutati. Nüüd mõtleme välja, millist ümberlõikamist pügatakse
Üldine algoritm
Otsustasime, et saame konvolutsioonid eemaldada. See näeb välja väga lihtne:
Mis tahes keerdude eemaldamine on võrgu jaoks stressirohke, mis põhjustab tavaliselt vigade suurenemist. Ühest küljest näitab see vea suurenemine, kui õigesti me konvolutsioone eemaldame (näiteks näitab suur kasv, et teeme midagi valesti). Kuid väike tõus on üsna vastuvõetav ja sageli välistatakse selle hilisema kerge ümberõppega väikese LR-iga. Ümberõppeetapi lisamine:
Nüüd peame välja mõtlema, millal tahame oma õppimise<-> pügamistsükli peatada. Siin võib olla eksootilisi võimalusi, kui peame vähendama võrku teatud suuruse ja töökiiruseni (näiteks mobiilseadmete jaoks). Kõige tavalisem variant on aga tsükli jätkamine seni, kuni viga muutub vastuvõetavast suuremaks. Tingimuse lisamine:
Nii saab algoritm selgeks. Jääb veel välja mõelda, kuidas määrata eemaldatavad keerdud.
Eemaldatud kimpude leidmine
Peame eemaldama mõned keerdud. Ette tormamine ja ükskõik millise "tulistamine" on halb mõte, kuigi see toimib. Kuid kuna pea on olemas, võite mõelda ja proovida kustutamiseks valida "nõrgad" konvolutsioonid. Valikuid on mitu:
Igal valikul on õigus elule ja selle rakendusfunktsioonid. Siin käsitleme väikseima L1-mõõduga varianti
Käsitsi protsess YOLOv3 jaoks
Algne arhitektuur sisaldab jääkplokke. Kuid hoolimata sellest, kui lahedad need sügavate võrkude jaoks on, segavad nad meid pisut. Raskus seisneb selles, et nendes kihtides ei saa kustutada erinevate indeksitega kooskõlastusi:
Seetõttu valime kihid, millest saame kooskõlastusi vabalt eemaldada:
Nüüd koostame töötsükli:
Aktiveeringute üleslaadimine
Arutab, kui palju lõigata
Lõika välja
10 epohhi õppimine LR=1e-4
Testimine
Kogumite mahalaadimine on kasulik selleks, et hinnata, kui palju saame konkreetse etapi käigus eemaldada. Näitete üleslaadimine:
Näeme, et peaaegu kõikjal on 5% konvolutsioonidest väga madal L1-norm ja me saame need eemaldada. Igal etapil korrati sellist mahalaadimist ja hinnati, milliseid kihte ja kui palju saab lõigata.
Kogu protsess mahub 4 sammu (siin ja kõikjal RTX 2060 Super numbrid):
Samm
kaart75
Parameetrite arv, miljon
Võrgu suurus, mb
Originaalist, %
Tööaeg, ms
Lõikeseisund
0
0.9656
60
241
100
180
-
1
0.9622
55
218
91
175
5% kõigist
2
0.9625
50
197
83
168
5% kõigist
3
0.9633
39
155
64
155
15% kihtide puhul, millel on üle 400 kimbu
4
0.9555
31
124
51
146
10% kihtide puhul, millel on üle 100 kimbu
2. sammule lisati üks positiivne efekt - partii suurus 4 sai mällu, mis kiirendas oluliselt lisatreeningu protsessi.
4. etapil protsess peatati, kuna isegi pikaajaline lisatreening ei tõstnud mAp75 vanadele väärtustele.
Selle tulemusel oli võimalik järeldamist kiirendada 15%, vähendage suurust 35% ja ei kaota täpsust.
Automatiseerimine lihtsamate arhitektuuride jaoks
Lihtsamate võrguarhitektuuride puhul (ilma tingimusliku lisamise, konkaternatsiooni ja jääkplokkideta) on täiesti võimalik keskenduda kõigi konvolutsioonikihtide töötlemisele ja automatiseerida konvolutsioonide lõikamise protsessi.
Rakendasin selle võimaluse siin.
See on lihtne: teil on ainult kadufunktsioon, optimeerija ja partiigeneraatorid:
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)
Vajadusel saate muuta konfiguratsiooni parameetreid:
{
"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
}
Lisaks rakendatakse standardhälbel põhinev piirang. Eesmärk on piirata eemaldatud osa, jättes välja keerdud juba "piisavate" L1-meetmetega:
Seega lubame parempoolsetest jaotustest eemaldada ainult nõrgad konvolutsioonid ja mitte mõjutada vasakpoolsete jaotuste eemaldamist:
Kui jaotus läheneb normaalsele, saab pruning_standart_deviation_part koefitsiendi valida järgmiste hulgast:
Soovitan 2 sigma oletust. Või võite seda funktsiooni ignoreerida, jättes väärtuseks < 1.0.
Väljund on graafik võrgu suuruse, kaotuse ja võrgu tööaja kohta kogu testi jooksul, normaliseeritud väärtusele 1.0. Näiteks siin on võrgu suurust vähendatud peaaegu 2 korda ilma kvaliteeti kaotamata (väike konvolutsioonivõrk 100 XNUMX kaalu jaoks):
Jooksukiirus on tavapäraste kõikumiste all ja pole palju muutunud. Sellele on seletus:
Konvolutsioonide arv muutub mugavast (32, 64, 128) videokaartide jaoks mitte kõige mugavamaks - 27, 51 jne. Ma võin siin eksida, kuid ilmselt see nii on.
Arhitektuur ei ole lai, kuid ühtlane. Laiust vähendades me sügavust ei puuduta. Seega vähendame koormust, kuid ei muuda kiirust.
Seetõttu väljendus paranemine CUDA koormuse vähenemises jooksu ajal 20-30%, kuid mitte jooksuaja vähenemises
Tulemused
Mõtiskleme. Kaalusime 2 kärpimisvõimalust - YOLOv3 jaoks (kui peate oma kätega töötama) ja lihtsama arhitektuuriga võrkude jaoks. On näha, et mõlemal juhul on võimalik saavutada võrgu suuruse vähendamine ja kiirendus ilma täpsust kaotamata. Tulemused:
Suuruse vähendamine
Jooksu kiirendus
CUDA koormuse vähendamine
Selle tulemusena keskkonnasõbralikkus (Optimeerime arvutusressursside edaspidist kasutamist. Kuskil rõõmustatakse Greta Thunberg)
Lisa
Pärast pügamisetappi saate ka kvantiseerimist muuta (näiteks TensorRT-ga)