Обучение и сохранение состояния
English | 简体中文 | 日本語 | Deutsch | Русский
Документация · Тензорная платформа · 中文
Настройте бэкенд обучения
Используйте Autodiff<Cuda<f32, i32>> для записи графов обратного прохода CUDA-тензоров, ruda-nn для определения слоёв и ruda-optim для обновления параметров. Настройка NVIDIA описана в разделе начала работы.
Добавьте эти зависимости в Cargo.toml вашего приложения. В примере каталог приложения размещается рядом с исходным каталогом RUDA:
[dependencies]
ruda-autodiff = { path = "../RUDA/ruda-autodiff", default-features = false, features = ["std"] }
ruda-model = { path = "../RUDA/ruda-model", default-features = false, features = ["std"] }
ruda-nn = { path = "../RUDA/ruda-nn", default-features = false, features = ["std"] }
ruda-optim = { path = "../RUDA/ruda-optim", default-features = false, features = ["std"] }
ruda-tensor-device = { path = "../RUDA/ruda-tensor-device", default-features = false, features = ["std", "cuda"] }
Прямое, обратное обновление и обновление параметров.
На этом этапе обучения берется реальный пакет x и нацеливается на y, вычисляется среднеквадратическая ошибка и обновляется линейный слой. Для двух входных функций и одного выходного x имеет форму [batch, 2], а y имеет форму [batch, 1]. Оба используют бэкенд B, одно и то же устройство и данные F32.
use ruda_autodiff::Autodiff;
use ruda_model::tensor::Tensor;
use ruda_nn::{Linear, LinearConfig};
use ruda_optim::{Adam, AdamConfig, GradientsParams, Optimizer, adaptor::OptimizerAdaptor};
use ruda_tensor_device::cuda::{Cuda, CudaDevice};
type B = Autodiff<Cuda<f32, i32>>;
type Model = Linear<B>;
type AdamOptimizer = OptimizerAdaptor<Adam, Model, B>;
fn train_step(
model: Model,
optimizer: &mut AdamOptimizer,
x: Tensor<B, 2>,
y: Tensor<B, 2>,
learning_rate: f64,
) -> Model {
let residual = model.forward(x) - y;
let loss = residual.square().mean();
let gradients = GradientsParams::from_grads(loss.backward(), &model);
optimizer.step(learning_rate, model, gradients)
}
Инициализируйте модель и оптимизатор, затем передайте их вместе с пакетом в train_step:
fn initialize(device: &CudaDevice) -> (Model, AdamOptimizer) {
let model = LinearConfig::new(2, 1).init::<B>(device);
let optimizer = AdamConfig::new().init();
(model, optimizer)
}
backward() использует тензор потерь и создает градиенты. GradientsParams::from_grads связывает их с параметрами модели. Сохраняйте новую модель, возвращаемую каждым вызовом optimizer.step, и сохраняйте оптимизатор между шагами, чтобы сохранить состояние импульса Адама.
Накопление градиента и планирование скорости обучения
Если полная партия не помещается в память устройства, выполните несколько микропартий вперед и назад, прежде чем обновить параметры один раз. Эта функция требует одинакового количества образцов во всех микропартиях. Разделив каждую среднюю потерю на количество микропартий, получим градиент совокупной средней потери.
use ruda_optim::GradientsAccumulator;
use ruda_optim::lr_scheduler::{
LrScheduler,
step::{StepLrScheduler, StepLrSchedulerConfig},
};
fn train_window(
mut model: Model,
optimizer: &mut AdamOptimizer,
scheduler: &mut StepLrScheduler,
batches: &[(Tensor<B, 2>, Tensor<B, 2>)],
) -> Model {
if batches.is_empty() {
return model;
}
let mut accumulator = GradientsAccumulator::new();
for (x, y) in batches {
let residual = model.forward(x.clone()) - y.clone();
let loss = residual.square().mean() / batches.len() as f64;
let gradients = GradientsParams::from_grads(loss.backward(), &model);
accumulator.accumulate(&model, gradients);
}
model = optimizer.step(scheduler.step(), model, accumulator.grads());
model
}
accumulate добавляет градиенты без усреднения. grads() возвращает накопленные градиенты и сбрасывает аккумулятор. Для неравных размеров микропартий потери веса определяются количеством проб вместо использования разделения по равному весу, описанного выше.
Вызовите scheduler.step() один раз при каждом обновлении параметра, а не после каждого микропакета. Создайте его с помощью StepLrSchedulerConfig::new(1e-3, 100).with_gamma(0.5).init(): скорость обучения начинается с 1e-3 и умножается на 0.5 каждые 100 вызовов. Инициализация возвращает Result<StepLrScheduler, String>.
Сохранить и восстановить состояние тренировки
TrainingRecord сохраняет вместе модель, оптимизатор, планировщик скорости обучения, ожидающие накопленные градиенты и состояние вызывающего объекта. Эти функции повторно используют приведенные выше типы и получают активное состояние обучения. При сохранении не создается новый оптимизатор, планировщик или аккумулятор.
use ruda_model::record::{BinFileRecorder, FullPrecisionSettings, RecorderError};
use ruda_optim::training::{RestoredTraining, TrainingRecord};
use std::path::Path;
type Snapshot = TrainingRecord<B, Model, AdamOptimizer, StepLrScheduler, (usize, usize)>;
fn save_training(
path: &Path,
model: &Model,
optimizer: &AdamOptimizer,
scheduler: &StepLrScheduler,
accumulator: &GradientsAccumulator<Model>,
completed_updates: usize,
pending_microbatches: usize,
) -> Result<(), RecorderError> {
let recorder = BinFileRecorder::<FullPrecisionSettings>::default();
Snapshot::capture(
model, optimizer, scheduler, accumulator,
(completed_updates, pending_microbatches),
)?.save(&recorder, path.into())
}
fn restore_training(
path: &Path,
device: &CudaDevice,
model: Model,
optimizer: AdamOptimizer,
scheduler: StepLrScheduler,
) -> Result<RestoredTraining<Model, AdamOptimizer, StepLrScheduler, (usize, usize)>, RecorderError> {
let recorder = BinFileRecorder::<FullPrecisionSettings>::default();
Snapshot::load(&recorder, path.into(), device)?
.restore(model, optimizer, scheduler, device)
}
При передаче Path::new("checkpoints/step-100") записывается checkpoints/step-100.bin. completed_updates подсчитывает завершенные обновления параметров, а pending_microbatches подсчитывает накопленные микропартии в текущем окне. Получите оба счетчика из restored.state после восстановления.
Восстановление с той же структурой модели, конфигурацией Адама и конфигурацией планировщика, которые использовались при сохранении. Продолжите с restored.accumulator; не очищайте его раньше времени и не воспроизводите уже накопленные микропартии. Поместите позицию итерации данных и состояние RNG в состояние вызывающего абонента U и восстановите их перед получением следующего пакета. TrainingRecord не создает автоматически снимок DataLoader.
Выбрать другой оптимизатор
ruda_optim также предоставляет SgdConfig, AdamWConfig, AdaGradConfig, RmsPropConfig, AdanConfig, MuonConfig и LBFGSConfig. При переключении оптимизаторов измените как конфигурацию, так и тип состояния. См. ruCCL для интеграции коллективного обучения.
API Ссылка: Оптимизаторы, Записи обучения.
Нативное обучение PyTorch на ruda:0
Этот путь отделён от примеров Rust Autodiff<Cuda<...>> выше. Используйте библиотеку Rust и расширение C++ из одного исходного состояния либо совместимый готовый bundle: базовый ABI 10, training API 4, router API 1, paged-backward API 2, graph API 3. См. руководство PyTorch и контракты API.
ruda_torch.RMSNorm/rms_norm, LayerNorm/layer_norm и silu_mul поддерживают нативное обучение первого порядка. Нормализация выполняется по последней оси, статистика — FP32, выход сохраняет dtype активации; аффинные параметры допускают dtype входа или FP32. Стандартный torch.nn.LayerNorm выбирает нативный путь для поддерживаемых непрерывных входов с нормализацией по последней оси. Высшие производные и захват графа обучения не поддерживаются.
ruda_torch.AdamW(params, fused_step=True, max_grad_norm=1.0, hierarchical_stats=True) явно включает анализ без изменения градиентов, глобальное L2-отсечение после снятия масштаба и иерархическую статистику. Обе булевы настройки по умолчанию False; отсечение — None и требует fused_step=True. Перед обновлениями считывается отчёт из 12 байт; нечисловые/бесконечные градиенты пропускают весь шаг. .grad сохраняется, мастер-параметры и моменты — FP32. На каждый активный параметр запускается отдельное ядро обновления, а не одно ядро для всей модели. Перед следующим окном накопления очистите градиенты. На одном экземпляре ruda_torch.GradScaler последовательно вызывайте scaler.scale(loss).backward(), scaler.step(optimizer), scaler.update().
Иерархия имеет fan-in 1024, не более двух дополнительных ядер слияния и 49 200 байт повторно используемой памяти редукции, без учёта исходной статистики. До 1024 строк дополнительные слияния не нужны. Меняется порядок редукции, но не правило отсечения.
PagedAttentionPlan(..., backward_strategy="ordered") выбирает градиенты истории без атомиков; по умолчанию остаётся "atomic". Autograd выделяет только запрошенные градиенты. Уплотнение истории и обучение роутера/экспертов при фиксированном выборе описаны в ruDNN, групповой обратный проход — в ruBLAS.
Сохраняйте state_dict() модели, оптимизатора и scaler вместе с позицией данных и состоянием RNG. Оптимизатор сохраняет fused_step и max_grad_norm; иерархические checkpoint используют step-options версии 2. Без этих настроек fused/hierarchical при восстановлении отключены. StaticGraph поддерживает явно включаемое обучение первого порядка с native forward и пересчитываемым на том же устройстве backward, без захвата обновлений оптимизатора. Обычный forward/backward модели использует отдельный AOT-вход.
См. LoRA/NF4 для адаптеров, каузального loss и восстановления и распределённое обучение для явных rank/устройств, весов по токенам и checkpoint каждого rank.