# Project Setup Best practices for structuring a RustyTorch++ project. ## Recommended Project Structure ``` my-ml-project/ ├── Cargo.toml ├── src/ │ ├── main.rs │ ├── lib.rs │ ├── models/ │ │ ├── mod.rs │ │ ├── classifier.rs │ │ └── transformer.rs │ ├── data/ │ │ ├── mod.rs │ │ ├── dataset.rs │ │ └── transforms.rs │ ├── training/ │ │ ├── mod.rs │ │ ├── trainer.rs │ │ └── optimizer.rs │ └── utils/ │ ├── mod.rs │ └── metrics.rs ├── configs/ │ ├── model.toml │ └── training.toml ├── data/ │ └── .gitkeep ├── checkpoints/ │ └── .gitkeep └── benches/ └── model_bench.rs ``` ## Cargo.toml Configuration ```toml [package] name = "my-ml-project" version = "0.1.0" edition = "2024" [dependencies] # Core ML functionality rtx-tensor = { version = "1.0", features = ["cuda"] } rtx-autograd = "1.0" rtx-nn = "1.0" # Training utilities rtx-transformers = "1.0" rtx-distributed = { version = "1.0", optional = true } # Production serving rtx-inference = "1.0" rtx-serving-api = { version = "1.0", optional = true } # Data processing rtx-preprocessing = "1.0" rtx-data-validation = "1.0" # Configuration and logging anyhow = "1.0" thiserror = "1.0" tracing = "0.1" tracing-subscriber = "0.3" serde = { version = "1.0", features = ["derive"] } toml = "0.8" # Async runtime tokio = { version = "1.0", features = ["full"] } [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] } proptest = "1.4" tempfile = "3.0" [features] default = ["cuda"] cuda = ["rtx-tensor/cuda"] metal = ["rtx-tensor/metal"] distributed = ["dep:rtx-distributed"] serving = ["dep:rtx-serving-api"] [[bench]] name = "model_bench" harness = false [profile.release] lto = "thin" codegen-units = 1 panic = "abort" [profile.dev] opt-level = 1 # Faster debug builds ``` ## Configuration Files ### Model Configuration (`configs/model.toml`) ```toml [model] name = "my-classifier" version = "1.0" [model.architecture] type = "transformer" hidden_size = 768 num_layers = 12 num_heads = 12 intermediate_size = 3072 dropout = 0.1 [model.input] image_size = 224 patch_size = 16 num_channels = 3 [model.output] num_classes = 1000 ``` ### Training Configuration (`configs/training.toml`) ```toml [training] epochs = 100 batch_size = 64 gradient_accumulation_steps = 4 [training.optimizer] type = "adamw" learning_rate = 1e-4 weight_decay = 0.01 beta1 = 0.9 beta2 = 0.999 epsilon = 1e-8 [training.scheduler] type = "cosine" warmup_steps = 1000 min_lr = 1e-6 [training.checkpoint] save_every = 10 keep_last = 5 path = "./checkpoints" [training.logging] log_every = 100 tensorboard = true ``` ## Loading Configuration ```rust use serde::Deserialize; use std::fs; #[derive(Debug, Deserialize)] pub struct ModelConfig { pub model: ModelSettings, } #[derive(Debug, Deserialize)] pub struct ModelSettings { pub name: String, pub version: String, pub architecture: ArchitectureConfig, } #[derive(Debug, Deserialize)] pub struct ArchitectureConfig { pub r#type: String, pub hidden_size: usize, pub num_layers: usize, pub num_heads: usize, pub intermediate_size: usize, pub dropout: f32, } impl ModelConfig { pub fn load(path: &str) -> anyhow::Result { let content = fs::read_to_string(path)?; let config: ModelConfig = toml::from_str(&content)?; Ok(config) } } ``` ## Logging Setup ```rust use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; pub fn setup_logging() { let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); tracing_subscriber::registry() .with(filter) .with(tracing_subscriber::fmt::layer()) .init(); } ``` ## Error Handling ```rust use thiserror::Error; #[derive(Error, Debug)] pub enum ProjectError { #[error("Model error: {0}")] Model(#[from] rtx_nn::NNError), #[error("Tensor error: {0}")] Tensor(#[from] rtx_tensor::TensorError), #[error("Configuration error: {0}")] Config(String), #[error("IO error: {0}")] Io(#[from] std::io::Error), #[error("Data loading error: {0}")] DataLoading(String), } pub type Result = std::result::Result; ``` ## Main Entry Point ```rust mod models; mod data; mod training; mod utils; use anyhow::Result; use clap::Parser; #[derive(Parser)] #[command(name = "my-ml-project")] #[command(about = "Train and serve ML models")] struct Cli { #[command(subcommand)] command: Command, } #[derive(clap::Subcommand)] enum Command { /// Train a model Train { #[arg(short, long, default_value = "configs/training.toml")] config: String, }, /// Run inference Infer { #[arg(short, long)] model: String, #[arg(short, long)] input: String, }, /// Start serving API Serve { #[arg(short, long, default_value = "8080")] port: u16, }, } #[tokio::main] async fn main() -> Result<()> { utils::setup_logging(); let cli = Cli::parse(); match cli.command { Command::Train { config } => { training::run_training(&config).await?; } Command::Infer { model, input } => { let result = models::run_inference(&model, &input)?; println!("Result: {:?}", result); } Command::Serve { port } => { // Requires "serving" feature #[cfg(feature = "serving")] { use rtx_serving_api::Server; Server::new(port).run().await?; } #[cfg(not(feature = "serving"))] { eprintln!("Serving feature not enabled. Rebuild with --features serving"); } } } Ok(()) } ``` ## Next Steps - [Architecture Overview](../architecture/overview.md) - Framework internals - [Performance Tuning](../performance/gpu-optimization.md) - Optimize training - [Deployment](../deployment/production.md) - Deploy to production