[Déploiement du modèle] Tutoriel de démarrage (3) : Explication détaillée de PyTorch à ONNX

Tutoriel d'introduction au déploiement de modèles (3) : Explication détaillée de PyTorch à ONNX - Zhihu (zhihu.com)

Dans les deux tutoriels précédents , nous avons amené tout le monde à réussir le déploiement du premier modèle et résolu certaines difficultés pouvant être rencontrées lors du déploiement du modèle. À partir d'aujourd'hui, nous présenterons les connaissances liées à ONNX, du superficiel au plus profond. ONNX est actuellement l'une des représentations intermédiaires les plus importantes pour le déploiement de modèles. Après avoir appris les détails techniques d'ONNX, vous pouvez éviter de nombreux problèmes de déploiement de modèles.
Lors de la conversion d'un modèle PyTorch en modèle ONNX, nous n'avons souvent besoin d'appeler qu'une seule phrase facilement torch.onnx.export. L'interface de cette fonction semble simple, mais il existe de nombreuses "règles cachées" dans son utilisation. Dans ce didacticiel, nous présenterons en détail le principe et les précautions de conversion du modèle PyTorch en modèle ONNX. De plus, nous présenterons également la correspondance des opérateurs entre PyTorch et ONNX pour vous apprendre à gérer les problèmes de support des opérateurs qui peuvent être rencontrés lors de la conversion du modèle PyTorch.

Un aperçu : dans les articles suivants, nous continuerons à présenter comment prendre en charge davantage d'opérateurs ONNX dans PyTorch, afin que chacun puisse parcourir complètement la route de déploiement de PyTorch à ONNX ; présenter la connaissance d'ONNX lui-même, et modifier et déboguer ONNX Le Une approche commune du modèle vous permet de résoudre vous-même la plupart des problèmes de déploiement liés à ONNX. Restez à l'écoute ~

torch.onnx.export Panne


Dans cette section, nous présenterons en détail la fonction de conversion de PyTorch vers ONNX -  torch.onnx.export. Nous espérons que vous pourrez utiliser cette interface de conversion de modèle avec plus de souplesse et comprendre son principe de mise en œuvre pour mieux gérer l'erreur de cette fonction (en raison de la compatibilité du déploiement de modèle, cette fonction signale souvent des erreurs lors du déploiement de modèles complexes).


Méthode d'exportation du graphique de calcul

TorchScript  est un format de sérialisation et d'optimisation des modèles PyTorch. Lors de l'optimisation, un torch.nn.Modulemodèle est converti en  torch.jit.ScriptModulemodèle TorchScript. Désormais, TorchScript est également souvent utilisé comme représentation intermédiaire. Nous avons une introduction détaillée à TorchScript dans d'autres articles ( Interprétation de TorchScript (1): Apprendre à connaître TorchScript pour la première fois - Zhihu ), et l'introduction de TorchScript ici n'est utilisée que pour illustrer le principe de conversion des modèles PyTorch en ONNX.
torch.onnx.exportLe modèle requis dans est en fait un fichier torch.jit.ScriptModule. Pour convertir le modèle PyTorch ordinaire en un tel modèle TorchScript, il existe deux méthodes d'exportation du graphique de calcul : la trace et le script. Si torch.onnx.exportun modèle PyTorch normal ( torch.nn.Module) est transmis, le modèle sera exporté à l'aide de la méthode de trace par défaut. Ce processus est illustré dans la figure ci-dessous :

Rappelez-vous les connaissances de notre premier tutoriel : la méthode de suivi ne peut exporter le graphe statique du modèle qu'en exécutant réellement le modèle une fois, c'est-à-dire qu'elle ne peut pas identifier le flux de contrôle (comme les boucles) dans le modèle ; la méthode d'enregistrement peut correctement enregistrer tous les flux de contrôle. Prenons le code suivant comme exemple pour voir la différence entre ces deux méthodes de conversion :

import torch 
 
class Model(torch.nn.Module): 
    def __init__(self, n): 
        super().__init__() 
        self.n = n 
        self.conv = torch.nn.Conv2d(3, 3, 3) 
 
    def forward(self, x): 
        for i in range(self.n): 
            x = self.conv(x) 
        return x 
 
 
models = [Model(2), Model(3)] 
model_names = ['model_2', 'model_3'] 
 
for model, model_name in zip(models, model_names): 
    dummy_input = torch.rand(1, 3, 10, 10) 
    dummy_output = model(dummy_input) 
    model_trace = torch.jit.trace(model, dummy_input) 
    model_script = torch.jit.script(model) 
 
    # 跟踪法与直接 torch.onnx.export(model, ...)等价 
    torch.onnx.export(model_trace, dummy_input, f'{model_name}_trace.onnx', example_outputs=dummy_output) 
    # 记录法必须先调用 torch.jit.sciprt 
    torch.onnx.export(model_script, dummy_input, f'{model_name}_script.onnx', example_outputs=dummy_output) 

Dans ce code, nous définissons un modèle avec une boucle, et le modèle ncontrôle le nombre de fois où le tenseur d'entrée est convolué à travers des paramètres. Ensuite, nous avons chacun créé un modèle de n=2et n=3. Nous exportons ces deux modèles par des méthodes de suivi et d'enregistrement, respectivement.
Il convient de mentionner que puisque les deux modèles ( model_tracemodel_script) ici sont des modèles TorchScript, exportla fonction n'a pas besoin de réexécuter le modèle. (Si le modèle est obtenu à l'aide de la méthode de suivi, torch.jit.traceil sera exécuté une fois pendant l'exécution ; et lorsque la méthode d'enregistrement est utilisée pour l'exportation, le modèle n'a pas besoin d'être réellement dummy_inputexécuté dummy_output) type de tenseurs d'entrée et de sortie et forme.
Exécutez le code ci-dessus, nous visualisons les 4 fichiers onnx obtenus avec Netron :

Examinons d'abord la structure du modèle ONNX obtenue par la méthode de suivi. On peut voir que  nla structure du modèle ONNX est différente pour différents modèles.

Avec la méthode d'enregistrement, le modèle ONNX final utilise  Loop des nœuds pour représenter les boucles. De cette façon, même pour différents modèles  nONNX, les modèles ONNX ont la même structure.

La version de PyTorch utilisée dans cet article est la 1.8.2. Selon les commentaires, d'autres versions de PyTorch peuvent obtenir des résultats différents.

Étant donné que le moteur d'inférence prend mieux en charge les graphiques statiques, nous n'avons généralement pas besoin de convertir explicitement le modèle PyTorch en modèle TorchScript lors du déploiement du modèle, et nous pouvons directement exporter le modèle PyTorch avec trace  torch.onnx.export . Comprendre cette partie des connaissances consiste principalement à mieux localiser si le problème se produit à l'étape PyTorch vers TorchScript lorsque l'erreur de conversion du modèle est signalée.

Explication des paramètres

Après avoir compris le principe de la fonction de conversion, introduisons en détail la fonction des principaux paramètres de la fonction. Nous présenterons principalement comment chaque paramètre doit être défini dans différents scénarios de déploiement de modèle du point de vue de l'application, au lieu d'énumérer toutes les méthodes de définition de chaque paramètre. Pour la documentation API détaillée de cette fonction, veuillez vous référer à :  torch.onnx ‒ La documentation PyTorch 1.11.0 est définie dans le fichier comme suit
torch.onnx.export : torch.onnx.__init__.py

def export(model, args, f, export_params=True, verbose=False, training=TrainingMode.EVAL, 
           input_names=None, output_names=None, aten=False, export_raw_ir=False, 
           operator_export_type=None, opset_version=None, _retain_param_name=True, 
           do_constant_folding=True, example_outputs=None, strip_doc_string=True, 
           dynamic_axes=None, keep_initializers_as_inputs=None, custom_opsets=None, 
           enable_onnx_checker=True, use_external_data_format=False): 

Les trois premiers paramètres requis sont le modèle, l'entrée du modèle et le nom du fichier onnx exporté. Nous connaissons déjà ces paramètres. Concentrons-nous plus tard sur certains des paramètres facultatifs couramment utilisés.

export_params

S'il faut stocker les poids du modèle dans le modèle. Généralement, la représentation intermédiaire contient deux types d'informations : la structure du modèle et le poids du modèle Ces deux types d'informations peuvent être stockées dans le même fichier ou stockées dans des fichiers séparés. ONNX utilise le même fichier pour représenter la structure et le poids du modèle d'enregistrement.
Nous avons généralement par défaut ce paramètre sur True lors du déploiement. Si le fichier onnx est utilisé pour transférer des modèles entre différents frameworks (tels que PyTorch vers Tensorflow) plutôt que pour le déploiement, ce paramètre peut être défini sur False.

noms_entrée, noms_sortie

Définissez les noms des tenseurs d'entrée et de sortie. S'il n'est pas défini, un nom simple (comme un numéro) sera automatiquement attribué.
Chaque tenseur d'entrée et de sortie d'un modèle ONNX porte un nom. Lorsque de nombreux moteurs d'inférence exécutent des fichiers ONNX, ils doivent saisir des données sous la forme de paires de données "nom-valeur de tenseur" et obtenir des données de sortie en fonction du nom du tenseur de sortie. Lorsque vous effectuez des réglages liés au tenseur (comme l'ajout de dimensions dynamiques), vous devez également connaître le nom du tenseur.
Dans le pipeline de déploiement réel, nous devons tous définir les noms des tenseurs d'entrée et de sortie, et nous assurer qu'ONNX et le moteur d'inférence utilisent le même ensemble de noms.

opset_version

À quelle version du poste opérateur ONNX se référer lors de la conversion, la valeur par défaut est 9. La correspondance des opérateurs entre PyTorch et ONNX sera présentée en détail ultérieurement.

axes_dynamiques

Spécifie les dimensions des Tensors d'entrée et de sortie qui sont dynamiques.
Afin de rechercher l'efficacité, ONNX définit par défaut que tous les tenseurs impliqués dans l'opération sont statiques (la forme du tenseur ne change pas). Mais dans les applications pratiques, nous espérons que le tenseur d'entrée du modèle est dynamique, en particulier le modèle entièrement convolutif qui n'a aucune restriction de forme. Par conséquent, nous devons indiquer explicitement quelles dimensions des tenseurs d'entrée et de sortie sont de taille variable.
Regardons un dynamic_axesexemple de configuration :

import torch 
 
class Model(torch.nn.Module): 
    def __init__(self): 
        super().__init__() 
        self.conv = torch.nn.Conv2d(3, 3, 3) 
 
    def forward(self, x): 
        x = self.conv(x) 
        return x 
 
 
model = Model() 
dummy_input = torch.rand(1, 3, 10, 10) 
model_names = ['model_static.onnx',  
'model_dynamic_0.onnx',  
'model_dynamic_23.onnx'] 
 
dynamic_axes_0 = { 
    'in' : [0], 
    'out' : [0] 
} 
dynamic_axes_23 = { 
    'in' : [2, 3], 
    'out' : [2, 3] 
} 
 
torch.onnx.export(model, dummy_input, model_names[0],  
input_names=['in'], output_names=['out']) 
torch.onnx.export(model, dummy_input, model_names[1],  
input_names=['in'], output_names=['out'], dynamic_axes=dynamic_axes_0) 
torch.onnx.export(model, dummy_input, model_names[2],  
input_names=['in'], output_names=['out'], dynamic_axes=dynamic_axes_23) 

Tout d'abord, nous exportons 3 modèles ONNX, qui sont des modèles sans dimension dynamique, dynamique à 0 dimension et dynamique à 2e et 3e dimensions.
Dans ce code, nous représentons des dimensions dynamiques dans une liste, par exemple :

dynamic_axes_0 = { 
    'in' : [0], 
    'out' : [0] 
} 


Étant donné qu'ONNX exige que chaque dimension dynamique ait un nom, l'écrire ainsi conduira à un UserWarning, nous avertissant que le système leur attribuera automatiquement des noms si nous définissons les dimensions dynamiques via une liste. Une façon d'ajouter explicitement des noms de dimensions dynamiques est la suivante :

dynamic_axes_0 = { 
    'in' : {0: 'batch'}, 
    'out' : {0: 'batch'} 
} 

Comme nous n'avons plus d'opérations sur les dimensions dynamiques dans ce code, nous pouvons simplement spécifier les dimensions dynamiques avec une liste.
Après cela, utilisons le code suivant pour examiner le rôle des dimensions dynamiques :

import onnxruntime 
import numpy as np 
 
origin_tensor = np.random.rand(1, 3, 10, 10).astype(np.float32) 
mult_batch_tensor = np.random.rand(2, 3, 10, 10).astype(np.float32) 
big_tensor = np.random.rand(1, 3, 20, 20).astype(np.float32) 
 
inputs = [origin_tensor, mult_batch_tensor, big_tensor] 
exceptions = dict() 
 
for model_name in model_names: 
    for i, input in enumerate(inputs): 
        try: 
            ort_session = onnxruntime.InferenceSession(model_name) 
            ort_inputs = {'in': input} 
            ort_session.run(['out'], ort_inputs) 
        except Exception as e: 
            exceptions[(i, model_name)] = e 
            print(f'Input[{i}] on model {model_name} error.') 
        else: 
            print(f'Input[{i}] on model {model_name} succeed.') 

Nous utilisons un (1, 3, 10, 10)tenseur de forme lors de l'exportation du graphe de calcul à partir du modèle. Maintenant, essayons d'utiliser les formes en (1, 3, 10, 10), (2, 3, 10, 10), (1, 3, 20, 20)entrée, exécutons ces modèles avec ONNX Runtime, voyons dans quelles circonstances une erreur sera signalée et enregistrons les informations d'erreur correspondantes. La sortie résultante devrait être la suivante :

Input[0] on model model_static.onnx succeed. 
Input[1] on model model_static.onnx error. 
Input[2] on model model_static.onnx error. 
Input[0] on model model_dynamic_0.onnx succeed. 
Input[1] on model model_dynamic_0.onnx succeed. 
Input[2] on model model_dynamic_0.onnx error. 
Input[0] on model model_dynamic_23.onnx succeed. 
Input[1] on model model_dynamic_23.onnx error. 
Input[2] on model model_dynamic_23.onnx succeed. 

On peut voir que (1, 3, 10, 10)l'entrée avec la même forme ne fait pas d'erreurs sur tous les modèles. Pour les entrées avec un lot (0ème dimension) ou une longueur et une largeur (2ème et 3ème dimensions) différents, aucune erreur ne se produira jusqu'à ce que la dimension dynamique correspondante soit définie. Nous pouvons savoir quelles dimensions sont erronées dans le message d'erreur. Par exemple, nous pouvons utiliser le code suivant pour afficher le message d'erreur input[1]dansmodel_static.onnx :

print(exceptions[(1, 'model_static.onnx')]) 
 
# output 
# [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Got invalid dimensions for input: in for the following indices index: 0 Got: 2 Expected: 1 Please fix either the inputs or the model. 

Ce message d'erreur nous indique que inla 0ème dimension de l'entrée nommée ne correspond pas. À l'origine, la longueur de cette dimension devrait être 1, mais notre entrée est 2. Dans le déploiement réel, si nous rencontrons des erreurs similaires, nous pouvons résoudre le problème en définissant des dimensions dynamiques.

Utiliser les suggestions

En apprenant les connaissances précédentes, nous avons fondamentalement maîtrisé  torch.onnx.exportle principe de réalisation partielle et la méthode de paramétrage de la fonction, ce qui est suffisant pour compléter la conversion du modèle simple. Mais dans les applications pratiques, l'utilisation de cette fonction se heurtera à de nombreux pièges. Ici, notre équipe de déploiement de modèles partage avec vous une expérience accumulée en combat réel.

Faire en sorte que les modèles se comportent différemment lorsqu'ils sont convertis dans ONNX

Parfois, nous voulons que le modèle ait des comportements différents lorsqu'il est exporté vers ONNX. Le modèle a un ensemble de logique lorsqu'il est déduit directement avec PyTorch, et un autre ensemble de logique dans le modèle ONNX exporté. Par exemple, nous pouvons mettre une logique de post-traitement dans le modèle pour simplifier le code autre que l'exécution du modèle. torch.onnx.is_in_onnx_export()Pour accomplir cette tâche, la fonction  torch.onnx.export()n'est vraie que lors de son exécution. Voici un exemple:

import torch 
 
class Model(torch.nn.Module): 
    def __init__(self): 
        super().__init__() 
        self.conv = torch.nn.Conv2d(3, 3, 3) 
 
    def forward(self, x): 
        x = self.conv(x) 
        if torch.onnx.is_in_onnx_export(): 
            x = torch.clip(x, 0, 1) 
        return x 


Ici, nous limitons uniquement la valeur du tenseur de sortie à [0, 1] lorsque le modèle est exporté. Son utilisation  is_in_onnx_exportnous permet d'ajouter facilement une logique liée au déploiement du modèle dans le code. Cependant, ces codes sont très hostiles aux développeurs et aux utilisateurs qui ne se soucient que de la formation des modèles, et la logique de déploiement abrupte réduira la lisibilité globale du code. Dans le même temps, is_in_onnx_exportil ne peut être "correctif" qu'à chaque endroit où une logique de déploiement doit être ajoutée, ce qui rend difficile la réalisation d'une gestion unifiée. Nous présenterons comment utiliser le mécanisme de réécriture de MMDeploy pour éviter ces problèmes plus tard.

Opérations suivies à l'aide de tenseurs d'interruption

La méthode d'exportation de suivi de PyTorch vers ONNX est-elle une panacée ? Si nous effectuons des opérations "prêtes à l'emploi" dans le modèle, la méthode de suivi transformera certains résultats intermédiaires qui dépendent de l'entrée en constantes, de sorte que le modèle ONNX exporté sera différent du modèle d'origine. Voici un exemple de ce qui causerait cette "rupture de trace":

class Model(torch.nn.Module): 
    def __init__(self): 
        super().__init__() 
 
    def forward(self, x): 
        x = x * x[0].item() 
        return x, torch.Tensor([i for i in x]) 
 
model = Model()       
dummy_input = torch.rand(10) 
torch.onnx.export(model, dummy_input, 'a.onnx') 

Si vous essayez d'exporter ce modèle, vous recevrez de nombreux avertissements, vous indiquant que le modèle converti n'est peut-être pas correct. Il n'est pas étonnant que dans ce modèle, nous utilisions .item()le tenseur de torche pour le convertir en une variable Python normale, et essayions de traverser le tenseur de torche et de créer un nouveau tenseur de torche avec une liste. Ces logiques impliquant la conversion de tenseurs et de variables ordinaires rendront le modèle ONNX final incorrect.
D'autre part, nous pouvons également utiliser cette propriété pour ordonner que les résultats intermédiaires du modèle deviennent constants sous la prémisse d'assurer l'exactitude. Cette technique est souvent utilisée pour rendre les modèles statiques, c'est-à-dire que toutes les formes de tenseurs du modèle deviennent constantes. Dans de futurs tutoriels, nous détaillerons ces opérations "avancées" dans des exemples de déploiement.

Utiliser des tenseurs comme entrée (PyTorch version < 1.9.0)

Comme indiqué dans notre premier didacticiel , l'ancien (< 1.9.0) PyTorch  torch.onnx.export()génère une erreur lors de l'introduction de valeurs Python dans un modèle. Par souci de compatibilité, nous recommandons toujours d'utiliser le tenseur comme entrée de modèle lors de la conversion du modèle.

Support opérateur de PyTorch pour ONNX

Après s'être assuré torch.onnx.export()que la méthode d'appel est correcte, le problème le plus probable lors de la conversion de PyTorch en ONNX est que l'opérateur n'est pas compatible. Ici, nous allons vous présenter comment juger si un opérateur PyTorch est compatible dans ONNX, afin de vous aider à mieux classer les erreurs lorsque vous rencontrez des erreurs. La méthode spécifique d'ajout d'opérateurs sera présentée dans un article ultérieur.
Lors de la conversion torch.nn.Modulede modèles ordinaires, PyTorch utilisera la méthode de suivi pour effectuer un raisonnement en avant et intégrer les opérateurs rencontrés dans un graphe de calcul ; d'autre part, PyTorch traduira également chaque opérateur rencontré en opérateur ONNX. Au cours de ce processus de traduction, les situations suivantes peuvent être rencontrées :

  • Cet opérateur peut être traduit en un opérateur ONNX un à un.
  • Cet opérateur n'a pas d'opérateur correspondant direct dans ONNX et sera traduit en un ou plusieurs opérateurs ONNX.
  • L'opérateur ne définit pas de règles de traduction vers ONNX et une erreur est signalée.

Alors, comment vérifier la correspondance entre les opérateurs PyTorch et les opérateurs ONNX ? Étant donné que les opérateurs PyTorch sont alignés sur ONNX, nous examinons ici d'abord la définition des opérateurs ONNX, puis examinons la relation de mappage des opérateurs définie par PyTorch.


Documentation opérateur ONNX

La définition des opérateurs ONNX peut être consultée dans la documentation officielle de l'opérateur . Ce document est très important, nous devons "consulter" ce document lorsque nous rencontrons des problèmes liés aux opérateurs ONNX.

Le tableau de changement d'opérateur au début de la partie la plus importante de ce document. La première colonne de la table est le nom de l'opérateur et la deuxième colonne est le numéro de version de l'ensemble d'opérateurs que l'opérateur a modifié, qui est le numéro de version de l'ensemble d'opérateurs que nous torch.onnx.exportavons mentionné précédemment. opset_versionEn visualisant le numéro de version du premier changement d'un opérateur, nous pouvons savoir à partir de quelle version un opérateur est pris en charge ; en visualisant le premier enregistrement de modification d'un opérateur inférieur ou égal à, nous pouvons connaître la version actuelle de l'ensemble d'opérateurs opset_version. règle de définition de l'opérateur dans .

En cliquant sur le lien dans le tableau, nous pouvons afficher les spécifications des paramètres d'entrée et de sortie et des exemples d'utilisation d'un opérateur. Par exemple, la figure ci-dessus est la règle de définition de Relu dans ONNX. Cette définition indique que Relu doit avoir une entrée et une entrée, et l'entrée et la sortie sont du même type, les deux tenseurs.

Mappage de PyTorch à l'opérateur ONNX

Dans PyTorch, toutes les définitions liées à ONNX sont placées  dans torch.onnxle répertoire , comme illustré dans la figure suivante :

Parmi eux, symbolic_opset{n}.py(fichier de table de symboles) fait référence au contenu nouvellement ajouté lorsque PyTorch prend en charge la nième version du jeu d'opérateurs ONNX. Comme nous l'avons mentionné précédemment, l'interpolation bicubique est prise en charge dans la version 11. Prenons-le comme exemple pour voir comment trouver le mappage des opérateurs.
Tout d'abord, utilisez la fonction de recherche torch/onnxpour rechercher "bicubique" dans le dossier, et vous pourrez retrouver cette interpolation dans le fichier de définition de la 11ème version :

Ensuite, nous sautons pas à pas vers la fonction de mappage ONNX du bas selon la logique d'appel du code :

upsample_bicubic2d = _interpolate("upsample_bicubic2d", 4, "cubic") 
 
-> 
 
def _interpolate(name, dim, interpolate_mode): 
    return sym_help._interpolate_helper(name, dim, interpolate_mode) 
 
-> 
 
def _interpolate_helper(name, dim, interpolate_mode): 
    def symbolic_fn(g, input, output_size, *args): 
        ... 
 
    return symbolic_fn 

Enfin, dans symbolic_fn, nous pouvons voir comment l'opérateur d'interpolation est mappé sur plusieurs opérateurs ONNX. Parmi eux, chacun g.opest une définition d'ONNX. Par exemple,  Resize l'opérateur s'écrit comme ceci :

return g.op("Resize", 
                input, 
                empty_roi, 
                empty_scales, 
                output_size, 
                coordinate_transformation_mode_s=coordinate_transformation_mode, 
                cubic_coeff_a_f=-0.75,  # only valid when mode="cubic" 
                mode_s=interpolate_mode,  # nearest, linear, or cubic 
                nearest_mode_s="floor")  # only valid when mode="nearest" 

En consultant la définition de l'opérateur Resize dans le document de l'opérateur ONNX susmentionné , nous pouvons connaître la signification de chaque paramètre. En utilisant une méthode similaire, nous pouvons interroger la signification des paramètres d'autres opérateurs ONNX, puis savoir comment les paramètres de PyTorch sont transmis étape par étape à chaque opérateur ONNX.
Après avoir maîtrisé comment interroger la relation entre PyTorch et ONNX, nous pouvons prédéfinir un numéro de version dans l'application réelle  torch.onnx.export()et opset_versionvérifier le fichier de table de symboles PyTorch correspondant en cas de problème. Si un opérateur n'existe pas, ou si la relation de mappage de l'opérateur ne répond pas à nos exigences, nous devrons peut-être le contourner avec d'autres opérateurs ou personnaliser l'opérateur.

Résumer

Dans ce tutoriel, nous avons présenté systématiquement le principe de conversion de PyTorch en ONNX. Nous nous sommes d'abord concentrés sur l'explication de la fonction torch.onnx.export la plus fréquemment utilisée, puis nous avons donné une méthode pour interroger le support de PyTorch pour les opérateurs ONNX. Grâce à cet article, nous espérons que vous pourrez convertir avec succès la plupart des modèles ONNX qui n'ont pas besoin d'ajouter de nouveaux opérateurs et que vous pourrez localiser efficacement la cause du problème lorsque vous rencontrez des problèmes d'opérateur. Plus précisément, après avoir lu cet article, vous devez comprendre les connaissances suivantes :

  • Quelle est la différence entre la méthode de traçage et la méthode d'enregistrement lors de l'exportation d'un graphique de calcul avec des instructions de contrôle.
  • torch.onnx.export()Comment installer  input_names, output_names, dynamic_axes.
  • Utilisez-le  torch.onnx.is_in_onnx_export()pour que les modèles se comportent différemment lorsqu'ils sont convertis en ONNX.
  • Comment interroger la documentation de l'opérateur ONNX ( https://github.com/onnx/onnx/blob/main/docs/Operators.md ).
  • Comment interroger le support de PyTorch pour les nouvelles fonctionnalités d'une certaine version d'ONNX.
  • Comment juger si PyTorch prend en charge un certain opérateur ONNX et quelle est la méthode prise en charge.

Les connaissances introduites dans ce numéro sont relativement abstraites, pensez-vous qu'elles sont un peu « aqueuses » ? Peu importe, dans le prochain didacticiel, nous présenterons une variété de méthodes pour ajouter la prise en charge de l'opérateur pour PyTorch à ONNX sous la forme d'exemples de code, et supprimerons plus d'obstacles pour tout le monde sur la route de PyTorch vers ONNX. Restez à l'écoute!

pratique la pratique

  1. L'opérateur Asinh apparaît dans le 9ème ensemble d'opérateurs ONNX. Comment PyTorch prend-il en charge cet opérateur dans le fichier de table de symboles de la version 9 ?
  2. L'opérateur BitShift est apparu dans le 11e ensemble d'opérateurs ONNX. Comment PyTorch prend-il en charge cet opérateur dans le fichier de table de symboles de la version 11 ?
  3. Dans le premier tutoriel , nous avons dit que PyTorch (à partir du jeu d'opérateurs #11) ne prend pas en charge la définition de facteurs de mise à l'échelle dynamiques dans l'interpolation. À quel paramètre de la relation de mappage de l'opérateur de redimensionnement correspond ce coefficient torch.onnx.symbolic_helper._interpolate_helper ? symbolic_fnComment avons-nous modifié ce paramètre ?

Les réponses aux exercices seront révélées dans le prochain tutoriel~ Essayons ensemble~

Bienvenue à tous pour découvrir MMDeploy ~

https://github.com/open-mmlab/mmdeploy​github.com/open-mmlab/mmdeploy

Si notre partage vous apporte de l'aide, bienvenue pour aimer, collecter et faire attention, aimer ~

Portail des séries

OpenMMLab : Interprétation de TorchScript (1) : Apprendre à connaître TorchScript pour la première fois

OpenMMLab : Interprétation de TorchScript (2) : analyse de l'implémentation du traceur Torch jit

OpenMMLab : Interprétation de TorchScript (3) : réécriture de sous-graphes dans jit24 D'accord · 0 commentaires Article43 D'accord · 0 commentaires L'article est en cours de téléchargement...ReuploadAnnuler

OpenMMLab : Interprétation de TorchScript (4) : Analyse d'alias dans Torch jit

OpenMMLab : Introduction au déploiement de modèles (1) : Introduction au déploiement de modèles 172 D'accord 22 Commentaires 498 D'accord 50

OpenMMLab : Tutoriel d'introduction au déploiement de modèles (2) : Résoudre les problèmes de déploiement de modèles

OpenMMLab : Tutoriel d'introduction pour le déploiement de modèles (3) : PyTorch vers ONNX Explication détaillée

OpenMMLab : Tutoriel de déploiement de modèle (4) : Prend en charge plus d'opérateurs ONNX dans PyTorch 68 d'accord· 19 commentaires 190 d'accord· 53

OpenMMLab : Tutoriel d'introduction au déploiement de modèles (5) : Modification et débogage du modèle ONNX 86 d'accord· 4 commentaires 217 d'accord· 25 commentaires en cours de téléchargement...

Je suppose que tu aimes

Origine blog.csdn.net/qq_43456016/article/details/130254810
conseillé
Classement