Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Før du igjen er oppgaven med å oppdage objekter. Prioriteten er operasjonshastighet med akseptabel nøyaktighet. Du tar YOLOv3-arkitekturen og trener den videre. Nøyaktigheten (mAp75) er større enn 0.95. Men løpsraten er fortsatt lav. Dritt.

I dag vil vi omgå kvantisering. Og under kuttet ser vi Modell Beskjæring — trimming av redundante deler av nettverket for å øke hastigheten på inferens uten tap av nøyaktighet. Det er tydelig hvor, hvor mye og hvordan du skal kutte. La oss finne ut hvordan du gjør dette manuelt og hvor du kan automatisere det. På slutten er det et depot på keras.

Innledning

På mitt forrige arbeidssted, Macroscop i Perm, fikk jeg en vane - å alltid overvåke utførelsestiden til algoritmer. Og kontroller alltid nettverkets kjøretid gjennom et tilstrekkelighetsfilter. Vanligvis passerer ikke toppmoderne produksjon dette filteret, noe som førte meg til Beskjæring.

Beskjæring er et gammelt tema som ble diskutert i Stanford forelesninger i 2017. Hovedideen er å redusere størrelsen på det trente nettverket uten å miste nøyaktigheten ved å fjerne ulike noder. Det høres kult ut, men jeg hører sjelden om bruken. Sannsynligvis er det ikke nok implementeringer, det er ingen russiskspråklige artikler, eller rett og slett alle anser det som beskjæring av kunnskap og forblir tause.
Men la oss ta det fra hverandre

Et innblikk i biologi

Jeg elsker det når Deep Learning ser på ideer som kommer fra biologi. De, som evolusjon, kan stole på (visste du at ReLU er veldig lik funksjon av nevronaktivering i hjernen?)

Modellbeskjæringsprosessen er også nær biologi. Nettverkets respons her kan sammenlignes med hjernens plastisitet. Det er et par interessante eksempler i boken. Norman Doidge:

  1. Hjernen til en kvinne som ble født med bare den ene halvdelen, har omprogrammert seg til å utføre funksjonene til den manglende halvdelen.
  2. Fyren skjøt av den delen av hjernen som var ansvarlig for synet. Over tid overtok andre deler av hjernen disse funksjonene. (vi prøver ikke å gjenta)

På samme måte kan du kutte ut noen av de svake konvolusjonene fra modellen din. Som en siste utvei vil de gjenværende buntene bidra til å erstatte de kuttede.

Elsker du Transfer Learning eller lærer du fra bunnen av?

Alternativ nummer én. Du bruker Transfer Learning på Yolov3. Retina, Mask-RCNN eller U-Net. Men mesteparten av tiden trenger vi ikke å gjenkjenne 80 objektklasser som i COCO. I min praksis er alt begrenset til klasse 1-2. Man kan anta at arkitekturen for 80 klasser er overflødig her. Dette tilsier at arkitekturen må gjøres mindre. Dessuten vil jeg gjerne gjøre dette uten å miste de eksisterende ferdigtrente vektene.

Alternativ nummer to. Kanskje du har mye data og dataressurser, eller trenger bare en supertilpasset arkitektur. spiller ingen rolle. Men du lærer nettverket fra bunnen av. Den vanlige prosedyren er å se på datastrukturen, velge en arkitektur som er OVERDRAGENDE i kraft, og presse frafall fra omskolering. Jeg så 0.6 frafall, Karl.

I begge tilfeller kan nettverket reduseres. Motivert. La oss nå finne ut hva slags omskjæring beskjæring er

Generell algoritme

Vi bestemte oss for at vi kunne fjerne buntene. Det ser ganske enkelt ut:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Å fjerne enhver konvolusjon er stressende for nettverket, noe som vanligvis fører til en viss økning i feil. På den ene siden er denne økningen i feil en indikator på hvor riktig vi fjerner konvolusjoner (for eksempel indikerer en stor økning at vi gjør noe galt). Men en liten økning er ganske akseptabelt og elimineres ofte ved påfølgende lett tilleggstrening med en liten LR. Legg til et ekstra treningstrinn:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Nå må vi finne ut når vi vil stoppe Learning<->Pruning loopen vår. Det kan være eksotiske alternativer her når vi skal redusere nettverket til en viss størrelse og hastighet (for eksempel for mobile enheter). Det vanligste alternativet er imidlertid å fortsette syklusen til feilen blir høyere enn akseptabelt. Legg til en betingelse:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Så algoritmen blir tydelig. Det gjenstår å finne ut hvordan man bestemmer de slettede konvolusjonene.

Søk etter slettede bunter

Vi må fjerne noen viklinger. Å skynde seg frem og "skyte" noen er en dårlig idé, selv om det vil fungere. Men siden du har et hode, kan du tenke og prøve å velge "svake" konvolusjoner for fjerning. Det er flere alternativer:

  1. Minste L1-mål eller lav_magnitude_beskjæring. Ideen om at konvolusjoner med små vekter i liten grad bidrar til den endelige avgjørelsen
  2. Minste L1-mål med hensyn til gjennomsnitt og standardavvik. Vi supplerer med en vurdering av fordelingens art.
  3. Maskere viklinger og ekskludere de som minst påvirker den endelige nøyaktigheten. Mer nøyaktig bestemmelse av ubetydelige viklinger, men svært tidkrevende og ressurskrevende.
  4. Andre

Hvert av alternativene har rett til liv og sine egne implementeringsfunksjoner. Her vurderer vi alternativet med det minste L1-målet

Manuell prosess for YOLOv3

Den opprinnelige arkitekturen inneholder restblokker. Men uansett hvor kule de er for dype nettverk, vil de hindre oss noe. Vanskeligheten er at du ikke kan slette avstemminger med forskjellige indekser i disse lagene:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

La oss derfor velge lag som vi fritt kan slette avstemminger fra:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

La oss nå bygge en arbeidssyklus:

  1. Laster opp aktiveringer
  2. Finner ut hvor mye du skal kutte
  3. Kutt ut
  4. Læring 10 epoker med LR=1e-4
  5. Testing

Lossing av konvolusjoner er nyttig for å estimere hvor mye del vi kan fjerne på et bestemt trinn. Eksempler på lossing:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Vi ser at nesten overalt 5 % av konvolusjonene har en veldig lav L1-norm og vi kan fjerne dem. Ved hvert trinn ble denne lossingen gjentatt og det ble gjort en vurdering av hvilke lag og hvor mange som kunne kuttes ut.

Hele prosessen ble fullført i 4 trinn (tall her og overalt for RTX 2060 Super):

Trinn mAp75 Antall parametere, millioner Nettverksstørrelse, mb Fra initial, % Kjøretid, ms Omskjæringstilstand
0 0.9656 60 241 100 180 -
1 0.9622 55 218 91 175 5 % av alle
2 0.9625 50 197 83 168 5 % av alle
3 0.9633 39 155 64 155 15 % for lag med 400+ viklinger
4 0.9555 31 124 51 146 10 % for lag med 100+ viklinger

En positiv effekt ble lagt til trinn 2 - batchstørrelse 4 passet inn i minnet, noe som i stor grad akselererte prosessen med tilleggstrening.
Ved trinn 4 ble prosessen stoppet pga selv langvarig tilleggstrening løftet ikke mAp75 til gamle verdier.
Som et resultat klarte vi å fremskynde slutningen med 15%, reduser størrelsen med 35% og ikke tape akkurat.

Automatisering for enklere arkitekturer

For enklere nettverksarkitekturer (uten betinget add, concaternate og residual blocks), er det fullt mulig å fokusere på å behandle alle konvolusjonslag og automatisere prosessen med å kutte ut konvolusjoner.

Jeg implementerte dette alternativet her.
Det er enkelt: du trenger bare en tapsfunksjon, en optimizer og batchgeneratorer:

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)

Om nødvendig kan du endre konfigurasjonsparametrene:

{
    "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
}

I tillegg implementeres en begrensning basert på standardavviket. Målet er å begrense delen som fjernes, unntatt konvolusjoner med allerede "tilstrekkelige" L1-mål:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Dermed lar vi deg fjerne bare svake konvolusjoner fra distribusjoner som ligner på den høyre og ikke påvirke fjerningen fra distribusjoner som ligner på den venstre:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Når fordelingen nærmer seg normal, kan pruning_standart_deviation_part koeffisienten velges fra:

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring
Jeg anbefaler en antagelse om 2 sigma. Eller du kan ignorere denne funksjonen og la verdien være < 1.0.

Utdataene er en graf over nettverksstørrelse, tap og nettverkskjøringstid for hele testen, normalisert til 1.0. For eksempel, her ble nettverksstørrelsen redusert med nesten 2 ganger uten tap av kvalitet (lite konvolusjonsnettverk med 100k vekter):

Jedi-teknikk for å redusere konvolusjonelle nettverk - beskjæring

Kjørehastigheten er underlagt normale svingninger og forblir praktisk talt uendret. Det er en forklaring på dette:

  1. Antall viklinger endres fra praktisk (32, 64, 128) til ikke det mest praktiske for skjermkort - 27, 51, etc. Jeg kan ta feil her, men mest sannsynlig har det en effekt.
  2. Arkitekturen er ikke bred, men konsekvent. Ved å redusere bredden påvirker vi ikke dybden. Dermed reduserer vi belastningen, men endrer ikke hastigheten.

Derfor ble forbedringen uttrykt i en reduksjon i CUDA-belastningen under kjøringen med 20-30 %, men ikke i en reduksjon i løpetiden

Resultater av

La oss reflektere. Vi vurderte 2 alternativer for beskjæring - for YOLOv3 (når du må jobbe med hendene) og for nettverk med enklere arkitekturer. Det kan sees at i begge tilfeller er det mulig å oppnå reduksjon og hastighet på nettverksstørrelse uten tap av nøyaktighet. Resultater:

  • Redusere størrelsen
  • Akselerasjonsløp
  • Reduserer CUDA-belastningen
  • Som et resultat, miljøvennlighet (Vi optimerer fremtidig bruk av dataressurser. Et sted er man fornøyd Greta Thunberg)

Vedlegg

  • Etter beskjæringstrinnet kan du legge til kvantisering (for eksempel med TensorRT)
  • Tensorflow gir muligheter for lav_magnitude_beskjæring. Virker.
  • oppbevaringssted Jeg ønsker å utvikle meg og vil gjerne hjelpe

Kilde: www.habr.com

Legg til en kommentar