Je souhaite tracer un modèle pytorch (en particulier un système de traitement de la voix) (modèle gelé, modèle tflite dans TensorFlow).
pytorch lui-même fait des inférences de types, mais il a ses limites. En particulier dans le système de traitement de la voix, il existe différents codes autres que la partie neuronale.De plus, comme il existe des tableaux dynamiques et des récidives, il est nécessaire de taper de manière appropriée.
Supposons que pytorch v1.4.0 (dernière stable au 04/04/2020).
https://pytorch.org/docs/stable/jit.html
Le modèle tracé est-il idéal et le second TorchScript?
Il semble que vous puissiez combiner les deux.
typing
typé en Python et la syntaxe d'annotation de type peuvent être utilisés)Vous pouvez parcourir les types de votre script Python actuel pour le découvrir.
Dois-je utiliser un débogueur Python ou ipython ... Sera-t-il affiché dans le laboratoire Jupyter?
Je ne connais que l'exécution de base de la ligne de commande vim +, donc je vérifie en insérant print (type (x)) etc. où je veux chaque type ...
https://pytorch.org/docs/stable/jit.html
Pour python2 etc. et 3.5, vous pouvez utiliser torch.jit.annotate
ou écrire le type dans le commentaire, mais il est recommandé d'utiliser le module typing
et de taper l'annotation dans la syntaxe python.
def forward(self, x: List[torch.Tensor]) -> Tuple[torch.Tensor]:
my_list: List[Tuple[int, float]] = []
Vous pouvez le sentir.
Optional
Comme std :: optionnel en C ++, None ou avoir un type peut être ʻOptional [T] `.
Optional[int]
@torch.jit.export
Normalement, seules la méthode forward ()
et la fonction appelée depuis forward sont compilées JIT, mais vous pouvez explicitement exporter (compiler JIT) la méthode en utilisant le décorateur @ torch.jit.export
.
(Forward
est implicitement décoré avec @ torch.jit.export
)
nn.ModuleList
nn.ModuleList (tableau)
...
self.mods = nn.Modulelist([...])
for i in range(10):
self.mods[i](x)
Il n'est actuellement pas possible d'accéder par index de tableau comme.
[jit] Can't index nn.ModuleList in script function #16123 https://github.com/pytorch/pytorch/issues/16123
Pour le moment, il semble que cela puisse être géré par itération sous la forme de __constants__
et for mod in modules
, mais si vous utilisez plusieurs nn.ModuleList, vous devrez redéfinir une classe dédiée. Masu.
Cependant, dans ce cas, la définition des opérations réseau change (le nom de state_dict change), et le poids du modèle pré-entraîné doit être bien traité.
De plus, dans la v1.5.0 (v1.6.0?), Les index Array avec des constantes telles que self.mods [0]
ont commencé à être supportés.
[JIT] Add modulelist indexing for integer literal #29236 https://github.com/pytorch/pytorch/pull/29236
Une erreur s'est produite lors de l'évaluation de TorchScript (côté libtorch).
(Il a une expression comme getattr (xxx, 10)
, qui ne peut pas être analysée à l'exécution)
Il faut attendre encore un peu la maturité.
De plus, il ne prend pas en charge l'itération inverse avec reverse
lors de l'itération de nn.ModuleList.
print, assert
Dans TorchScript, print
, ʻassert` fonctionnent également dans TorchScript (peut-être pas dans trace).
Il peut être utilisé pour envoyer un message de débogage.
Quand il est exécuté par script, certains traitements sont omis, ou Aucun est supposé, mais quand il est non None, le type est arbitraire, donc il ne peut pas être tapé avec ʻOptional [T] `, donc le traitement est divisé. J'ai un étui que je veux.
torch.jit.is_scripting ()
détermine si le script est exécuté (exécuté par libtorch) à l'exécution, il ne peut donc pas être utilisé pour déterminer s'il est tracé (compilé).
Ce serait bien s'il y avait des décorateurs, mais il ne semble pas y avoir de situation actuelle.
Par conséquent, il semble qu'il n'est pas possible de basculer entre python et TorchScript fonction par fonction. Comme vous pouvez le voir dans la documentation torchscript,
@torch.jit.ignore
def forward_pytorch():
...
def forward_for_torchscript():
...
def forward():
if torch.jit.is_scripting():
forward_for_torchscript()
else
foward_pytorch()
Cependant, puisque l'expression (instruction) elle-même est la cible du traçage, s'il y a du code utilisant numpy () etc., il ne pourra pas compiler et une erreur se produira.
Vous devez le faire fonctionner comme ci-dessus et migrer le code qui fonctionne avec pytorch (+ numpy) vers @ torch.jit.ignore
(car @ torch.jit.unused
est soumis à la compilation).
GeneratorExp utilisé en interne ne prend pas en charge TorchScript. C'est pour ajuster la disposition de la mémoire pour le GPU, afin que vous puissiez l'ignorer en toute sécurité (supprimer le code).
@torch.jit.unused
decorator@torch.jit.ignore
decoratorPour inutilisé et ignorer, forward
est défini, mais c'est à des fins d'apprentissage et peut être utilisé lorsque vous voulez l'ignorer dans TorchScript.
La différence entre non utilisé et ignorer est que non utilisé déclenche une exception lorsque vous appelez une méthode, mais ignore ne fait rien lorsque vous appelez une méthode.
F.pad(x, [0, 0, maxlen - m.size(2), 0])
^^^^^^^^^^^^^^^^^^^^^
Il n'a pas été déduit de type comme List [int]
(M est torch.Tensor). Il a été résolu en créant explicitement une variable de type int.
.numpy()
Il semble que .numpy ()
ne puisse pas être utilisé. Par exemple x.cpu (). Data.numpy ()
. Du côté C ++, aten le gère bien, vous n'avez donc pas à utiliser .numpy ()
. peut être...?
En outre, il est souhaitable de ne pas utiliser la fonction numpy dans le code à tracer.
T.B.W.
Il semble bon de spécifier explicitement le type renvoyé par forward
du modèle qui sera l'entrée.
Cela permet de mieux comprendre de quel type il s'agit lors de l'exécution côté C ++.
(Si les types ne correspondent pas, une assertion sera émise lors de l'exécution)
Lors du retour d'un seul Tensor, il peut être traité comme torch :: Tensor
.
Si vous souhaitez renvoyer plusieurs tenseurs, ce sera Tuple,
model.forward(inputs).toTuple()
ça ira.
TODO
def myfun(x, activation = None):
if activation:
x = activation(x)
return x
myfun(activation=torch.relu)
Que dois-je faire lorsque je souhaite gérer quelque chose comme une fonction arbitraire ou Aucune?
class Mod:
def forward(self, x, alpha=1.0):
...
class Model:
def __init__(self):
self.mod = Mod()
def forward(self, x):
self.mod.forward(x)
...
Il y a un argument facultatif dans l'avant de la classe appelée en interne, comme dans. Dois-je le supprimer si je ne l'utilise pas réellement?