Délégués GPU pour TensorFlow Lite

L'utilisation d'unités de traitement graphique (GPU) pour exécuter vos modèles d'apprentissage automatique (ML) peut améliorer considérablement les performances de votre modèle et l'expérience utilisateur de vos applications compatibles ML. TensorFlow Lite permet l'utilisation de GPU et d'autres processeurs spécialisés via un pilote matériel appelé délégués . L'activation de l'utilisation de GPU avec vos applications TensorFlow Lite ML peut offrir les avantages suivants :

  • Vitesse - Les GPU sont conçus pour un débit élevé de charges de travail massivement parallèles. Cette conception les rend bien adaptés aux réseaux de neurones profonds, qui se composent d'un grand nombre d'opérateurs, chacun travaillant sur des tenseurs d'entrée qui peuvent être traités en parallèle, ce qui entraîne généralement une latence plus faible. Dans le meilleur des cas, l'exécution de votre modèle sur un GPU peut être suffisamment rapide pour permettre des applications en temps réel qui n'étaient pas possibles auparavant.
  • Efficacité énergétique - Les GPU effectuent des calculs ML de manière très efficace et optimisée, consommant généralement moins d'énergie et générant moins de chaleur que la même tâche exécutée sur des processeurs.

Ce document fournit un aperçu de la prise en charge des GPU dans TensorFlow Lite et de certaines utilisations avancées des processeurs GPU. Pour plus d'informations sur la mise en œuvre de la prise en charge GPU sur des plates-formes spécifiques, consultez les guides suivants :

Prise en charge des opérations GPU ML

Il existe certaines limitations quant aux opérations TensorFlow ML, ou ops , qui peuvent être accélérées par le délégué GPU TensorFlow Lite. Le délégué prend en charge les opérations suivantes en précision flottante 16 bits et 32 bits :

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

Par défaut, toutes les opérations ne sont prises en charge qu'à la version 1. L'activation de la prise en charge de la quantification active les versions appropriées, par exemple, ADD v2.

Dépannage de la prise en charge du GPU

Si certaines des opérations ne sont pas prises en charge par le délégué GPU, le framework n'exécutera qu'une partie du graphique sur le GPU et la partie restante sur le CPU. En raison du coût élevé de la synchronisation CPU/GPU, un mode d'exécution fractionné comme celui-ci entraîne souvent des performances plus lentes que lorsque l'ensemble du réseau est exécuté sur le CPU seul. Dans ce cas, l'application génère des avertissements, tels que :

WARNING: op code #42 cannot be handled by this delegate.

Il n'y a pas de rappel pour les échecs de ce type, car il ne s'agit pas d'un échec d'exécution réel. Lorsque vous testez l'exécution de votre modèle avec le délégué GPU, vous devez être attentif à ces avertissements. Un nombre élevé de ces avertissements peut indiquer que votre modèle n'est pas le mieux adapté à une utilisation pour l'accélération GPU et peut nécessiter une refactorisation du modèle.

Exemples de modèles

Les exemples de modèles suivants sont conçus pour tirer parti de l'accélération GPU avec TensorFlow Lite et sont fournis à titre de référence et de test :

Optimisation pour les GPU

Les techniques suivantes peuvent vous aider à obtenir de meilleures performances lors de l'exécution de modèles sur du matériel GPU à l'aide du délégué GPU TensorFlow Lite :

  • Opérations de remodelage - Certaines opérations rapides sur un CPU peuvent avoir un coût élevé pour le GPU sur les appareils mobiles. Les opérations de remodelage sont particulièrement coûteuses à exécuter, notamment BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH , etc. Vous devez examiner attentivement l'utilisation des opérations de remodelage et considérer qu'elles peuvent avoir été appliquées uniquement pour l'exploration des données ou pour les premières itérations de votre modèle. Les supprimer peut améliorer considérablement les performances.

  • Canaux de données d'image - Sur GPU, les données de tenseur sont découpées en 4 canaux, et donc un calcul sur un tenseur de forme [B,H,W,5] fonctionne à peu près de la même manière sur un tenseur de forme [B,H,W,8] , mais significativement pire que [B,H,W,4] . Si le matériel de la caméra que vous utilisez prend en charge les cadres d'image en RGBA, l'alimentation de cette entrée à 4 canaux est nettement plus rapide, car elle évite une copie de la mémoire du RVB à 3 canaux vers le RGBX à 4 canaux.

  • Modèles optimisés pour les mobiles - Pour de meilleures performances, vous devez envisager de recycler votre classifieur avec une architecture de réseau optimisée pour les mobiles. L'optimisation de l'inférence sur l'appareil peut réduire considérablement la latence et la consommation d'énergie en tirant parti des fonctionnalités du matériel mobile.

Prise en charge avancée du processeur graphique

Vous pouvez utiliser des techniques avancées supplémentaires avec le traitement GPU pour améliorer encore les performances de vos modèles, y compris la quantification et la sérialisation. Les sections suivantes décrivent ces techniques plus en détail.

Utilisation de modèles quantifiés

Cette section explique comment le délégué GPU accélère les modèles quantifiés 8 bits, notamment :

Pour optimiser les performances, utilisez des modèles qui ont à la fois des tenseurs d'entrée et de sortie à virgule flottante.

Comment cela marche-t-il?

Étant donné que le backend GPU ne prend en charge que l'exécution en virgule flottante, nous exécutons des modèles quantifiés en lui donnant une "vue en virgule flottante" du modèle d'origine. À un niveau élevé, cela implique les étapes suivantes :

  • Les tenseurs constants (tels que les poids/biais) sont déquantifiés une fois dans la mémoire GPU. Cette opération se produit lorsque le délégué est activé pour TensorFlow Lite.

  • Les entrées et les sorties du programme GPU, si elles sont quantifiées sur 8 bits, sont déquantifiées et quantifiées (respectivement) pour chaque inférence. Cette opération est effectuée sur le CPU à l'aide des noyaux optimisés de TensorFlow Lite.

  • Des simulateurs de quantification sont insérés entre les opérations pour imiter le comportement quantifié. Cette approche est nécessaire pour les modèles où les ops s'attendent à ce que les activations suivent les limites apprises lors de la quantification.

Pour plus d'informations sur l'activation de cette fonctionnalité avec le délégué GPU, consultez les éléments suivants :

Réduction du temps d'initialisation grâce à la sérialisation

La fonctionnalité de délégué GPU vous permet de charger à partir du code du noyau précompilé et des données de modèle sérialisées et enregistrées sur le disque à partir des exécutions précédentes. Cette approche évite la recompilation et peut réduire le temps de démarrage jusqu'à 90 %. Cette amélioration est obtenue en échangeant de l'espace disque pour gagner du temps. Vous pouvez activer cette fonctionnalité avec quelques options de configuration, comme illustré dans les exemples de code suivants :

C++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

Lorsque vous utilisez la fonctionnalité de sérialisation, assurez-vous que votre code respecte ces règles de mise en œuvre :

  • Stockez les données de sérialisation dans un répertoire qui n'est pas accessible aux autres applications. Sur les appareils Android, utilisez getCodeCacheDir() qui pointe vers un emplacement privé pour l'application actuelle.
  • Le jeton de modèle doit être unique pour l'appareil pour le modèle spécifique. Vous pouvez calculer un jeton de modèle en générant une empreinte digitale à partir des données du modèle à l'aide de bibliothèques telles que farmhash::Fingerprint64 .