การผูกสนิมสำหรับ C ++ API ของ Pytorch เป้าหมายของลัง tch คือการจัดเตรียมเครื่องห่อบาง ๆ รอบ C ++ Pytorch API (aka libtorch) มันมีจุดมุ่งหมายที่จะอยู่ใกล้กับ C ++ API ดั้งเดิมมากที่สุด การผูกมัดสนิมที่มีสำนวนมากขึ้นนั้นสามารถพัฒนาได้จากด้านบนของสิ่งนี้ เอกสารสามารถพบได้ใน docs.rs
การเปลี่ยนแปลง
ส่วนการสร้างรหัสสำหรับ C API ด้านบนของ Libtorch มาจาก Ocaml-Torch
ลังนี้ต้องใช้ไลบรารี C ++ Pytorch (Libtorch) ในเวอร์ชัน v2.5.1 ที่จะพร้อมใช้งานในระบบของคุณ คุณสามารถ:
LIBTORCHLIBTORCH_USE_PYTORCH=1LIBTORCH สคริปต์บิลด์สามารถดาวน์โหลด Libtorch รุ่นไบนารีที่สร้างไว้ล่วงหน้าโดยใช้คุณสมบัติ download-libtorch โดยค่าเริ่มต้นจะใช้เวอร์ชัน CPU ตัวแปรสภาพแวดล้อม TORCH_CUDA_VERSION สามารถตั้งค่าเป็น cu117 เพื่อรับไบนารีที่สร้างไว้ล่วงหน้าโดยใช้ CUDA 11.7 บนแพลตฟอร์ม Linux สคริปต์ Build จะมองหาไลบรารี Libtorch ทั่วทั้งระบบใน /usr/lib/libtorch.so
หากตั้งค่าตัวแปรสภาพแวดล้อม LIBTORCH_USE_PYTORCH แล้วล่าม Python ที่ใช้งานจะถูกเรียกให้ดึงข้อมูลเกี่ยวกับแพ็คเกจ Torch Python เวอร์ชันนี้จะเชื่อมโยงกับ
libtorch จากส่วนดาวน์โหลดเว็บไซต์ Pytorch และแยกเนื้อหาของไฟล์ zip.bashrc หรือเทียบเท่าโดยที่ /path/to/libtorch เป็นเส้นทางไปยังไดเรกทอรีที่สร้างขึ้นเมื่อคลายซิปไฟล์ export LIBTORCH=/path/to/libtorchตำแหน่งไฟล์ส่วนหัวยังสามารถระบุแยกต่างหากจากไลบรารีที่ใช้ร่วมกันผ่านทางต่อไปนี้:
# LIBTORCH_INCLUDE must contain `include` directory.
export LIBTORCH_INCLUDE=/path/to/libtorch/
# LIBTORCH_LIB must contain `lib` directory.
export LIBTORCH_LIB=/path/to/libtorch/ สำหรับผู้ใช้ Windows สมมติว่า X:pathtolibtorch เป็นไดเรกทอรี libtorch ที่ถูกซิป
LIBTORCH และตั้งค่าเป็น X:pathtolibtorchX:pathtolibtorchlib ไปยังตัวแปร Pathหากคุณต้องการตั้งค่าตัวแปรสภาพแวดล้อมชั่วคราวใน PowerShell คุณสามารถเรียกใช้
$ Env: LIBTORCH = " X:pathtolibtorch "
$ Env: Path += " ;X:pathtolibtorchlib "cargo run --example basicsตามเอกสารของ Pytorch การดีบัก Windows และการเปิดตัวจะไม่เข้ากันได้กับ ABI สิ่งนี้อาจนำไปสู่ Segfaults บางตัวหากใช้ Libtorch เวอร์ชันที่ไม่ถูกต้อง
ขอแนะนำให้ใช้ MSVC Rust Toolchain (เช่นการติดตั้ง stable-x86_64-pc-windows-msvc ผ่าน Rustup) แทนที่จะเป็น MingW ที่ใช้เป็น Pytorch มีปัญหาความเข้ากันได้กับ MingW
เมื่อตั้งค่าสภาพแวดล้อมตัวแปร LIBTORCH_STATIC=1 libtorch มีการเชื่อมโยงแบบคงที่แทนที่จะใช้ไลบรารีแบบไดนามิก สิ่งประดิษฐ์ที่รวบรวมไว้ล่วงหน้าดูเหมือนจะไม่รวม libtorch.a โดยค่าเริ่มต้นดังนั้นสิ่งนี้จะต้องมีการรวบรวมด้วยตนเองเช่นผ่านสิ่งต่อไปนี้:
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. ลังนี้ให้ประเภทเทนเซอร์ที่ห่อเทนเซอร์ Pytorch นี่คือตัวอย่างน้อยที่สุดของวิธีการดำเนินการเทนเซอร์
use tch :: Tensor ;
fn main ( ) {
let t = Tensor :: from_slice ( & [ 3 , 1 , 4 , 1 , 5 ] ) ;
let t = t * 2 ;
t . print ( ) ;
} Pytorch ให้ความแตกต่างโดยอัตโนมัติสำหรับการดำเนินการเทนเซอร์ส่วนใหญ่ที่รองรับ สิ่งนี้ใช้กันทั่วไปในการฝึกอบรมแบบจำลองโดยใช้การไล่ระดับสี การเพิ่มประสิทธิภาพจะดำเนินการผ่านตัวแปรที่สร้างขึ้นผ่าน nn::VarStore โดยการกำหนดรูปร่างและการเริ่มต้น
ในตัวอย่างด้านล่าง my_module ใช้ตัวแปรสองตัว x1 และ x2 ซึ่งค่าเริ่มต้นคือ 0. ผ่านไปข้างหน้าใช้กับ Tensor xs ส่งคืน xs * x1 + exp(xs) * x2
เมื่อสร้างโมเดลแล้วตัวเพิ่มประสิทธิภาพ nn::Sgd จะถูกสร้างขึ้น จากนั้นในแต่ละขั้นตอนของการฝึกอบรม:
VarStore ได้รับการแก้ไขตามลำดับ 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 ) ;
}
} nn API สามารถใช้ในการสร้างสถาปัตยกรรมเครือข่ายประสาทเช่นรหัสต่อไปนี้กำหนดโมเดลที่เรียบง่ายด้วยเลเยอร์ที่ซ่อนอยู่หนึ่งชั้นและฝึกอบรมบนชุดข้อมูล MNIST โดยใช้ 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 ( ( ) )
}รายละเอียดเพิ่มเติมเกี่ยวกับการฝึกอบรมสามารถพบได้ในการสอนโดยละเอียด
ตัวอย่างรูปแบบ pretrained แสดงวิธีการใช้โมเดลการมองเห็นคอมพิวเตอร์ที่ผ่านการฝึกอบรมมาล่วงหน้าบนภาพ น้ำหนัก - ซึ่งได้รับการสกัดจากการใช้งาน pytorch - สามารถดาวน์โหลดได้ที่นี่ resnet18.OT และที่นี่ resnet34.ot
ตัวอย่างสามารถเรียกใช้ผ่านคำสั่งต่อไปนี้:
cargo run --example pretrained-models -- resnet18.ot tiger.jpgสิ่งนี้ควรพิมพ์หมวดหมู่ Imagenet 5 อันดับแรกสำหรับภาพ รหัสสำหรับตัวอย่างนี้ค่อนข้างง่าย
// 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 เป็นรูปแบบที่เรียบง่ายใหม่โดย HuggingFace สำหรับการจัดเก็บเทนเซอร์ มันไม่ได้พึ่งพาโมดูล pickle ของ Python ดังนั้นเทนเซอร์จึงไม่ผูกพันกับคลาสเฉพาะและโครงสร้างไดเรกทอรีที่แน่นอนที่ใช้เมื่อบันทึกแบบจำลอง นอกจากนี้ยังเป็นศูนย์คัดลอกซึ่งหมายความว่าการอ่านไฟล์จะไม่จำเป็นต้องมีหน่วยความจำมากกว่าไฟล์ต้นฉบับ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ safetensors โปรดตรวจสอบ https://github.com/huggingface/safetensors
safetensors คุณสามารถติดตั้ง safetensors ผ่าน PIP Manager:
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' ) หมายเหตุ: ชื่อไฟล์ของการส่งออกจะต้องตั้งชื่อด้วยคำต่อท้าย .safetensors เพื่อให้ได้รับการถอดรหัสอย่างเหมาะสมโดย 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 ( ( ) )
}ตัวอย่างเพิ่มเติม ได้แก่ :
วัสดุภายนอก:
tch-rs และ opencv เพื่อเรียกใช้การอนุมานบนฟีดเว็บแคมสำหรับรุ่นที่ผ่านการฝึกอบรมของ Python ตาม Mobilenet V3 ดูรายละเอียดบางอย่างในหัวข้อนี้
ตรวจสอบปัญหานี้
ดูปัญหานี้อาจเกิดจากการวิเคราะห์สนิมที่ไม่รู้เกี่ยวกับตัวแปรสภาพแวดล้อมที่เหมาะสมเช่น LIBTORCH และ LD_LIBRARY_PATH
เป็นไปได้ที่จะเรียกรหัส Rust/TCH จาก Python ผ่าน PYO3, TCH-EXT เป็นตัวอย่างของส่วนขยาย Python ดังกล่าว
หากคุณได้รับข้อผิดพลาดเกี่ยวกับการไม่ค้นหาไลบรารีที่ใช้ร่วมกันเมื่อเรียกใช้ไบนารีที่สร้างขึ้น (เช่น error while loading shared libraries: libtorch_cpu.so: cannot open shared object file: No such file or directory ) คุณสามารถลองเพิ่มสิ่งต่อไปนี้ใน .bashrc ของคุณโดยที่ /path/to/libtorch เป็นเส้นทางไปสู่การติดตั้ง 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 มีการแจกจ่ายภายใต้ข้อกำหนดของทั้งใบอนุญาต MIT และใบอนุญาต Apache (เวอร์ชัน 2.0) ตามตัวเลือกของคุณ
ดูใบอนุญาต-APACHE, ใบอนุญาตสำหรับรายละเอียดเพิ่มเติม