Rust Bindings pour l'API C ++ de Pytorch. L'objectif de la caisse tch est de fournir des emballages minces autour de l'API Pytorch C ++ (aka libtorch). Il vise à rester le plus près possible de l'API C ++ d'origine. Plus de liaisons de rouille idiomatiques pourraient alors être développées en plus de cela. La documentation peut être trouvée sur docs.rs.
changelog
La partie de génération de code pour l'API C en plus de LiBtorch provient de OCAML-TORCH.
Cette caisse nécessite que la bibliothèque C ++ Pytorch (LIBTORCH) dans la version V2.5.1 soit disponible sur votre système. Vous pouvez soit:
LIBTORCH .LIBTORCH_USE_PYTORCH=1 .LIBTORCH n'est pas défini, le script de construction peut télécharger une version binaire prédéfinie de LiBtorch en utilisant la fonctionnalité download-libtorch . Par défaut, une version CPU est utilisée. La variable d'environnement TORCH_CUDA_VERSION peut être définie sur cu117 afin d'obtenir un binaire pré-construit à l'aide de CUDA 11.7. Sur les plates-formes Linux, le script de construction recherchera une bibliothèque libtorch à l'échelle du système dans /usr/lib/libtorch.so .
Si la variable d'environnement LIBTORCH_USE_PYTORCH est définie, l'interpréteur Python actif est appelé pour récupérer des informations sur le package Python Torch. Cette version est ensuite liée.
libtorch à partir de la section de téléchargement du site Web de Pytorch et extraire le contenu du fichier zip..bashrc ou équivalent, où /path/to/libtorch est le chemin d'accès au répertoire créé lors de la déziement du fichier. export LIBTORCH=/path/to/libtorchL'emplacement des fichiers d'en-tête peut également être spécifié séparément de la bibliothèque partagée via ce qui suit:
# LIBTORCH_INCLUDE must contain `include` directory.
export LIBTORCH_INCLUDE=/path/to/libtorch/
# LIBTORCH_LIB must contain `lib` directory.
export LIBTORCH_LIB=/path/to/libtorch/ Pour les utilisateurs de Windows, en supposant que X:pathtolibtorch est le répertoire libtorch non terminé.
LIBTORCH et définissez-la sur X:pathtolibtorch .X:pathtolibtorchlib vers la variable Path .Si vous préférez définir temporairement les variables d'environnement, dans PowerShell, vous pouvez courir
$ Env: LIBTORCH = " X:pathtolibtorch "
$ Env: Path += " ;X:pathtolibtorchlib "cargo run --example basics .Selon les documents Pytorch, les versions de débogage Windows et la libération ne sont pas compatibles ABI. Cela pourrait conduire à certains segfaults si la version incorrecte de libtorch est utilisée.
Il est recommandé d'utiliser la chaîne d'outils MSVC Rust (par exemple en installant stable-x86_64-pc-windows-msvc via rustup) plutôt que basée sur Mingw car pytorch a des problèmes de compatibilités avec Mingw.
Lors de la définition de la variable d'environnement LIBTORCH_STATIC=1 , libtorch est lié statiquement plutôt que d'utiliser les bibliothèques dynamiques. Les artefacts pré-compilés ne semblent pas inclure libtorch.a par défaut, donc cela devrait être compilé manuellement, par exemple via ce qui suit:
git clone -b v2.5.1 --recurse-submodule https://github.com/pytorch/pytorch.git pytorch-static --depth 1
cd pytorch-static
USE_CUDA=OFF BUILD_SHARED_LIBS=OFF python setup.py build
# export LIBTORCH to point at the build directory in pytorch-static. Cette caisse fournit un type de tenseur qui enveloppe les tenseurs de pytorch. Voici un exemple minimal de la façon d'effectuer certaines opérations de tenseur.
use tch :: Tensor ;
fn main ( ) {
let t = Tensor :: from_slice ( & [ 3 , 1 , 4 , 1 , 5 ] ) ;
let t = t * 2 ;
t . print ( ) ;
} Pytorch fournit une différenciation automatique pour la plupart des opérations de tension qu'elle prend en charge. Ceci est couramment utilisé pour former des modèles à l'aide de la descente de gradient. L'optimisation est effectuée sur des variables qui sont créées via un nn::VarStore en définissant leurs formes et leurs initialisations.
Dans l'exemple ci-dessous my_module utilise deux variables x1 et x2 quelles valeurs initiales sont 0. La passe avant appliquée au tenseur xs renvoie xs * x1 + exp(xs) * x2 .
Une fois le modèle généré, un nn::Sgd Optimizer est créé. Ensuite, à chaque étape de la boucle de formation:
VarStore sont modifiées en conséquence. use tch :: nn :: { Module , OptimizerConfig } ;
use tch :: { kind , nn , Device , Tensor } ;
fn my_module ( p : nn :: Path , dim : i64 ) -> impl nn :: Module {
let x1 = p . zeros ( "x1" , & [ dim ] ) ;
let x2 = p . zeros ( "x2" , & [ dim ] ) ;
nn :: func ( move |xs| xs * & x1 + xs . exp ( ) * & x2 )
}
fn gradient_descent ( ) {
let vs = nn :: VarStore :: new ( Device :: Cpu ) ;
let my_module = my_module ( vs . root ( ) , 7 ) ;
let mut opt = nn :: Sgd :: default ( ) . build ( & vs , 1e-2 ) . unwrap ( ) ;
for _idx in 1 .. 50 {
// Dummy mini-batches made of zeros.
let xs = Tensor :: zeros ( & [ 7 ] , kind :: FLOAT_CPU ) ;
let ys = Tensor :: zeros ( & [ 7 ] , kind :: FLOAT_CPU ) ;
let loss = ( my_module . forward ( & xs ) - ys ) . pow_tensor_scalar ( 2 ) . sum ( kind :: Kind :: Float ) ;
opt . backward_step ( & loss ) ;
}
} L'API nn peut être utilisée pour créer des architectures de réseau neuronal, par exemple le code suivant définit un modèle simple avec une couche cachée et la forme sur l'ensemble de données MNIST à l'aide de l'optimiseur ADAM.
use anyhow :: Result ;
use tch :: { nn , nn :: Module , nn :: OptimizerConfig , Device } ;
const IMAGE_DIM : i64 = 784 ;
const HIDDEN_NODES : i64 = 128 ;
const LABELS : i64 = 10 ;
fn net ( vs : & nn :: Path ) -> impl Module {
nn :: seq ( )
. add ( nn :: linear (
vs / "layer1" ,
IMAGE_DIM ,
HIDDEN_NODES ,
Default :: default ( ) ,
) )
. add_fn ( |xs| xs . relu ( ) )
. add ( nn :: linear ( vs , HIDDEN_NODES , LABELS , Default :: default ( ) ) )
}
pub fn run ( ) -> Result < ( ) > {
let m = tch :: vision :: mnist :: load_dir ( "data" ) ? ;
let vs = nn :: VarStore :: new ( Device :: Cpu ) ;
let net = net ( & vs . root ( ) ) ;
let mut opt = nn :: Adam :: default ( ) . build ( & vs , 1e-3 ) ? ;
for epoch in 1 .. 200 {
let loss = net
. forward ( & m . train_images )
. cross_entropy_for_logits ( & m . train_labels ) ;
opt . backward_step ( & loss ) ;
let test_accuracy = net
. forward ( & m . test_images )
. accuracy_for_logits ( & m . test_labels ) ;
println ! (
"epoch: {:4} train loss: {:8.5} test acc: {:5.2}%" ,
epoch ,
f64 :: from ( & loss ) ,
100. * f64 :: from ( & test_accuracy ) ,
) ;
}
Ok ( ( ) )
}Plus de détails sur la boucle de formation peuvent être trouvés dans le tutoriel détaillé.
L'exemple de modèles de pré-entraînement illustre comment utiliser un modèle de vision informatique pré-formé sur une image. Les poids - qui ont été extraits de l'implémentation Pytorch - peuvent être téléchargés ici resnet18.ot et ici resnet34.ot.
L'exemple peut ensuite être exécuté via la commande suivante:
cargo run --example pretrained-models -- resnet18.ot tiger.jpgCela devrait imprimer les 5 meilleures catégories d'imaget pour l'image. Le code de cet exemple est assez simple.
// First the image is loaded and resized to 224x224.
let image = imagenet :: load_image_and_resize ( image_file ) ? ;
// A variable store is created to hold the model parameters.
let vs = tch :: nn :: VarStore :: new ( tch :: Device :: Cpu ) ;
// Then the model is built on this variable store, and the weights are loaded.
let resnet18 = tch :: vision :: resnet :: resnet18 ( vs . root ( ) , imagenet :: CLASS_COUNT ) ;
vs . load ( weight_file ) ? ;
// Apply the forward pass of the model to get the logits and convert them
// to probabilities via a softmax.
let output = resnet18
. forward_t ( & image . unsqueeze ( 0 ) , /*train=*/ false )
. softmax ( - 1 ) ;
// Finally print the top 5 categories and their associated probabilities.
for ( probability , class ) in imagenet :: top ( & output , 5 ) . iter ( ) {
println ! ( "{:50} {:5.2}%" , class , 100.0 * probability )
} safetensors est un nouveau format simple en étreignant pour le stockage des tenseurs. Il ne s'appuie pas sur le module pickle de Python, et donc les tenseurs ne sont pas liés aux classes spécifiques et à la structure du répertoire exact utilisée lorsque le modèle est enregistré. Il est également zéro-copy, ce qui signifie que la lecture du fichier ne nécessitera pas plus de mémoire que le fichier d'origine.
Pour plus d'informations sur safetensors , veuillez consulter https://github.com/huggingface/safetenseurs
safetensors Vous pouvez installer safetensors via le gestionnaire PIP:
pip install safetensors
import torchvision
from safetensors import torch as stt
model = torchvision . models . resnet18 ( pretrained = True )
stt . save_file ( model . state_dict (), 'resnet18.safetensors' ) Remarque: Le nom de fichier de l'exportation doit être nommé avec tch suffixe .safetensors
tch use anyhow :: Result ;
use tch :: {
Device ,
Kind ,
nn :: VarStore ,
vision :: {
imagenet ,
resnet :: resnet18 ,
}
} ;
fn main ( ) -> Result < ( ) > {
// Create the model and load the pre-trained weights
let mut vs = VarStore :: new ( Device :: cuda_if_available ( ) ) ;
let model = resnet18 ( & vs . root ( ) , 1000 ) ;
vs . load ( "resnet18.safetensors" ) ? ;
// Load the image file and resize it to the usual imagenet dimension of 224x224.
let image = imagenet :: load_image_and_resize224 ( "dog.jpg" ) ?
. to_device ( vs . device ( ) ) ;
// Apply the forward pass of the model to get the logits
let output = image
. unsqueeze ( 0 )
. apply_t ( & model , false )
. softmax ( - 1 , Kind :: Float ) ;
// Print the top 5 categories for this image.
for ( probability , class ) in imagenet :: top ( & output , 5 ) . iter ( ) {
println ! ( "{:50} {:5.2}%" , class , 100.0 * probability )
}
Ok ( ( ) )
}D'autres exemples incluent:
Matériel externe:
tch-rs et opencv pour exécuter l'inférence sur un flux de webcam pour un modèle formé Python basé sur MobileNet V3. Voir quelques détails dans ce fil.
Vérifiez ce problème.
Voir ce problème, cela pourrait être causé par Rust-Analyzer sans savoir les variables d'environnement appropriées comme LIBTORCH et LD_LIBRARY_PATH .
Il est possible d'appeler Rust / Tch Code de Python via PYO3, TCH-EXT fournit un exemple d'une telle extension Python.
Si vous obtenez une erreur de ne pas trouver de bibliothèques partagées lors de l'exécution des binaires générés (par exemple error while loading shared libraries: libtorch_cpu.so: cannot open shared object file: No such file or directory ). Vous pouvez essayer d'ajouter ce qui suit à votre .bashrc où /path/to/libtorch est le chemin d'accès à votre installation libtorch.
# For Linux
export LD_LIBRARY_PATH=/path/to/libtorch/lib:$LD_LIBRARY_PATH
# For macOS
export DYLD_LIBRARY_PATH=/path/to/libtorch/lib:$DYLD_LIBRARY_PATH
tch-rs est distribué en vertu des termes de la licence MIT et de la licence Apache (version 2.0), à votre option.
Voir Licence-APache, Licence-MIT pour plus de détails.