Skip to main content

optirs_nas/
lib.rs

1//! # OptiRS NAS - Neural Architecture Search
2//!
3//! **Version:** 0.3.2
4//! **Status:** Research-grade implementations; APIs may still change between releases
5//!
6//! ⚠️ **Warning:** Architecture search is compute-heavy and the search-space / objective
7//! APIs are still evolving. Validate a discovered architecture against your own baselines
8//! before relying on it in production.
9//!
10//! `optirs-nas` provides neural architecture search and automated optimizer discovery
11//! built on [SciRS2](https://github.com/cool-japan/scirs).
12//!
13//! ## Dependencies
14//!
15//! - `scirs2-core` 0.6.5 - required foundation (arrays, RNG, numeric traits)
16//!
17//! This crate has **no intra-workspace dependencies**: `optirs-core` and
18//! `optirs-learned` were declared once but never referenced, and were removed so
19//! `optirs-nas` builds and tests standalone. The benchmark harness in
20//! [`evaluation::BenchmarkSuite`] implements its optimizer update rules directly, which
21//! also makes NAS scores reproducible independently of sibling-crate changes.
22//!
23//! ## Implementation Status (v0.3.2)
24//!
25//! - ✅ Bayesian optimization ([`search_strategies::bayesian`] - Gaussian-process surrogate search)
26//! - ✅ Hyperparameter search ([`hyperparameter`] - grid enumeration, TPE, a GP-free
27//!   kernel-regression surrogate, and evolutionary search)
28//! - ✅ Evolutionary algorithms ([`search_strategies::evolutionary`] - population-based search)
29//! - ✅ RL-based search ([`search_strategies::rl_search`] - neural-controller sampling)
30//! - ✅ Differentiable search ([`search_strategies::differentiable`] - DARTS-style gradient search)
31//! - ✅ Multi-objective optimization ([`multi_objective`] - NSGA-II, NSGA-III, MOEA/D,
32//!   weighted-sum, Pareto frontier, exact hypervolume)
33//! - ✅ Hardware-aware cost modeling ([`hardware_cost`] - latency/memory/energy estimation)
34//! - ✅ AutoML pipeline coordination ([`automl_pipeline`]), cross-domain transfer, few-shot and
35//!   progressive search
36//! - 📝 Real, tested algorithms throughout - still labeled research-grade because search-space
37//!   and objective APIs may change across releases
38//!
39//! ## Features
40//!
41//! ### Search Strategies
42//! - **Bayesian Optimization** - Gaussian processes for efficient search
43//! - **Evolutionary Algorithms** - Population-based architecture evolution
44//! - **Reinforcement Learning** - Neural controller for architecture sampling
45//! - **Gradient-Based** - DARTS and differentiable NAS
46//!
47//! ### Multi-Objective Optimization
48//! - **Pareto Frontier** - Balance accuracy, speed, memory
49//! - **Weighted Sum** - Customizable objective functions
50//! - **NSGA-II** - Non-dominated sorting genetic algorithm
51//! - **NSGA-III** - Reference-point-based many-objective sorting
52//! - **MOEA/D** - Decomposition-based optimization (Tchebycheff/PBI/ASF/weighted-sum)
53//! - Interactive preference articulation and Pareto-level constraint handling
54//!   (`MultiObjectiveConfig::user_preferences`/`constraint_handling`) are declared
55//!   but not yet consulted by any optimizer; hard resource limits are enforced
56//!   separately by [`nas_engine::resources::ResourceMonitor`], not by the
57//!   multi-objective layer.
58//!
59//! ### Progressive Search
60//! - **Start Simple** - Begin with small architectures
61//! - **Gradual Complexity** - Incrementally increase depth/width
62//! - **Early Stopping** - Prune unpromising architectures
63//! - **Transfer Learning** - Reuse knowledge from previous searches
64//!
65//! ### Hardware-Aware NAS
66//! - **Latency Prediction** - Model inference time on target hardware
67//! - **Memory Estimation** - Predict GPU/TPU memory usage
68//! - **Energy Consumption** - Optimize for mobile/edge devices
69//! - **Cost Optimization** - Minimize cloud compute costs
70//!
71//! ## Example Usage
72//!
73//! The engine type is [`nas_engine::NeuralArchitectureSearch`], configured with a
74//! [`nas_engine::NASConfig`]. This example compiles and runs as a doctest, so it
75//! cannot drift away from the real API.
76//!
77//! ```rust
78//! use optirs_nas::nas_engine::resources::SystemResourceTracker;
79//! use optirs_nas::nas_engine::telemetry::{FixedTelemetry, TelemetrySample};
80//! use optirs_nas::nas_engine::{
81//!     create_minimal_nas_config, NeuralArchitectureSearch, SearchStrategyType,
82//! };
83//! use std::time::Duration;
84//!
85//! # fn main() -> Result<(), optirs_nas::error::OptimError> {
86//! // A small, ready-made configuration: a populated search space, a Random
87//! // strategy and a tiny budget.
88//! let mut config = create_minimal_nas_config::<f64>();
89//! config.search_strategy = SearchStrategyType::Evolutionary;
90//! config.search_budget = 2;
91//! config.population_size = 4;
92//!
93//! let mut engine = NeuralArchitectureSearch::new(config)?;
94//! // The engine reports which strategy is *actually* running, not just what was
95//! // requested.
96//! assert_eq!(engine.search_strategy_name(), "EvolutionaryStrategy");
97//!
98//! // Pin the telemetry so this example's outcome does not depend on how much
99//! // memory the host happens to have free. `resource_monitor_mut` is the supported
100//! // injection point for real telemetry too.
101//! engine.resource_monitor_mut().set_trackers(vec![Box::new(
102//!     SystemResourceTracker::with_telemetry(
103//!         "example".to_string(),
104//!         Duration::from_secs(5),
105//!         Box::new(FixedTelemetry::new("example", TelemetrySample::unknown())),
106//!     ),
107//! )]);
108//!
109//! // A short search: two generations against the built-in evaluator.
110//! let results = engine.run_search()?;
111//! assert!(!results.search_history.is_empty());
112//! # Ok(())
113//! # }
114//! ```
115//!
116//! Hyperparameter search is independent of the engine and can be driven directly:
117//!
118//! ```rust
119//! use optirs_nas::hyperparameter::{
120//!     DistributionType, HyperparameterOptimizer, HyperparameterSpace,
121//!     OptimizationStrategy, ParameterRange,
122//! };
123//!
124//! # fn main() -> Result<(), optirs_nas::error::OptimError> {
125//! let mut space: HyperparameterSpace<f64> = HyperparameterSpace::new();
126//! space.add_parameter(
127//!     "learning_rate".to_string(),
128//!     ParameterRange {
129//!         name: "learning_rate".to_string(),
130//!         min_value: 1e-5,
131//!         max_value: 1e-1,
132//!         distribution: DistributionType::Uniform,
133//!         log_scale: true,
134//!         discrete_values: None,
135//!     },
136//! );
137//!
138//! // Grid search enumerates the grid; it does not sample at random.
139//! let mut optimizer =
140//!     HyperparameterOptimizer::with_seed(space, OptimizationStrategy::Grid, 7);
141//! optimizer.set_grid_resolution(4);
142//! assert_eq!(optimizer.grid_size(), Some(4));
143//!
144//! let suggestion = optimizer.suggest_configuration()?;
145//! let learning_rate = suggestion.parameters["learning_rate"];
146//! assert!((1e-5..=1e-1).contains(&learning_rate));
147//! # Ok(())
148//! # }
149//! ```
150//!
151//! ## Supported Search Spaces
152//!
153//! - **Optimizer Selection** - Choose between SGD, Adam, RMSprop, etc.
154//! - **Hyperparameters** - Learning rates, momentum, weight decay
155//! - **Learning Rate Schedules** - Warmup, decay, cosine annealing
156//! - **Regularization** - L1/L2, dropout rates, gradient clipping
157//! - **Architecture Components** - Optimizer composition and ensembles
158//!
159//! ## Architecture
160//!
161//! Every algorithm in this crate is implemented here; `scirs2-core` supplies the
162//! numeric substrate only:
163//!
164//! - **Arrays**: `scirs2_core::ndarray` ([`scirs2_core::ndarray::Array1`] / `Array2` / `Array3`)
165//! - **Numeric traits**: `scirs2_core::numeric` ([`scirs2_core::numeric::Float`], `NumCast`)
166//! - **RNG**: `scirs2_core::random` (`Random`, `Rng`)
167//!
168//! The search machinery itself lives in this crate:
169//! - **Search space**: [`nas_engine::SearchSpaceConfig`]
170//! - **Engine**: [`nas_engine::NeuralArchitectureSearch`]
171//! - **Strategies**: [`search_strategies`]
172//! - **Multi-objective**: [`multi_objective`]
173//!
174//! (Earlier revisions of this document referenced
175//! `scirs2_core::neural_architecture_search` and
176//! `scirs2_core::quantum_optimization`; neither module exists.)
177//!
178//! ## References
179//!
180//! - DARTS: Differentiable Architecture Search (Liu et al., 2019)
181//! - EfficientNet: Rethinking Model Scaling for CNNs (Tan & Le, 2019)
182//! - Once-for-All: Train One Network and Specialize it for Efficient Deployment (Cai et al., 2020)
183//!
184//! ## Contributing
185//!
186//! Research contributions welcome! Follow SciRS2 integration guidelines.
187
188/// Compiles and runs every `rust` code block in `README.md` as a doctest, so the
189/// README cannot drift away from the API.
190///
191/// The previous README documented roughly twenty types that do not exist
192/// (`NASEngine`, `BayesianOptimizer`, `ProgressiveNAS::new().with_initial_depth(..)`,
193/// `HardwareAwareNAS`, `DistributedNAS`, ...) and `.await`ed every call in a crate
194/// with no `async fn` at all. Nothing caught it because nothing compiled it.
195///
196/// `#[cfg(doctest)]` keeps this out of the published documentation and out of
197/// normal builds; it exists only so `cargo test --doc` picks the file up.
198#[cfg(doctest)]
199#[doc = include_str!("../README.md")]
200struct ReadmeDoctests;
201
202pub mod architecture;
203pub mod architecture_embedding;
204pub mod architecture_knowledge_graph;
205pub mod automl_pipeline;
206pub mod cross_domain_transfer;
207pub mod domain_specific_nas;
208pub mod error;
209pub mod evaluation;
210pub mod few_shot_architecture;
211pub mod hardware_cost;
212pub mod hyperparameter;
213pub mod multi_objective;
214pub mod multimodal_nas;
215pub mod nas_engine;
216pub(crate) mod numeric;
217pub mod progressive;
218pub mod search_strategies;
219pub mod speech_nas;
220
221pub use architecture::ArchitectureSpace;
222pub use architecture_embedding::{AggregationMethod, ArchitectureEmbedder};
223pub use architecture_knowledge_graph::{
224    ArchKnowledgeEdge, ArchKnowledgeNode, ArchitectureKnowledgeGraph, NodeId, PerformanceRecord,
225    RelationType,
226};
227pub use automl_pipeline::{
228    AutomlPipelineConfig, AutomlPipelineCoordinator, CandidateModel, EnsembleStrategy,
229    FeatureEngineeringStep, PipelineEvaluation, PreprocessingStep, ScoredPipeline, SvmKernel,
230    TrainValSplit,
231};
232pub use cross_domain_transfer::{
233    CrossDomainTransferEngine, DomainProfile, DomainSimilarityMetric, DomainSimilarityReport,
234    TransferRecommendation, TransferabilityWeights,
235};
236pub use domain_specific_nas::{
237    DomainNASEngine, DomainSearchSpace, DomainType as NASDomainType, NASConstraint,
238};
239pub use error::{OptimError, Result};
240pub use few_shot_architecture::{
241    ArchitectureExample, DistanceMetric, FewShotAlgorithm, FewShotArchitectureOptimizer,
242    FewShotConfig, FewShotPrediction,
243};
244pub use hardware_cost::{
245    ActivationKind, Bottleneck, CostReport, HardwareCostModel, HardwareProfile, LatencyLookupTable,
246    LatencyPrediction, LatencySource, LayerKind, LayerSignature, LayerSpec, PerLayerCost, PoolKind,
247    RooflineResult,
248};
249pub use multimodal_nas::{
250    FusionOp, Modality, ModalityEncoder, MultimodalArchitecture, MultimodalEvaluation,
251    MultimodalLayer, MultimodalNasEngine, MultimodalSearchSpace, MultimodalValidationError,
252};
253pub use search_strategies::SearchStrategy;
254pub use speech_nas::{
255    layer_position_constraint, LayerPositionConstraint, SpeechLayerType, SpeechModelConfig,
256    SpeechModelEvaluation, SpeechNasEngine, SpeechSearchSpace,
257};
258
259// Re-export key types
260use serde::{Deserialize, Serialize};
261
262/// Evaluation configuration for architecture search
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct EvaluationConfig {
265    /// Number of epochs for evaluation
266    pub epochs: u32,
267    /// Batch size for training
268    pub batch_size: usize,
269    /// Learning rate for evaluation
270    pub learning_rate: f64,
271    /// Use performance prediction
272    pub performance_prediction: bool,
273}
274
275/// Evaluation metrics for architectures
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
277pub enum EvaluationMetric {
278    /// Final performance metric
279    FinalPerformance,
280    /// Convergence speed metric
281    ConvergenceSpeed,
282    /// Model stability metric
283    Stability,
284    /// Robustness metric
285    Robustness,
286    /// Efficiency metric
287    Efficiency,
288    /// Generalization metric
289    Generalization,
290    /// Memory usage metric
291    MemoryUsage,
292    /// Computation time metric
293    ComputationTime,
294    /// Training stability metric
295    TrainingStability,
296    /// Memory efficiency metric
297    MemoryEfficiency,
298    /// Computational efficiency metric
299    ComputationalEfficiency,
300    /// Accuracy metric
301    Accuracy,
302    /// Training time metric
303    TrainingTime,
304}
305
306// ---------------------------------------------------------------------------
307// Canonical result / architecture types
308// ---------------------------------------------------------------------------
309//
310// The generic, element-type-parameterised definitions in
311// [`nas_engine::results`] are the single source of truth for architectures,
312// evaluation results and resource accounting. They are re-exported here so
313// `optirs_nas::OptimizerArchitecture<T>` and
314// `nas_engine::results::OptimizerArchitecture<T>` name the *same* type. Earlier
315// releases carried a second, `f64`-only copy of each of these structs at the
316// crate root; those duplicates are gone.
317
318pub use nas_engine::config::NASConfig;
319pub use nas_engine::results::{
320    BenchmarkResult, CrossValidationResults, EvaluationResults, OptimizerArchitecture,
321    ResourceUsage, TrainingSnapshot,
322};
323
324impl Default for EvaluationConfig {
325    fn default() -> Self {
326        Self {
327            epochs: 20,
328            batch_size: 32,
329            learning_rate: 1e-3,
330            performance_prediction: false,
331        }
332    }
333}
334
335impl EvaluationConfig {
336    /// Derive an evaluation configuration from the richer, generic
337    /// [`nas_engine::config::EvaluationConfig`] carried by [`NASConfig`].
338    ///
339    /// The engine-level configuration describes budgets and statistical
340    /// testing; the evaluation subsystem only needs the step budget, batch size
341    /// and base learning rate, plus whether performance prediction is enabled.
342    /// `max_epochs` is clamped to at least one step so an evaluation always
343    /// performs real work.
344    pub fn from_engine_config<T>(config: &nas_engine::config::EvaluationConfig<T>) -> Self
345    where
346        T: scirs2_core::numeric::Float + std::fmt::Debug + Send + Sync + 'static,
347    {
348        Self {
349            epochs: config.evaluation_budget.max_epochs.max(1) as u32,
350            batch_size: 32,
351            learning_rate: 1e-3,
352            performance_prediction: false,
353        }
354    }
355}