### Run Burn Example Project Source: https://burn.dev/books/burn/print.html/index Executes a demo project from Burn's base directory using Cargo. This command is used to run the example guide provided with the Burn library. ```bash cargo run --example guide ``` -------------------------------- ### Create New Cargo Project Source: https://burn.dev/books/burn/print.html/index Initializes a new Rust project using Cargo, named 'guide'. This command creates the necessary project structure, including Cargo.toml and src/main.rs files. ```bash cargo new guide ``` -------------------------------- ### Execute Burn Example using Cargo Source: https://burn.dev/books/burn/print.html/index This command allows you to run a specific example provided within the Burn project. Replace '' with the actual name of the example you wish to execute. ```bash cargo run --example ``` -------------------------------- ### Rust: Model Initialization with References Source: https://burn.dev/books/burn/print.html/index Provides an example of a Rust function `init` that takes references (`&self` and `&B::Device`) as parameters. This pattern is used in the Burn framework to avoid taking ownership of the `ModelConfig` and the backend `Device`, allowing them to be used elsewhere. ```rust __ pub fn init(&self, device: &B::Device) -> Model { Model { // ... } } ``` -------------------------------- ### Instantiate Module on a Specific Device using Configuration in Rust Source: https://burn.dev/books/burn/print.html/index Demonstrates how to use the `init` method on a configuration object to create a deep learning module instance on a specified device. This example uses the Wgpu backend, highlighting Burn's backend-agnostic approach to module initialization. ```rust use burn::backend::Wgpu; let device = Default::default(); let my_module = config.init::(&device); ``` -------------------------------- ### Backend Selection for Burn Models in Rust Source: https://burn.dev/books/burn/print.html/index Illustrates how to select a backend for Burn models in Rust. The code comments out examples for Candle, LibTorch, and NdArray backends, and explicitly defines 'Wgpu' as the chosen backend. This demonstrates the flexibility of Burn's backend abstraction. ```rust // Choose from any of the supported backends. // type Backend = Candle; // type Backend = LibTorch; // type Backend = NdArray; type Backend = Wgpu; // Creation of two tensors. ``` -------------------------------- ### Global Allocator Setup for no_std Environments Source: https://burn.dev/books/burn/print.html/index This code sets up a global allocator using `embedded_alloc` for no_std environments where a default allocator is not available. It defines a heap with a specified size and initializes it. ```rust use embedded_alloc::LlffHeap as Heap; #[global_allocator] static HEAP: Heap = Heap::empty(); #[embassy_executor::main] async fn main(_spawner: Spawner) { { use core::mem::MaybeUninit; // Watch out for this, if it is too big or small for your model, the // program may crash. This is in u8 bytes, as such this is a total of 100kb const HEAP_SIZE: usize = 100 * 1024; static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) } // Initialize the heap } } ``` -------------------------------- ### Handling Tensor Ownership with Cloning Source: https://burn.dev/books/burn/print.html/index Demonstrates Rust's ownership rules with tensors, showing how operations consume tensors and necessitate cloning for reuse. Includes an example of min-max normalization requiring cloning. ```rust let input = Tensor::::from_floats([1.0, 2.0, 3.0, 4.0], &device); let min = input.clone().min(); let max = input.clone().max(); let input = (input.clone() - min.clone()).div(max - min); println!("{}", input.to_data());// Success: [0.0, 0.33333334, 0.6666667, 1.0] // Notice that max, min have been moved in last operation so // the below print will give an error. // If we want to use them for further operations, // they will need to be cloned in similar fashion. // println!("{:?}", min.to_data()); ``` -------------------------------- ### Example Debug Output for Key Remapping Source: https://burn.dev/books/burn/print.html/index Illustrates the expected debug output when key remapping is enabled during PyTorch model import in Burn. It shows the original key, the remapped key, the tensor shape, and the data type for each parameter, aiding in verification and debugging. ```text Debug information of keys and tensor shapes: --- Original Key: conv.conv1.bias Remapped Key: conv1.bias Shape: [2] Dtype: F32 --- Original Key: conv.conv1.weight Remapped Key: conv1.weight Shape: [2, 2, 2, 2] Dtype: F32 --- Original Key: conv.conv2.weight Remapped Key: conv2.weight Shape: [2, 2, 2, 2] Dtype: F32 --- ``` -------------------------------- ### Create New Rust Project with Cargo Source: https://burn.dev/books/burn/print.html/index Initializes a new Rust project directory with a Cargo.toml manifest file and a src directory containing a main.rs file. This command is fundamental for starting any new Rust project managed by Cargo. ```rust cargo new my_burn_app ``` -------------------------------- ### Flexible Optimizer Configuration in Rust Source: https://burn.dev/books/burn/print.html/index Illustrates how to apply different learning rates, optimizer parameters, or even entirely different optimizers to specific parts of a model in Rust using Burn. This is achieved by splitting `GradientParams` into subsets corresponding to different model components, allowing for fine-grained control over the optimization process. The example shows how to extract gradients for convolutional layers, biases, and remaining parameters, applying distinct optimization steps for each. ```rust // Start with calculating all gradients let grads = loss.backward(); // Now split the gradients into various parts. let grads_conv1 = GradientParams::from_module(&mut grads, &model.conv1); let grads_conv2 = GradientParams::from_module(&mut grads, &model.conv2); // You can step the model with these gradients, using different learning // rates for each param. You could also use an entirely different optimizer here! model = optim.step(config.lr * 2.0, model, grads_conv1); model = optim.step(config.lr * 4.0, model, grads_conv2); // For even more granular control you can split off individual parameter // eg. a linear bias usually needs a smaller learning rate. if let Some(bias) == model.linear1.bias { let grads_bias = GradientParams::from_params(&mut grads, &model.linear1, &[bias.id]); model = optim.step(config.lr * 0.1, model, grads_bias); } // Note that above calls remove gradients, so we can just get all "remaining" gradients. let grads = GradientsParams::from_grads(grads, &model); model = optim.step(config.lr, model, grads); ``` -------------------------------- ### Load Hugging Face Dataset with Rust Source: https://burn.dev/books/burn/print.html/index Loads a dataset from Hugging Face using the `HuggingfaceDatasetLoader`. This method utilizes SQLite for storage to avoid repeated downloads or Python process startup. It requires dataset items to derive `serde::Serialize`, `serde::Deserialize`, `Clone`, and `Debug`. The `HuggingfaceDatasetLoader` depends on the HuggingFace `datasets` Python library, necessitating an existing Python installation. ```rust #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct DbPediaItem { pub title: String, pub content: String, pub label: usize, } fn main() { let dataset: SqliteDataset = HuggingfaceDatasetLoader::new("dbpedia_14") .dataset("train") // The training split. .unwrap(); } ``` -------------------------------- ### Burn Inference and Validation Examples Source: https://burn.dev/books/burn/print.html/index Shows how to handle inference and validation with Burn tensors. For validation, `tensor.inner()` can be used to get the inner tensor from an AutodiffBackend, allowing operations without tracking gradients. For general inference, any Backend can be used directly. ```rust use burn::tensor::backend::{AutodiffBackend, Backend}; use burn::tensor::Tensor; /// Use `B: AutodiffBackend` fn example_validation(tensor: Tensor) { let inner_tensor: Tensor = tensor.inner(); let _ = inner_tensor + 5; } /// Use `B: Backend` fn example_inference(tensor: Tensor) { let _ = tensor + 5; ... } ``` -------------------------------- ### Create Data Splits with PartialDataset Source: https://burn.dev/books/burn/print.html/index Returns a view of the dataset with specified start and end indices, commonly used for creating train/validation/test splits. Can be chained with other transformations like ShuffledDataset. ```Rust // define chained dataset type here for brevity type PartialData = PartialDataset>; let len = dataset.len(); let split = "train"; // or "val"/"test" let data_split = match split { "train" => PartialData::new(dataset, 0, len * 8 / 10), // Get first 80% dataset "test" => PartialData::new(dataset, len * 8 / 10, len), // Take remaining 20% _ => panic!("Invalid split type"), // Handle unexpected split types }; ``` -------------------------------- ### Initialize and Use Module Configuration with Builder Pattern in Rust Source: https://burn.dev/books/burn/print.html/index Illustrates how to instantiate and manipulate a configuration object defined with `#[derive(Config)]`. It showcases the generated `new` and `with_` methods for setting parameters and demonstrates saving the configuration to a JSON file, facilitating reproducibility. ```rust fn main() { let config = MyModuleConfig::new(512, 2048); println!("{}", config.d_model); // 512 println!("{}", config.d_ff); // 2048 println!("{}", config.dropout); // 0.1 let config = config.with_dropout(0.2); println!("{}", config.dropout); // 0.2 config.save("config.json").unwrap(); } ``` -------------------------------- ### Implement Burn ModuleMapper for Clamping Parameters Source: https://burn.dev/books/burn/print.html/index Demonstrates implementing the ModuleMapper trait to create a 'Clamp' struct that limits parameter values within a specified range. This example focuses on clamping float tensors. ```rust /// Clamp parameters into the range `[min, max]`. pub struct Clamp { /// Lower-bound of the range. pub min: f32, /// Upper-bound of the range. pub max: f32, } // Clamp all floating-point parameter tensors between `[min, max]`. impl ModuleMapper for Clamp { fn map_float( &mut self, _id: burn::module::ParamId, tensor: burn::prelude::Tensor, ) -> burn::prelude::Tensor { tensor.clamp(self.min, self.max) } } // Clamp module mapper into the range `[-0.5, 0.5]` let mut clamp = Clamp { min: -0.5, max: 0.5, }; let model = model.map(&mut clamp); ``` -------------------------------- ### Configure and Train Model with Wgpu Backend in Rust Source: https://burn.dev/books/burn/print.html/index This Rust code snippet demonstrates how to set up the Wgpu backend for GPU acceleration and initiate the model training process. It defines the backend types, device, artifact directory, and training configuration. The `train` function is called with these parameters. ```rust #![recursion_limit = "256"] mod data; mod model; mod training; use crate::{model::ModelConfig, training::TrainingConfig}; use burn::{ backend::{Autodiff, Wgpu}, data::dataset::Dataset, optim::AdamConfig, }; fn main() { type MyBackend = Wgpu; type MyAutodiffBackend = Autodiff; let device = burn::backend::wgpu::WgpuDevice::default(); let artifact_dir = "/tmp/guide"; crate::training::train::( artifact_dir, TrainingConfig::new(ModelConfig::new(10, 512), AdamConfig::new()), device.clone(), ); } ``` -------------------------------- ### PyTorch Inference Mode Example Source: https://burn.dev/books/burn/print.html/index Illustrates how to disable gradient calculations in PyTorch for inference or validation purposes using `torch.inference()` or `torch.no_grad()` context managers. This is a common pattern to optimize performance when gradients are not needed. ```python # Inference mode torch.inference(): # your code ... # Or no grad torch.no_grad(): # your code ... ``` -------------------------------- ### Rust: Instantiate and Print a Burn Model Source: https://burn.dev/books/burn/print.html/index Shows how to instantiate a neural network model defined with Burn and print its configuration. It uses the `Wgpu` backend for f32/i32 and initializes the `ModelConfig` with specified dimensions before printing the resulting model structure. ```rust __ #![recursion_limit = "256"] mod model; use crate::model::ModelConfig; use burn::backend::Wgpu; fn main() { type MyBackend = Wgpu; let device = Default::default(); let model = ModelConfig::new(10, 512).init::(&device); println!("{model}"); } ``` -------------------------------- ### Initialize Deep Learning Module from Configuration in Rust Source: https://burn.dev/books/burn/print.html/index Shows how to implement an initialization method for a configuration struct that creates a deep learning module. This pattern allows for creating module instances with specific configurations, abstracting away the details of underlying layers and their settings. ```rust impl MyModuleConfig { /// Create a module on the given device. pub fn init(&self, device: &B::Device) -> MyModule { MyModule { linear: LinearConfig::new(self.d_model, self.d_ff).init(device), dropout: DropoutConfig::new(self.dropout).init(), } } } ``` -------------------------------- ### Load CSV Dataset In-Memory with Rust Source: https://burn.dev/books/burn/print.html/index Loads records from a CSV file directly into memory using `InMemDataset`. The CSV reader can be configured, for example, to use a tab delimiter. This method requires the `csv` crate. ```rust // Build dataset from csv with tab ('\t') delimiter. // The reader can be configured for your particular file. let mut rdr = csv::ReaderBuilder::new(); let rdr = rdr.delimiter(b'\t'); let dataset = InMemDataset::from_csv("path/to/csv", rdr).unwrap(); ``` -------------------------------- ### Initializing Tensors from Various Data Sources Source: https://burn.dev/books/burn/print.html/index Illustrates initializing tensors using `from_data` with different inputs like arrays, slices, and custom structs. It also shows `from_floats` as a recommended alternative for f32. ```rust // Initialization from a given Backend (Wgpu) let tensor_1 = Tensor::::from_data([1.0, 2.0, 3.0], &device); // Initialization from a generic Backend let tensor_2 = Tensor::::from_data(TensorData::from([1.0, 2.0, 3.0]), &device); // Initialization using from_floats (Recommended for f32 ElementType) // Will be converted to TensorData internally. let tensor_3 = Tensor::::from_floats([1.0, 2.0, 3.0], &device); // Initialization of Int Tensor from array slices let arr: [i32; 6] = [1, 2, 3, 4, 5, 6]; let tensor_4 = Tensor::::from_data(TensorData::from(&arr[0..3]), &device); // Initialization from a custom type struct BodyMetrics { age: i8, height: i16, weight: f32 } let bmi = BodyMetrics{ age: 25, height: 180, weight: 80.0 }; let data = TensorData::from([bmi.age as f32, bmi.height as f32, bmi.weight]); let tensor_5 = Tensor::::from_data(data, &device); ``` -------------------------------- ### Define Burn Model Architecture Source: https://burn.dev/books/burn/print.html/index This Rust code defines a Burn model structure `Net` that mirrors the PyTorch model architecture. It includes two `Conv2d` layers, matching the configuration used in the PyTorch export example, preparing it for weight import. ```rust #![allow(unused)] fn main() { use burn:: nn::conv::{Conv2d, Conv2dConfig}, prelude::*; #[derive(Module, Debug)] pub struct Net { conv1: Conv2d, conv2: Conv2d, } impl Net { /// Create a new model. pub fn init(device: &B::Device) -> Self { let conv1 = Conv2dConfig::new([2, 2], [2, 2]) .init(device); let conv2 = Conv2dConfig::new([2, 2], [2, 2]) .with_bias(false) .init(device); Self { conv1, conv2 } } /// Forward pass of the model. pub fn forward(&self, x: Tensor) -> Tensor { let x = self.conv1.forward(x); self.conv2.forward(x) } } } ``` -------------------------------- ### Tensor Addition with WGPU Backend in Rust Source: https://burn.dev/books/burn/print.html/index Demonstrates creating two tensors, one with explicit data and another with ones, and performing element-wise addition using the WGPU backend. It requires the 'burn::tensor::Tensor' and 'burn::backend::Wgpu' modules. ```rust use burn::tensor::Tensor; use burn::backend::Wgpu; // Type alias for the backend to use. type Backend = Wgpu; fn main() { let device = Default::default(); // Creation of two tensors, the first with explicit values and the second one with ones, with the same shape as the first let tensor_1 = Tensor::::from_data([[2., 3.], [4., 5.]], &device); let tensor_2 = Tensor::::ones_like(&tensor_1); // Print the element-wise addition (done with the WGPU backend) of the two tensors. println!("{}", tensor_1 + tensor_2); } ``` -------------------------------- ### Run Burn Project Training Source: https://burn.dev/books/burn/print.html/index This command executes the Burn project in release mode, initiating the model training process. It is the standard way to run the application after all configurations and code are in place. ```bash cargo run --release ``` -------------------------------- ### Efficient Tensor Concatenation for Data Augmentation Source: https://burn.dev/books/burn/print.html/index Illustrates how to efficiently concatenate tensors, preferably on a separate data augmentation device rather than the training device, to avoid potential performance bottlenecks. This example shows batching multiple tensors into a single one. ```rust #![allow(unused)] fn main() { /// Items is a vector of many tensors. let items = ..; let batch = Tensor::cat(items, 1); } ``` -------------------------------- ### Export PyTorch Model Weights to .pt File Source: https://burn.dev/books/burn/print.html/index Exports only the model weights (state_dict) from a PyTorch model to a .pt file. This ensures compatibility for importing into Burn. It requires PyTorch to be installed. The output is a .pt file containing the model's weights. ```python import torch import torch.nn as nn class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(2, 2, (2,2)) self.conv2 = nn.Conv2d(2, 2, (2,2), bias=False) def forward(self, x): x = self.conv1(x) x = self.conv2(x) return x if __name__ == "__main__": # Set seed for reproducibility torch.manual_seed(42) # Initialize model and ensure it's on CPU model = Net().to(torch.device("cpu")) # Extract model weights dictionary model_weights = model.state_dict() # Save only the weights, not the entire model torch.save(model_weights, "conv2d.pt") ``` -------------------------------- ### Initializing Model and Loading State Source: https://burn.dev/books/burn/print.html/index This code demonstrates how to initialize your ONNX model and load its state within the main function. It obtains a default device for the chosen backend and creates an instance of your model. ```rust use your_model::Model; // Get a default device for the backend let device = BackendDevice::default(); // Create a new model and load the state let model: Model = Model::default(); ``` -------------------------------- ### Initial Tensor Operation Sequence (Rust) Source: https://burn.dev/books/burn/print.html/index Demonstrates an initial sequence of tensor operations. This might lead to less optimal fusion due to intermediate tensor lifetimes and potential global memory writes. ```rust #![allow(unused)] fn main() { let tensor4 = tensor1.unsqueeze().matmul(tensor2) + tensor3.unsqueeze(); } ``` -------------------------------- ### Implement Burn Dataset Trait (Rust) Source: https://burn.dev/books/burn/print.html/index Implements the `Dataset` trait for the `MnistDataset` struct, enabling it to be used with Burn's data loading utilities. It provides `get` and `len` methods to access individual items and the total number of items in the dataset, respectively. ```rust __ impl Dataset for MnistDataset { fn get(&self, index: usize) -> Option { self.dataset.get(index) } fn len(&self) -> usize { self.dataset.len() } } ``` -------------------------------- ### Load PyTorch Model at Runtime with burn-import Source: https://burn.dev/books/burn/print.html/index Loads PyTorch model weights directly at runtime using the `burn-import` dependency. This method requires `burn-import` to be installed and available during execution. It takes a PyTorch file path as input and returns a loaded Burn model. ```rust use crate::model; use burn::record::{FullPrecisionSettings, Recorder}; use burn_import::pytorch::PyTorchFileRecorder; type Backend = burn_ndarray::NdArray; fn main() { let device = Default::default(); // Load weights from PyTorch file let record = PyTorchFileRecorder::::default() .load("./conv2d.pt".into(), &device) .expect("Should decode state successfully"); // Initialize model and load weights let model = model::Net::::init(&device).load_record(record); } ``` -------------------------------- ### Burn Prelude Import in Rust Source: https://burn.dev/books/burn/print.html/index Demonstrates the use of the 'prelude' module in Burn to import commonly used structs and macros collectively, simplifying code by reducing the need for individual 'use' declarations. ```rust use burn::prelude::*; ``` ```rust use burn::{ config::Config, module::Module, nn, tensor::{ backend::Backend, Bool, Device, ElementConversion, Float, Int, Shape, Tensor, TensorData, }, }; ``` -------------------------------- ### Upgrade ONNX Opset Version with Python Script Source: https://burn.dev/books/burn/print.html/index This Python script uses the ONNX library to load an ONNX model, convert it to opset version 16, perform shape inference, and save the upgraded model. Ensure you have the 'onnx' Python package installed. ```python import onnx from onnx import version_converter, shape_inference # Load your ONNX model model = onnx.load('path/to/your/model.onnx') # Convert the model to opset version 16 upgraded_model = version_converter.convert_version(model, 16) # Apply shape inference to the upgraded model inferred_model = shape_inference.infer_shapes(upgraded_model) # Save the converted model onnx.save(inferred_model, 'upgraded_model.onnx') ``` -------------------------------- ### Rust: Initialize Mnist Training Configuration and DataLoaders Source: https://burn.dev/books/burn/print.html/index Sets up the training configuration for the MNIST dataset, including hyperparameters like epochs, batch size, and learning rate. It also initializes data loaders for both training and testing sets using specified batching and shuffling strategies. ```rust #[derive(Config, Debug)] pub struct MnistTrainingConfig { #[config(default = 10)] pub num_epochs: usize, #[config(default = 64)] pub batch_size: usize, #[config(default = 4)] pub num_workers: usize, #[config(default = 42)] pub seed: u64, #[config(default = 1e-4)] pub lr: f64, pub model: ModelConfig, pub optimizer: AdamConfig, } pub fn run(device: B::Device) { // Create the configuration. let config_model = ModelConfig::new(10, 1024); let config_optimizer = AdamConfig::new(); let config = MnistTrainingConfig::new(config_model, config_optimizer); B::seed(&device, config.seed); // Create the model and optimizer. let mut model = config.model.init::(&device); let mut optim = config.optimizer.init(); // Create the batcher. let batcher = MnistBatcher::default(); // Create the dataloaders. let dataloader_train = DataLoaderBuilder::new(batcher.clone()) .batch_size(config.batch_size) .shuffle(config.seed) .num_workers(config.num_workers) .build(MnistDataset::train()); let dataloader_test = DataLoaderBuilder::new(batcher) .batch_size(config.batch_size) .shuffle(config.seed) .num_workers(config.num_workers) .build(MnistDataset::test()); ... } ``` -------------------------------- ### Dataset Trait Implementation in Rust Source: https://burn.dev/books/burn/print.html/index Defines the core `Dataset` trait in Rust, which represents a collection of data items accessible by index. It requires implementations for `get` to retrieve an item and `len` to return the total number of items. This trait is designed for fixed-length datasets with constant-time random access. ```rust pub trait Dataset: Send + Sync { fn get(&self, index: usize) -> Option; fn len(&self) -> usize; } ``` -------------------------------- ### Custom Module Derivation with Burn in Rust Source: https://burn.dev/books/burn/print.html/index Demonstrates how to create a custom deep learning module using Burn's `#[derive(Module)]` macro. This example shows a simple module 'MyCustomModule' composed of linear layers and a ReLU activation, highlighting the ease of implementing the `Module` trait for custom structures. ```rust #[derive(Module, Debug)] pub struct MyCustomModule { linear1: Linear, linear2: Linear, activation: Relu, } ``` -------------------------------- ### Load Multi-Label Image Classification Dataset with Rust Source: https://burn.dev/books/burn/print.html/index Creates a multi-label image classification dataset from a provided list of items. Each item is a tuple containing an image path and a vector of associated labels. A list of all possible classes in the dataset must also be provided. ```rust // Create a multi-label image classification dataset from a list of items, // where each item is a tuple `(image path, labels)`, and a list of classes // in the dataset. // // For example: let items = vec![ ("root/dog/dog1.png", vec!["animal".to_string(), "dog".to_string()]), ("root/cat/cat1.png", vec!["animal".to_string(), "cat".to_string()]), ]; let dataset = ImageFolderDataset::new_multilabel_classification_with_items( items, &["animal", "cat", "dog"], ) .unwrap(); ``` -------------------------------- ### Quantize Model Weights using Burn Source: https://burn.dev/books/burn/print.html/index Demonstrates how to quantize the weights of a Burn model using the `Quantizer` and `QuantScheme`. This process involves defining the quantization level, value, and parameter, then applying it to the model. It requires the `burn::module::Quantizer` and `burn::tensor::quantization` modules. ```rust use burn::module::Quantizer; use burn::tensor::quantization::{Calibration, QuantLevel, QuantParam, QuantScheme, QuantValue}; // Quantization config let scheme = QuantScheme::default() .with_level(QuantLevel::Block(32)) .with_value(QuantValue::Q4F) .with_param(QuantParam::F16); let mut quantizer = Quantizer { calibration: Calibration::MinMax, scheme, }; // Quantize the weights let model = model.quantize_weights(&mut quantizer); ``` -------------------------------- ### Implement Training and Validation Steps in Rust Source: https://burn.dev/books/burn/print.html/index Defines the `TrainStep` and `InferenceStep` for the `Model` struct in Rust. The `TrainStep` performs a single training iteration, calling `forward_classification` and returning a `TrainOutput` that includes the loss for backpropagation. The `InferenceStep` performs a single inference iteration, also using `forward_classification` to get the model's predictions. ```rust use crate::{ data::{MnistBatch, MnistBatcher}, model::{Model, ModelConfig}, }; use burn::{ data::{dataloader::DataLoaderBuilder, dataset::vision::MnistDataset}, nn::loss::CrossEntropyLossConfig, optim::AdamConfig, prelude::*, record::CompactRecorder, tensor::backend::AutodiffBackend, train::{ ClassificationOutput, InferenceStep, Learner, SupervisedTraining, TrainOutput, TrainStep, metric::{AccuracyMetric, LossMetric}, }, }; impl Model { pub fn forward_classification( &self, images: Tensor, targets: Tensor, ) -> ClassificationOutput { let output = self.forward(images); let loss = CrossEntropyLossConfig::new() .init(&output.device()) .forward(output.clone(), targets.clone()); ClassificationOutput::new(loss, output, targets) } } impl TrainStep for Model { type Input = MnistBatch; type Output = ClassificationOutput; fn step(&self, batch: MnistBatch) -> TrainOutput> { let item = self.forward_classification(batch.images, batch.targets); TrainOutput::new(self, item.loss.backward(), item) } } impl InferenceStep for Model { type Input = MnistBatch; type Output = ClassificationOutput; fn step(&self, batch: MnistBatch) -> ClassificationOutput { self.forward_classification(batch.images, batch.targets) } } ``` -------------------------------- ### Disable Gradient Tracking for Validation in Rust Source: https://burn.dev/books/burn/print.html/index Explains how to disable gradient tracking during the validation phase of a model training loop in Rust using `model.valid()`. This is crucial for evaluating model performance on unseen data without affecting the gradients computed during training. The example highlights the importance of matching the batcher's backend to the inner backend of the model to avoid compilation errors. ```rust // To disable gradient tracking during validation: model.valid() ``` -------------------------------- ### Batch Synchronous Operations with Transactions Source: https://burn.dev/books/burn/print.html/index Demonstrates how to batch synchronous operations like collecting tensor data into a single transaction to minimize synchronization overhead and improve hardware utilization. This is particularly useful when gathering metrics during training. ```rust #![allow(unused)] fn main() { /// All of these variables are tensors. let (output, loss, targets) = ..; /// Now output, loss, and targets will be `TensorData` stored on the CPU. let [output, loss, targets] = Transaction::default() .register(output) .register(loss) .register(targets) .execute() .try_into() .expect("Correct amount of tensor data"); } ``` -------------------------------- ### Initializing 1D Tensor from Floats Source: https://burn.dev/books/burn/print.html/index Shows how to initialize a 1-dimensional tensor with 5 float elements using `from_floats`. It emphasizes correct dimensionality declaration. ```rust let floats = [1.0, 2.0, 3.0, 4.0, 5.0]; // Get the default device let device = Default::default(); // correct: Tensor is 1-Dimensional with 5 elements let tensor_1 = Tensor::::from_floats(floats, &device); // incorrect: let tensor_1 = Tensor::::from_floats(floats, &device); // this will lead to an error and is for creating a 5-D tensor ```