burn для Rust: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

burn для Rust: полное руководство с примерами

1. Что это и зачем нужна

Burn — это современный фреймворк для глубокого обучения, написанный на Rust. Он предоставляет полный набор инструментов для создания, обучения и развертывания нейронных сетей с акцентом на производительность, безопасность памяти и гибкость. В отличие от традиционных фреймворков, таких как PyTorch или TensorFlow, Burn использует все преимущества Rust: нулевая стоимость абстракций, гарантии безопасности на этапе компиляции и отсутствие сборщика мусора. Это делает его идеальным выбором для систем, где критичны предсказуемая производительность и низкое потребление ресурсов — например, в робототехнике, встраиваемых системах, высоконагруженных серверах и edge-устройствах.

Burn предлагает уникальную архитектуру, основанную на концепции "backend-нейтральности". Это означает, что один и тот же код может выполняться на CPU (через собственный тензорный движок), GPU (через CUDA/WGPU), а в будущем — на специализированных ускорителях. Фреймворк поддерживает автоматическое дифференцирование, оптимизаторы (Adam, SGD, AdamW), функции потерь, слои (Linear, Conv2d, BatchNorm, Dropout и др.), а также встроенные датасеты и DataLoader. Ключевая особенность — возможность компилировать модели в статические библиотеки для развертывания без зависимостей от Python или CUDA runtime.

Зачем использовать Burn? Во-первых, для проектов, где требуется максимальная производительность и контроль над памятью. Во-вторых, для создания кроссплатформенных решений, работающих на CPU, GPU и даже WebAssembly. В-третьих, для безопасного развертывания моделей в production, где ошибки времени выполнения (например, null pointer или type mismatch) недопустимы. Burn активно развивается сообществом и уже используется в таких областях, как компьютерное зрение, NLP, рекомендательные системы и обучение с подкреплением.

2. Установка

Для установки Burn требуется Rust (рекомендуется версия 1.75 или новее). Если Rust еще не установлен, воспользуйтесь rustup.

Создайте новый проект и добавьте зависимости в Cargo.toml:

cargo new my_burn_project
cd my_burn_project

Добавьте в Cargo.toml:

[dependencies]
burn = { version = "0.15", features = ["ndarray"] }  # для CPU
# или для GPU (CUDA):
# burn = { version = "0.15", features = ["cuda"] }
# или для WGPU (кроссплатформенный GPU):
# burn = { version = "0.15", features = ["wgpu"] }

Затем выполните:

cargo build

Для работы с CUDA потребуется установленный CUDA Toolkit 11.x или 12.x. Для WGPU — Vulkan, Metal или DirectX 12 (в зависимости от ОС).

3. Быстрый старт — минимальный рабочий пример

Создадим простую нейронную сеть для задачи регрессии на синтетических данных. Этот пример демонстрирует основные шаги: определение модели, создание данных, обучение и инференс.

use burn::{
    module::Module,
    nn::{Linear, Relu},
    tensor::{backend::Backend, Tensor},
    train::{Adam, Learner},
    data::dataloader::DataLoaderBuilder,
};

// Определяем структуру модели
#[derive(Module, Debug)]
struct MyModel {
    linear1: Linear,
    linear2: Linear,
    activation: Relu,
}

impl MyModel {
    fn new() -> Self {
        Self {
            linear1: Linear::new(1, 16),
            linear2: Linear::new(16, 1),
            activation: Relu::new(),
        }
    }

    fn forward(&self, input: Tensor) -> Tensor {
        let x = self.linear1.forward(input);
        let x = self.activation.forward(x);
        self.linear2.forward(x)
    }
}

fn main() {
    // Используем backend на CPU
    type B = burn::backend::NdArray;

    // Создаем модель
    let model = MyModel::::new();

    // Генерируем синтетические данные: y = 2*x + 1 + шум
    let x = Tensor::::from_data([[1.0], [2.0], [3.0], [4.0], [5.0]]);
    let y = Tensor::::from_data([[3.0], [5.0], [7.0], [9.0], [11.0]]);

    // Создаем оптимизатор Adam
    let mut optimizer = Adam::new(0.01);

    // Обучаем 100 эпох
    for epoch in 0..100 {
        let output = model.forward(x.clone());
        let loss = (output.clone() - y.clone()).powf(2.0).mean();

        // Обратное распространение
        let grads = loss.backward();
        optimizer.step(&model, &grads);

        if epoch % 10 == 0 {
            println!("Epoch {}: Loss = {:.4}", epoch, loss.into_scalar());
        }
    }

    // Инференс
    let test_input = Tensor::::from_data([[6.0]]);
    let prediction = model.forward(test_input);
    println!("Prediction for x=6: {:.2}", prediction.into_data().to_vec::()[0]);
}

Этот пример показывает, как легко создать и обучить модель в Burn. Обратите внимание на использование дженериков B: Backend — это позволяет переключаться между CPU и GPU без изменения кода модели.

4. Основные методы/функции/классы

4.1. Module — derive-макрос для нейросетевых модулей

Сигнатура: #[derive(Module)]

Что делает: Автоматически реализует трейт Module для структуры, позволяя управлять параметрами, сериализацией и перемещением между устройствами.

#[derive(Module, Debug)]
struct MyModule {
    linear: Linear,
    dropout: Dropout,
}

4.2. Tensor::from_data — создание тензора из данных

Сигнатура: pub fn from_data(data: impl Into>) -> Tensor

Что делает: Создает тензор заданной размерности из предоставленных данных. Данные могут быть массивом, вектором или срезом.

let t = Tensor::::from_data([[1.0, 2.0], [3.0, 4.0]]);

4.3. Linear::new — полносвязный слой

Сигнатура: pub fn new(d_input: usize, d_output: usize) -> Self

Что делает: Создает линейный (полносвязный) слой с заданным количеством входных и выходных нейронов. Инициализирует веса и смещения.

let layer = Linear::::new(64, 128);

4.4. Conv2d::new — двумерный сверточный слой

Сигнатура: pub fn new(in_channels: usize, out_channels: usize, kernel_size: usize) -> Self

Что делает: Создает 2D сверточный слой для обработки изображений. Можно задать размер ядра, шаг и паддинг.

let conv = Conv2d::::new(3, 32, 3); // 3 входных канала, 32 выходных, ядро 3x3

4.5. Adam::new — оптимизатор Adam

Сигнатура: pub fn new(learning_rate: f64) -> Self

Что делает: Создает оптимизатор Adam с заданной скоростью обучения. Можно дополнительно настроить параметры beta1, beta2 и epsilon.

let optimizer = Adam::new(0.001);

4.6. Tensor::backward — обратное распространение

Сигнатура: pub fn backward(&self) -> Gradients

Что делает: Вычисляет градиенты для всех параметров, от которых зависит данный тензор. Возвращает структуру Gradients, содержащую градиенты.

let loss = (output - target).powf(2.0).mean();
let grads = loss.backward();

4.7. DataLoaderBuilder — построитель загрузчика данных

Сигнатура: pub fn new(dataset: D) -> DataLoaderBuilder

Что делает: Создает загрузчик данных с возможностью настройки размера батча, перемешивания и многопоточной загрузки.

let dataloader = DataLoaderBuilder::new(dataset)
    .batch_size(32)
    .shuffle(true)
    .num_workers(4)
    .build();

4.8. CrossEntropyLoss — функция потерь кросс-энтропии

Сигнатура: pub fn new() -> Self

Что делает: Создает функцию потерь для задач многоклассовой классификации. Применяет softmax к выходным логитам и вычисляет кросс-энтропию.

let loss_fn = CrossEntropyLoss::::new();
let loss = loss_fn.forward(output, targets);

4.9. Tensor::matmul — матричное умножение

Сигнатура: pub fn matmul(&self, other: &Tensor) -> Tensor

Что делает: Выполняет матричное умножение двух двумерных тензоров. Аналог torch.mm или np.dot.

let a = Tensor::::from_data([[1.0, 2.0], [3.0, 4.0]]);
let b = Tensor::::from_data([[5.0], [6.0]]);
let c = a.matmul(&b);

4.10. Module::save / Module::load — сериализация модели

Сигнатура: pub fn save(&self, writer: &mut F) -> Result<()>
pub fn load(reader: &mut F) -> Result

Что делает: Сохраняет и загружает параметры модели в/из файла. Использует формат, совместимый с serde.

// Сохранение
let mut file = File::create("model.bin").unwrap();
model.save(&mut file).unwrap();

// Загрузка
let mut file = File::open("model.bin").unwrap();
let loaded_model = MyModel::::load(&mut file).unwrap();

5. Реальный практический пример

Разработаем полную систему для классификации рукописных цифр (MNIST) с использованием Burn. Пример включает: загрузку данных, определение CNN, обучение, валидацию и сохранение модели.

use burn::{
    module::Module,
    nn::{Conv2d, Linear, Relu, MaxPool2d, Dropout},
    tensor::{backend::Backend, Tensor},
    train::{Adam, Learner},
    data::{dataset::Dataset, dataloader::DataLoaderBuilder},
    record::{FullPrecisionSettings, NamedMpkFileRecorder},
};

// Определяем модель CNN
#[derive(Module, Debug)]
struct MnistModel {
    conv1: Conv2d,
    conv2: Conv2d,
    pool: MaxPool2d,
    fc1: Linear,
    fc2: Linear,
    dropout: Dropout,
    activation: Relu,
}

impl MnistModel {
    fn new() -> Self {
        Self {
            conv1: Conv2d::new(1, 32, 3),   // 1 канал -> 32, ядро 3x3
            conv2: Conv2d::new(32, 64, 3),  // 32 -> 64, ядро 3x3
            pool: MaxPool2d::new(2),        // пулинг 2x2
            fc1: Linear::new(64 * 5 * 5, 128), // после пулинга: 64*5*5
            fc2: Linear::new(128, 10),      // 10 классов
            dropout: Dropout::new(0.5),
            activation: Relu::new(),
        }
    }

    fn forward(&self, input: Tensor) -> Tensor {
        let batch_size = input.dims()[0];
        let x = input.reshape([batch_size, 1, 28, 28]); // [N, 1, 28, 28]
        let x = self.conv1.forward(x);
        let x = self.activation.forward(x);
        let x = self.pool.forward(x);
        let x = self.conv2.forward(x);
        let x = self.activation.forward(x);
        let x = self.p                    

Рекомендаций