11.6 C
New York

Weblog Posit AI : sortir des sentiers battus



Pour le meilleur ou pour le pire, nous vivons dans un monde en constante évolution. Mettre l’accent sur la mieux, un exemple frappant est l’abondance, ainsi que l’évolution rapide des logiciels qui nous aident à atteindre nos objectifs. Avec cette bénédiction vient un défi, cependant. Nous devons être en mesure de réellement utiliser ces nouvelles fonctionnalités, installez cette nouvelle bibliothèque, intégrez cette nouvelle method dans notre package deal.

Avec torch, il y a tellement de choses que nous pouvons accomplir telles quelles, dont seule une infime partie a été évoquée sur ce weblog. Mais s’il y a une selected dont il faut être sûr, c’est qu’il n’y aura jamais, jamais de manque de demande pour plus de choses à faire. Voici trois scénarios qui me viennent à l’esprit.

  • charger un modèle pré-formé qui a été défini en Python (sans avoir à porter manuellement tout le code)

  • modifier un module de réseau neuronal, de manière à incorporer un nouveau raffinement algorithmique (sans encourir le coût de efficiency lié à l’exécution du code personnalisé dans R)

  • utiliser l’une des nombreuses bibliothèques d’extensions disponibles dans l’écosystème PyTorch (avec le moins d’effort de codage doable)

Cet article illustrera chacun de ces cas d’utilisation dans l’ordre. D’un level de vue pratique, cela constitue un passage progressif d’une perspective d’utilisateur à une perspective de développeur. Mais dans les coulisses, ce sont vraiment les mêmes blocs de development qui les alimentent tous.

Facilitateurs : torchexport et Torchscript

Le forfait R torchexport et (côté PyTorch) TorchScript fonctionnent à des échelles très différentes et jouent des rôles très différents. Néanmoins, les deux sont importants dans ce contexte, et je dirais même que l’acteur « à petite échelle » (torchexport) est le composant vraiment essentiel, du level de vue d’un utilisateur de R. C’est en partie parce qu’il determine dans les trois scénarios, alors que TorchScript n’est impliqué que dans le premier.

torchexport : gère la « pile de varieties » et s’occupe des erreurs

En R torch, la profondeur de la « pile de varieties » est vertigineuse. Le code destiné à l’utilisateur est écrit en R ; la fonctionnalité de bas niveau est intégrée dans libtorchune bibliothèque partagée C++ utilisée par torch ainsi que PyTorch. Le médiateur, comme c’est souvent le cas, est la Rcpp. Cependant, ce n’est pas là que l’histoire se termine. En raison d’incompatibilités de compilateur spécifiques au système d’exploitation, il doit y avoir une couche intermédiaire supplémentaire à motion bidirectionnelle qui supprime tous les varieties C++ d’un côté du pont (Rcpp ou libtorch, resp.), ne laissant que des pointeurs de mémoire bruts, et les rajoute de l’autre. En fin de compte, ce qui en résulte est une pile d’appels assez complexe. Comme vous pouvez l’imaginer, il existe un besoin d’accompagnement pour une gestion des erreurs soigneusement placée et adaptée au niveau, en s’assurant que l’utilisateur reçoit des informations utilisables à la fin.

Maintenant, que vaut pour torch s’applique à chaque extension côté R qui ajoute du code personnalisé ou appelle des bibliothèques C++ externes. C’est ici que torchexport En tant qu’auteur d’extension, tout ce que vous avez à faire est d’écrire une infime partie du code requis dans l’ensemble – le reste sera généré par torchexport. Nous y reviendrons dans les scénarios deux et trois.

TorchScript : permet la génération de code « à la volée »

Nous avons déjà rencontré TorchScript dans un message précédent, bien que sous un angle différent, et mettant en évidence un ensemble de termes différent. Dans cet article, nous avons montré remark vous pouvez former un modèle en R et hint cela, résultant en une représentation intermédiaire optimisée qui peut ensuite être enregistrée et chargée dans un environnement différent (éventuellement sans R). Là, l’accent conceptuel était mis sur l’agent permettant ce flux de travail : le compilateur juste-à-temps PyTorch (JIT) qui génère la représentation en query. Nous avons rapidement mentionné que du côté Python, il existe une autre façon d’invoquer le JIT : non pas sur un modèle « vivant » instancié, mais sur code de définition de modèle scripté. C’est cette deuxième voie, ainsi nommée scriptce qui est pertinent dans le contexte actuel.

Même si les scripts ne sont pas disponibles à partir de R (à moins que le code scripté ne soit écrit en Python), nous bénéficions toujours de son existence. Lorsque les bibliothèques d’extension côté Python utilisent TorchScript (au lieu du code C++ regular), nous n’avons pas besoin d’ajouter des liaisons aux fonctions respectives du côté R (C++). Au lieu de cela, tout est pris en cost par PyTorch.

Ceci – bien que complètement clear pour l’utilisateur – est ce qui permet le premier scénario. Dans (Python) TorchVision, les modèles pré-formés fournis utilisent souvent des opérateurs spéciaux (dépendants du modèle). Grâce à leur script, nous n’avons pas besoin d’ajouter une liaison pour chaque opérateur, et encore moins de les réimplémenter du côté R.

Après avoir décrit certaines des fonctionnalités sous-jacentes, nous présentons maintenant les scénarios eux-mêmes.

Scénario 1 : Charger un modèle TorchVision pré-formé

Peut-être avez-vous déjà utilisé l’un des modèles préformés mis à disposition par TorchVision : un sous-ensemble de ceux-ci a été porté manuellement vers torchvision, le paquet R. Mais il y en a plus – un parcelle plus. Beaucoup utilisent des opérateurs spécialisés – rarement nécessaires en dehors du contexte d’un algorithme. Il semblerait peu utile de créer des wrappers R pour ces opérateurs. Et bien sûr, l’apparition continuelle de nouveaux modèles nécessiterait de notre half des efforts de portage continuels.

Heureusement, il existe une answer élégante et efficace. Toute l’infrastructure nécessaire est mise en place par le package deal léger et dédié torchvisionlib. (Il peut se permettre d’être léger en raison de l’utilisation libérale de TorchScript du côté Python, comme expliqué dans la part précédente. Mais pour l’utilisateur – dont je prends la perspective dans ce scénario – ces détails n’ont pas besoin d’avoir de l’significance.)

Une fois que vous avez installé et chargé torchvisionlibvous avez le choix parmi un nombre impressionnant de modèles liés à la reconnaissance d’photos. Le processus est alors double :

  1. Vous instanciez le modèle en Python, scénario et enregistrez-le.

  2. Vous chargez et utilisez le modèle dans R.

Voici la première étape. Notez remark, avant le script, nous mettons le modèle dans eval mode, garantissant ainsi que toutes les couches présentent un comportement de temps d’inférence.

library(torchvisionlib)

mannequin <- torch::jit_load("fcn_resnet50.pt")

À ce stade, vous pouvez utiliser le modèle pour obtenir des prédictions, ou même l’intégrer en tant que bloc de development dans une structure plus giant.

Scénario 2 : implémenter un module personnalisé

Ne serait-il pas merveilleux si chaque nouvel algorithme bien accueilli, chaque nouvelle variante prometteuse d’un sort de couche ou, mieux encore, l’algorithme que vous avez l’intention de révéler au monde dans votre prochain article était déjà implémenté dans torch?

Eh bien, peut-être; mais peut-être pas. La answer beaucoup plus sturdy est de rendre raisonnablement facile l’extension torch dans de petits packages dédiés qui servent chacun un objectif précis et sont rapides à installer. Une procédure pas à pas détaillée et pratique du processus est fournie par le package deal lltm. Ce paquet a une touche récursive. En même temps, c’est une occasion d’un C++ torch extension, et sert de tutoriel montrant remark créer une telle extension.

Le README lui-même explique remark le code doit être structuré et pourquoi. Si vous êtes intéressé par la façon dont torch lui-même a été conçu, il s’agit d’une lecture éclairante, que vous envisagiez ou non d’écrire une extension. En plus de ce sort d’informations sur les coulisses, le README contient des directions étape par étape sur la façon de procéder dans la pratique. Conformément à l’objectif du package deal, le code supply est également richement documenté.

Comme déjà indiqué dans la part « Enablers », la raison pour laquelle j’ose écrire « rendre les choses raisonnablement faciles » (en référence à la création d’un torch extension) est torchexport, le package deal qui génère automatiquement du code C++ lié à la conversion et à la gestion des erreurs sur plusieurs couches de la « pile de varieties ». En règle générale, vous constaterez que la quantité de code généré automatiquement dépasse largement celle du code que vous avez écrit vous-même.

Scénario 3 : Interface vers les extensions PyTorch intégrées/sur le code C++

Il est tout sauf unbelievable qu’un jour, vous rencontriez une extension PyTorch que vous souhaiteriez être disponible en R. Au cas où cette extension serait écrite en Python (exclusivement), vous la traduiriez en R « à la primary », en utilisant toutes les fonctionnalités applicables torch fournit. Parfois, cependant, cette extension contiendra un mélange de code Python et C++. Ensuite, vous devrez vous lier à la fonctionnalité C++ de bas niveau d’une manière analogue à la façon dont torch lier à libtorch – et maintenant, toutes les exigences de typage décrites ci-dessus s’appliqueront à votre extension de la même manière.

Encore une fois, c’est torchexport qui vient à la rescousse. Et là aussi, le lltm Le README s’applique toujours ; c’est juste qu’au lieu d’écrire votre code personnalisé, vous ajouterez des liaisons aux fonctions C++ fournies en externe. Cela fait, vous aurez torchexport créer tout le code d’infrastructure requis.

Une sorte de modèle peut être trouvé dans le torchsparse package deal (actuellement en cours de développement). Les fonctions dans csrc/src/torchsparse.cpp tous appellent dans PyTorch clairseméeavec les déclarations de fonction trouvées dans le projet csrc/sparse.h.

Une fois que vous intégrez du code C++ externe de cette manière, une query supplémentaire peut se poser. Prenons un exemple de torchsparse. Dans le fichier d’en-tête, vous remarquerez des varieties de retour tels que std::tuple<torch::Tensor, torch::Tensor>, <torch::Tensor, torch::Tensor, <torch::optionally available<torch::Tensor>>, torch::Tensor>> … et plus. En R torch (la couche C++) nous avons torch::Tensoret nous avons torch::optionally available<torch::Tensor>, aussi. Mais nous n’avons pas de sort personnalisé pour chaque std::tuple vous pourriez construire. Tout comme ayant la base torch fournir toutes sortes de fonctionnalités spécialisées et spécifiques à un domaine n’est pas sturdy, cela n’a aucun sens d’essayer de prévoir toutes sortes de varieties qui seront un jour demandés.

En conséquence, les varieties doivent être définis dans les packages qui en ont besoin. Remark procéder exactement est expliqué dans le torchexport Sorts personnalisés vignette. Lorsqu’un tel sort personnalisé est utilisé, torchexport doit savoir remark les varieties générés, à différents niveaux, doivent être nommés. C’est pourquoi, dans de tels cas, au lieu d’un laconique //((torch::export))vous verrez des lignes comme / ((torch::export(register_types=c("tensor_pair", "TensorPair", "void*", "torchsparse::tensor_pair")))). La vignette explique cela en détail.

Et après

« Quelle est la prochaine » est une façon courante de terminer un message, en remplaçant, par exemple, « Conclusion » ou « Récapitulatif ». Mais ici, c’est à prendre au pied de la lettre. Nous espérons faire de notre mieux pour rendre l’utilisation, l’interfaçage et l’extension torch le moins d’effort doable. Par conséquent, veuillez nous faire half de toute difficulté que vous rencontrez ou de tout problème que vous rencontrez. Créez simplement un problème dans torcheexport, lltm, torcheou tout référentiel qui semble relevant.

Comme toujours, merci d’avoir lu!

photograph par Antonino Visalli sur Unsplash

Related Articles

LAISSER UN COMMENTAIRE

S'il vous plaît entrez votre commentaire!
S'il vous plaît entrez votre nom ici

Latest Articles