Chapes de ferrugem para a API C ++ de Pytorch. O objetivo da caixa tch é fornecer algumas embalagens finas ao redor da API C ++ Pytorch (também conhecida como Libtorch). O objetivo é permanecer o mais próximo possível da API C ++ original. Mais ligações de ferrugem idiomáticas podem ser desenvolvidas sobre isso. A documentação pode ser encontrada no doc.rs.
Changelog
A peça de geração de código para a API C no topo de Libtorch vem de OCAML-TORCH.
Esta caixa requer a biblioteca C ++ Pytorch (Libtorch) na versão v2.5.1 para estar disponível no seu sistema. Você pode:
LIBTORCH .LIBTORCH_USE_PYTORCH=1 .LIBTORCH não está definido, o script de construção pode baixar uma versão binária pré-criada do libtorch usando o recurso download-libtorch . Por padrão, uma versão da CPU é usada. A variável TORCH_CUDA_VERSION Ambient pode ser definida como cu117 para obter um binário pré-construído usando o CUDA 11.7. Nas plataformas Linux, o script de construção procurará uma biblioteca Libtorch em todo o sistema em /usr/lib/libtorch.so .
Se a variável de ambiente LIBTORCH_USE_PYTORCH estiver definida, o intérprete ativo do Python será chamado para recuperar informações sobre o pacote Python da tocha. Esta versão está então vinculada contra.
libtorch na seção de download do site da Pytorch e extraia o conteúdo do arquivo zip..bashrc ou equivalente, onde /path/to/libtorch é o caminho para o diretório que foi criado ao descompor o arquivo. export LIBTORCH=/path/to/libtorchO local dos arquivos do cabeçalho também pode ser especificado separadamente da biblioteca compartilhada através do seguinte:
# LIBTORCH_INCLUDE must contain `include` directory.
export LIBTORCH_INCLUDE=/path/to/libtorch/
# LIBTORCH_LIB must contain `lib` directory.
export LIBTORCH_LIB=/path/to/libtorch/ Para os usuários do Windows, assumindo que X:pathtolibtorch seja o diretório Libtorch descompactado.
LIBTORCH e defina -a como X:pathtolibtorch .X:pathtolibtorchlib na variável Path .Se você preferir definir temporariamente variáveis de ambiente, no PowerShell, você pode executar
$ Env: LIBTORCH = " X:pathtolibtorch "
$ Env: Path += " ;X:pathtolibtorchlib "cargo run --example basics .De acordo com o Pytorch, documenta as compilações de depuração e lançamento do Windows não são compatíveis com ABI. Isso pode levar a alguns Segfaults se a versão incorreta do Libtorch for usada.
Recomenda-se usar a cadeia de ferramentas Rust MSVC (por exemplo, instalando stable-x86_64-pc-windows-msvc via Rustup) em vez de um Mingw baseado em um, pois o Pytorch tem problemas de compatibilidade com o MINGW.
Ao definir a variável de ambiente LIBTORCH_STATIC=1 , libtorch está estaticamente vinculado, em vez de usar as bibliotecas dinâmicas. Os artefatos pré-compilados não parecem incluir libtorch.a por padrão, para que isso deva ser compilado manualmente, por exemplo, através do seguinte:
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. Esta caixa fornece um tipo de tensor que envolve tensores pytorch. Aqui está um exemplo mínimo de como executar algumas operações tensoras.
use tch :: Tensor ;
fn main ( ) {
let t = Tensor :: from_slice ( & [ 3 , 1 , 4 , 1 , 5 ] ) ;
let t = t * 2 ;
t . print ( ) ;
} O Pytorch fornece diferenciação automática para a maioria das operações tensoras que suporta. Isso é comumente usado para treinar modelos usando ascendência de gradiente. A otimização é realizada em variáveis criadas por meio de um nn::VarStore definindo suas formas e inicializações.
No exemplo abaixo, my_module usa duas variáveis x1 e x2 , quais valores iniciais são 0. O passe direto aplicado ao tensor xs retorna xs * x1 + exp(xs) * x2 .
Uma vez gerado o modelo, um otimizador nn::Sgd é criado. Então, em cada etapa do loop de treinamento:
VarStore são modificadas de acordo. 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 ) ;
}
} A API nn pode ser usada para criar arquiteturas de rede neural, por exemplo, o código a seguir define um modelo simples com uma camada oculta e o treina no conjunto de dados MNIST usando o Adam Optimizer.
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 ( ( ) )
}Mais detalhes sobre o ciclo de treinamento podem ser encontrados no tutorial detalhado.
O exemplo de modelos pré-treinados ilustra como usar algum modelo de visão computacional pré-treinamento em uma imagem. Os pesos - que foram extraídos da implementação de Pytorch - podem ser baixados aqui resnet18.ot e aqui resnet34.ot.
O exemplo pode ser executado através do seguinte comando:
cargo run --example pretrained-models -- resnet18.ot tiger.jpgIsso deve imprimir as 5 principais categorias ImageNet para a imagem. O código para este exemplo é bem simples.
// 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 é um novo formato simples, Huggingface para armazenar tensores. Ele não depende do módulo pickle do Python e, portanto, os tensores não estão ligados às classes específicas e à estrutura exata do diretório usada quando o modelo é salvo. Também é copia zero, o que significa que a leitura do arquivo não exigirá mais memória que o arquivo original.
Para mais informações sobre safetensors , consulte https://github.com/huggingface/safetetensors
safetensors Você pode instalar safetensors através do gerenciador 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' ) NOTA: O nome do arquivo da exportação deve ser nomeado com um sufixo .safetensors para que seja adequadamente decodificado por tch .
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 ( ( ) )
}Outros exemplos incluem:
Material externo:
tch-rs e opencv para executar a inferência em um feed da webcam para algum modelo treinado em Python baseado no MobileNet V3. Veja alguns detalhes neste tópico.
Verifique este problema.
Veja esse problema, isso pode ser causado pelo analisador de ferrugem por não conhecer as variáveis de ambiente adequadas como LIBTORCH e LD_LIBRARY_PATH .
É possível chamar o código RURN/TCH do Python via Pyo3, o TCH-EXT fornece um exemplo dessa extensão Python.
Se você receber um erro sobre não encontrar algumas bibliotecas compartilhadas ao executar os binários gerados (por exemplo error while loading shared libraries: libtorch_cpu.so: cannot open shared object file: No such file or directory ). Você pode tentar adicionar o seguinte ao seu .bashrc where /path/to/libtorch é o caminho para a instalação do 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 é distribuído nos termos da licença do MIT e da licença Apache (versão 2.0), por sua opção.
Consulte Licença-Apache, Licença-MIT para obter mais detalhes.