Technique Jedi pour réduire les réseaux convolutifs - élagage

Technique Jedi pour réduire les réseaux convolutifs - élagage

Avant vous est à nouveau la tâche de détecter des objets. La priorité est la rapidité de fonctionnement avec une précision acceptable. Vous prenez l’architecture YOLOv3 et la formez davantage. La précision (mAp75) est supérieure à 0.95. Mais le taux de réussite reste faible. Merde.

Aujourd'hui, nous contournerons la quantification. Et sous la coupe nous regarderons Taille du modèle — supprimer les parties redondantes du réseau pour accélérer l'inférence sans perte de précision. Il est clair où, combien et comment couper. Voyons comment procéder manuellement et où vous pouvez l'automatiser. A la fin il y a un dépôt sur keras.

introduction

Sur mon ancien lieu de travail, Macroscop à Perm, j'ai acquis une habitude : toujours surveiller le temps d'exécution des algorithmes. Et vérifiez toujours le temps d’exécution du réseau via un filtre d’adéquation. Habituellement, l'état de l'art en matière de production ne passe pas ce filtre, ce qui m'a conduit à l'élagage.

L'élagage est un vieux sujet qui a été abordé dans Conférences de Stanford en 2017. L'idée principale est de réduire la taille du réseau formé sans perdre en précision en supprimant divers nœuds. Cela a l'air sympa, mais j'entends rarement parler de son utilisation. Il n'y a probablement pas assez d'implémentations, il n'y a pas d'articles en russe, ou tout simplement tout le monde considère qu'il s'agit d'un savoir-faire d'élagage et reste silencieux.
Mais démontons-le

Un aperçu de la biologie

J'adore quand le Deep Learning examine des idées issues de la biologie. Comme l’évolution, on peut leur faire confiance (saviez-vous que ReLU est très similaire à fonction de l'activation des neurones dans le cerveau?)

Le processus de Model Pruning est également proche de la biologie. La réponse du réseau peut ici être comparée à la plasticité du cerveau. Il y a quelques exemples intéressants dans le livre. Normand Doidge:

  1. Le cerveau d’une femme née avec seulement une moitié s’est reprogrammé pour remplir les fonctions de la moitié manquante.
  2. Le gars a détruit la partie de son cerveau responsable de la vision. Au fil du temps, d’autres parties du cerveau ont pris en charge ces fonctions. (nous n'essayons pas de répéter)

De même, vous pouvez supprimer certaines des convolutions faibles de votre modèle. En dernier recours, les paquets restants permettront de remplacer ceux coupés.

Aimez-vous l’apprentissage par transfert ou apprenez-vous à partir de zéro ?

Option numéro un. Vous utilisez Transfer Learning sur Yolov3. Retina, Mask-RCNN ou U-Net. Mais la plupart du temps, nous n'avons pas besoin de reconnaître 80 classes d'objets comme dans COCO. Dans ma pratique, tout est limité aux niveaux 1 et 2. On pourrait supposer que l’architecture de 80 classes est ici redondante. Cela suggère que l’architecture doit être réduite. De plus, j'aimerais le faire sans perdre les poids pré-entraînés existants.

Option numéro deux. Peut-être disposez-vous de beaucoup de données et de ressources informatiques, ou avez-vous simplement besoin d'une architecture ultra-personnalisée. Cela n'a pas d'importance. Mais vous apprenez le réseau à partir de zéro. La procédure habituelle consiste à examiner la structure des données, à sélectionner une architecture EXCESSIVE en puissance et à repousser les abandons du recyclage. J'ai vu 0.6 abandon, Karl.

Dans les deux cas, le réseau peut être réduit. Motivé. Voyons maintenant quel type de taille de circoncision est

Algorithme général

Nous avons décidé de supprimer les paquets. Cela a l'air assez simple :

Technique Jedi pour réduire les réseaux convolutifs - élagage

La suppression de toute convolution est stressante pour le réseau, ce qui entraîne généralement une augmentation des erreurs. D'une part, cette augmentation de l'erreur est un indicateur de la manière dont nous supprimons correctement les convolutions (par exemple, une augmentation importante indique que nous faisons quelque chose de mal). Mais une petite augmentation est tout à fait acceptable et est souvent éliminée par un léger entraînement supplémentaire ultérieur avec un petit LR. Ajoutez une étape de formation supplémentaire :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Nous devons maintenant déterminer quand nous voulons arrêter notre boucle Learning<->Pruning. Il peut y avoir des options exotiques ici lorsque nous devons réduire le réseau à une certaine taille et vitesse (par exemple, pour les appareils mobiles). Cependant, l’option la plus courante consiste à poursuivre le cycle jusqu’à ce que l’erreur devienne supérieure à l’acceptable. Ajoutez une condition :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Ainsi, l’algorithme devient clair. Reste à savoir comment déterminer les circonvolutions supprimées.

Rechercher des packages supprimés

Nous devons supprimer certaines circonvolutions. Se précipiter et « tirer » sur n’importe qui est une mauvaise idée, même si cela fonctionnera. Mais puisque vous avez une tête, vous pouvez réfléchir et essayer de sélectionner des circonvolutions « faibles » à supprimer. Il existe plusieurs options :

  1. Plus petite mesure L1 ou low_magnitude_pruning. L'idée selon laquelle les circonvolutions avec de petits poids contribuent peu à la décision finale
  2. Plus petite mesure L1 prenant en compte la moyenne et l'écart type. Nous complétons par une évaluation de la nature de la distribution.
  3. Masquage des convolutions et exclusion de celles qui influencent le moins la précision finale. Détermination plus précise de circonvolutions insignifiantes, mais très chronophage et gourmande en ressources.
  4. Autres

Chacune des options a droit à la vie et ses propres fonctionnalités de mise en œuvre. Nous considérons ici l'option avec la plus petite mesure L1

Processus manuel pour YOLOv3

L'architecture originale contient des blocs résiduels. Mais peu importe à quel point ils sont intéressants pour les réseaux profonds, ils nous gêneront quelque peu. La difficulté est que vous ne pouvez pas supprimer les rapprochements avec des index différents dans ces couches :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Par conséquent, sélectionnons les couches à partir desquelles nous pouvons librement supprimer les rapprochements :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Construisons maintenant un cycle de travail :

  1. Téléchargement d'activations
  2. Déterminer combien couper
  3. Découper
  4. Apprendre 10 époques avec LR=1e-4
  5. Test

Le déchargement des convolutions est utile pour estimer la quantité de partie que nous pouvons supprimer à une certaine étape. Exemples de déchargement :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Nous voyons que presque partout 5 % des circonvolutions ont une norme L1 très basse et nous pouvons les supprimer. A chaque étape, ce déchargement a été répété et une évaluation a été faite pour savoir quelles couches et combien pouvaient être découpées.

L'ensemble du processus s'est déroulé en 4 étapes (des numéros ici et partout pour la RTX 2060 Super) :

Étape carte75 Nombre de paramètres, millions Taille du réseau, Mo À partir de la valeur initiale, % Temps d'exécution, ms État de circoncision
0 0.9656 60 241 100 180 -
1 0.9622 55 218 91 175 5% de tous
2 0.9625 50 197 83 168 5% de tous
3 0.9633 39 155 64 155 15 % pour les couches avec plus de 400 convolutions
4 0.9555 31 124 51 146 10 % pour les couches avec plus de 100 convolutions

Un effet positif a été ajouté à l'étape 2 : la taille du lot 4 est entrée en mémoire, ce qui a considérablement accéléré le processus de formation supplémentaire.
À l'étape 4, le processus a été arrêté car même une formation complémentaire à long terme n'a pas élevé mAp75 aux anciennes valeurs.
En conséquence, nous avons réussi à accélérer l’inférence en 15%, réduisez la taille de 35% et ne pas perdre exactement.

Automatisation pour des architectures plus simples

Pour des architectures de réseau plus simples (sans ajout conditionnel, concaténation et blocs résiduels), il est tout à fait possible de se concentrer sur le traitement de toutes les couches convolutives et d'automatiser le processus de suppression des convolutions.

J'ai implémenté cette option ici.
C'est simple : vous n'avez besoin que d'une fonction de perte, d'un optimiseur et de générateurs de lots :

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)

Si nécessaire, vous pouvez modifier les paramètres de configuration :

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

De plus, une limitation basée sur l’écart type est implémentée. Le but est de limiter la partie qui est supprimée, en excluant les convolutions avec des mesures L1 déjà « suffisantes » :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Ainsi, nous vous permettons de supprimer uniquement les convolutions faibles des distributions similaires à celle de droite et de ne pas affecter la suppression des distributions similaires à celle de gauche :

Technique Jedi pour réduire les réseaux convolutifs - élagage

Lorsque la distribution s'approche de la normale, le coefficient pruning_standart_deviation_part peut être sélectionné parmi :

Technique Jedi pour réduire les réseaux convolutifs - élagage
Je recommande une hypothèse de 2 sigma. Ou vous pouvez ignorer cette fonctionnalité, en laissant la valeur < 1.0.

Le résultat est un graphique de la taille, de la perte et de la durée d'exécution du réseau pour l'ensemble du test, normalisé à 1.0. Par exemple, ici, la taille du réseau a été réduite de près de 2 fois sans perte de qualité (petit réseau convolutionnel avec des poids de 100 XNUMX) :

Technique Jedi pour réduire les réseaux convolutifs - élagage

La vitesse de déplacement est soumise à des fluctuations normales et reste pratiquement inchangée. Il y a une explication à cela :

  1. Le nombre de circonvolutions passe de pratique (32, 64, 128) à pas le plus pratique pour les cartes vidéo - 27, 51, etc. Je peux me tromper ici, mais cela a très probablement un effet.
  2. L'architecture n'est pas large, mais cohérente. En réduisant la largeur, nous n'affectons pas la profondeur. Ainsi, nous réduisons la charge, mais ne modifions pas la vitesse.

Par conséquent, l'amélioration s'est traduite par une réduction de la charge CUDA pendant l'exécution de 20 à 30 %, mais pas par une réduction du temps d'exécution.

Les résultats de

Réfléchissons. Nous avons envisagé 2 options d'élagage - pour YOLOv3 (quand vous devez travailler de vos mains) et pour les réseaux avec des architectures plus simples. On peut voir que dans les deux cas, il est possible de réduire et d’accélérer la taille du réseau sans perte de précision. Résultats:

  • Réduction de taille
  • Course d'accélération
  • Réduire la charge CUDA
  • En conséquence, le respect de l'environnement (Nous optimisons l'utilisation future des ressources informatiques. Quelque part on est heureux Greta Tunberg)

Appendice

  • Après l'étape d'élagage, vous pouvez ajouter une quantification (par exemple, avec TensorRT)
  • Tensorflow fournit des fonctionnalités pour low_magnitude_pruning. Travaux.
  • dépôt Je veux me développer et je serai heureux de vous aider

Source: habr.com

Ajouter un commentaire