Tecnica Jedi per ridurre le reti convoluzionali - potatura

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Prima di te c'è di nuovo il compito di rilevare gli oggetti. La priorità è la velocità operativa con una precisione accettabile. Prendi l'architettura YOLOv3 e la addestri ulteriormente. La precisione (mAp75) è maggiore di 0.95. Ma il ritmo di esecuzione è ancora basso. Merda.

Oggi ignoreremo la quantizzazione. E sotto il taglio guarderemo Potatura del modello — tagliare parti ridondanti della rete per accelerare l'inferenza senza perdita di precisione. È chiaro dove, quanto e come tagliare. Scopriamo come farlo manualmente e dove puoi automatizzarlo. Alla fine c'è un repository su Keras.

Introduzione

Nel mio precedente posto di lavoro, Macroscop a Perm, ho acquisito un'abitudine: monitorare sempre il tempo di esecuzione degli algoritmi. E controlla sempre il runtime della rete attraverso un filtro di adeguatezza. Solitamente lo stato dell'arte della produzione non passa questo filtro, il che mi ha portato a Pruning.

La potatura è un vecchio argomento di cui si parlava Lezioni di Stanford nel 2017. L'idea principale è ridurre le dimensioni della rete addestrata senza perdere la precisione rimuovendo vari nodi. Sembra interessante, ma raramente sento parlare del suo utilizzo. Probabilmente non ci sono abbastanza implementazioni, non ci sono articoli in lingua russa, o semplicemente tutti pensano che si tratti di un know-how di potatura e tacciono.
Ma analizziamolo

Uno sguardo alla biologia

Mi piace quando il Deep Learning esamina le idee che provengono dalla biologia. Di loro, come dell'evoluzione, ci si può fidare (sapevi che ReLU è molto simile a funzione di attivazione dei neuroni nel cervello?)

Anche il processo di potatura del modello è vicino alla biologia. La risposta della rete in questo caso può essere paragonata alla plasticità del cervello. Nel libro ci sono un paio di esempi interessanti. Norman Dodge:

  1. Il cervello di una donna nata con solo una metà si è riprogrammato per svolgere le funzioni della metà mancante.
  2. Il ragazzo ha sparato alla parte del suo cervello responsabile della vista. Nel corso del tempo, altre parti del cervello hanno assunto queste funzioni. (non stiamo cercando di ripetere)

Allo stesso modo, puoi eliminare alcune delle convoluzioni deboli dal tuo modello. Come ultima risorsa, i fasci rimanenti aiuteranno a sostituire quelli tagliati.

Ti piace il Transfer Learning o stai imparando da zero?

Opzione numero uno. Utilizzi Transfer Learning su Yolov3. Retina, Mask-RCNN o U-Net. Ma la maggior parte delle volte non abbiamo bisogno di riconoscere 80 classi di oggetti come in COCO. Nella mia pratica, tutto è limitato ai gradi 1-2. Si potrebbe supporre che l'architettura per 80 classi sia qui ridondante. Ciò suggerisce che l’architettura deve essere rimpicciolita. Inoltre, vorrei farlo senza perdere i pesi preallenati esistenti.

Opzione numero due. Forse hai molti dati e risorse informatiche o hai semplicemente bisogno di un'architettura super personalizzata. Non importa. Ma stai imparando la rete da zero. La procedura abituale consiste nell'esaminare la struttura dei dati, selezionare un'architettura che sia ECCESSIVA in termini di potenza e spingere gli abbandonati dalla riqualificazione. Ho visto 0.6 abbandoni, Karl.

In entrambi i casi la rete può essere ridotta. Motivata. Adesso andiamo a capire che tipo di potatura circoncisa è

Algoritmo generale

Abbiamo deciso che potevamo rimuovere i fasci. Sembra abbastanza semplice:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Rimuovere qualsiasi convoluzione è stressante per la rete, il che di solito porta ad un aumento degli errori. Da un lato, questo aumento dell'errore è un indicatore di quanto correttamente rimuoviamo le convoluzioni (ad esempio, un grande aumento indica che stiamo facendo qualcosa di sbagliato). Ma un piccolo aumento è abbastanza accettabile e spesso viene eliminato da un successivo allenamento leggero e aggiuntivo con un LR piccolo. Aggiungi un ulteriore passaggio di formazione:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Ora dobbiamo capire quando vogliamo interrompere il nostro ciclo di apprendimento<->potatura. Potrebbero esserci opzioni esotiche qui quando dobbiamo ridurre la rete a una certa dimensione e velocità (ad esempio, per i dispositivi mobili). Tuttavia, l'opzione più comune è continuare il ciclo finché l'errore non diventa superiore a quello accettabile. Aggiungi una condizione:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Quindi, l’algoritmo diventa chiaro. Resta da capire come determinare le convoluzioni cancellate.

Cerca i pacchetti eliminati

Dobbiamo rimuovere alcune circonvoluzioni. Correre avanti e “sparare” a qualcuno è una cattiva idea, anche se funzionerà. Ma poiché hai una testa, puoi pensare e provare a selezionare le circonvoluzioni "deboli" da rimuovere. Ci sono diverse opzioni:

  1. Misura L1 più piccola o potatura_bassa_magnitudine. L'idea che le convoluzioni con pesi piccoli contribuiscano poco alla decisione finale
  2. Misura L1 più piccola che tiene conto della media e della deviazione standard. Integriamo con una valutazione della natura della distribuzione.
  3. Mascherare le convoluzioni ed escludere quelle che influenzano meno la precisione finale. Determinazione più accurata di convoluzioni insignificanti, ma dispendiosa in termini di tempo e risorse.
  4. Altrui

Ciascuna delle opzioni ha il diritto alla vita e le proprie caratteristiche di attuazione. Qui consideriamo l'opzione con la misura L1 più piccola

Processo manuale per YOLOv3

L'architettura originaria contiene isolati residui. Ma non importa quanto siano interessanti per le reti profonde, ci ostacoleranno in qualche modo. La difficoltà è che non è possibile eliminare riconciliazioni con indici diversi in questi livelli:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Selezioniamo quindi i layer dai quali possiamo eliminare liberamente le riconciliazioni:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Ora costruiamo un ciclo di lavoro:

  1. Caricamento attivazioni
  2. Capire quanto tagliare
  3. Dacci un taglio
  4. Imparare 10 epoche con LR=1e-4
  5. analisi

Le convoluzioni di scarico sono utili per stimare quanta parte possiamo rimuovere in un determinato passaggio. Esempi di scarico:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Vediamo che quasi ovunque il 5% delle convoluzioni ha una norma L1 molto bassa e possiamo rimuoverle. Ad ogni passaggio si ripeteva questo scarico e si valutava quali strati e quanti potevano essere tagliati.

L'intero processo è stato completato in 4 passaggi (numeri qui e ovunque per RTX 2060 Super):

Passomappa75Numero di parametri, milioniDimensioni della rete, MBDall'iniziale,%Tempo di esecuzione, signorinaCondizione di circoncisione
00.965660241100180-
10.96225521891175il 5% del totale
20.96255019783168il 5% del totale
30.9633391556415515% per layer con oltre 400 convoluzioni
40.9555311245114610% per layer con oltre 100 convoluzioni

Un effetto positivo è stato aggiunto alla fase 2: il batch di dimensione 4 si è adattato alla memoria, il che ha notevolmente accelerato il processo di formazione aggiuntiva.
Al passaggio 4, il processo è stato interrotto perché anche un allenamento aggiuntivo a lungo termine non ha riportato la mAp75 ai vecchi valori.
Di conseguenza, siamo riusciti ad accelerare l'inferenza di 15%, ridurre le dimensioni di 35% e non perdere esattamente.

Automazione per architetture più semplici

Per architetture di rete più semplici (senza aggiunte condizionali, blocchi concatenati e residui), è del tutto possibile concentrarsi sull'elaborazione di tutti gli strati convoluzionali e automatizzare il processo di eliminazione delle convoluzioni.

Ho implementato questa opzione qui.
È semplice: hai solo bisogno di una funzione di perdita, di un ottimizzatore e di generatori batch:

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)

Se necessario, puoi modificare i parametri di configurazione:

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

Inoltre, viene implementata una limitazione basata sulla deviazione standard. L’obiettivo è limitare la parte che viene rimossa, escludendo le convoluzioni con misure L1 già “sufficienti”:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Pertanto, ti consentiamo di rimuovere solo le convoluzioni deboli da distribuzioni simili a quella di destra e di non influenzare la rimozione da distribuzioni simili a quella di sinistra:

Tecnica Jedi per ridurre le reti convoluzionali - potatura

Quando la distribuzione si avvicina alla normalità, il coefficiente pruning_standart_deviation_part può essere selezionato da:

Tecnica Jedi per ridurre le reti convoluzionali - potatura
Raccomando un'ipotesi di 2 sigma. Oppure puoi ignorare questa funzionalità, lasciando il valore < 1.0.

L'output è un grafico delle dimensioni della rete, della perdita e del tempo di esecuzione della rete per l'intero test, normalizzato a 1.0. Ad esempio, qui la dimensione della rete è stata ridotta di quasi 2 volte senza perdita di qualità (piccola rete convoluzionale con pesi 100k):

Tecnica Jedi per ridurre le reti convoluzionali - potatura

La velocità di corsa è soggetta a normali fluttuazioni e rimane praticamente invariata. C'è una spiegazione per questo:

  1. Il numero di convoluzioni cambia da conveniente (32, 64, 128) a non il più conveniente per le schede video: 27, 51, ecc. Potrei sbagliarmi qui, ma molto probabilmente ha un effetto.
  2. L'architettura non è ampia, ma coerente. Riducendo la larghezza, non influiamo sulla profondità. Pertanto, riduciamo il carico, ma non modifichiamo la velocità.

Pertanto, il miglioramento si è espresso in una riduzione del carico CUDA durante la corsa del 20-30%, ma non in una riduzione del tempo di corsa

Risultati di

Riflettiamo. Abbiamo considerato 2 opzioni di potatura: per YOLOv3 (quando devi lavorare con le mani) e per reti con architetture più semplici. Si può vedere che in entrambi i casi è possibile ottenere una riduzione e un aumento della dimensione della rete senza perdita di precisione. Risultati:

  • Riduzione delle dimensioni
  • Corsa di accelerazione
  • Riduzione del carico CUDA
  • Di conseguenza, rispetto dell'ambiente (ottimizziamo l'uso futuro delle risorse informatiche. Da qualche parte si è felici Greta Tunberg)

Appendice

  • Dopo la fase di potatura, puoi aggiungere la quantizzazione (ad esempio, con TensorRT)
  • Tensorflow fornisce funzionalità per potatura_bassa_magnitudine. Lavori.
  • deposito Voglio svilupparmi e sarò felice di aiutarti

Fonte: habr.com

Acquista hosting affidabile per siti con protezione DDoS, server VPS VDS 🔥 Acquista un hosting web affidabile con protezione DDoS, server VPS e VDS | ProHoster