1#![cfg_attr(not(feature = "std"), no_std)]
42#![allow(dead_code)] #![allow(unused_imports)] #![allow(unused_variables)] #![allow(unused_mut)] #[cfg(not(feature = "std"))]
50extern crate alloc;
51
52pub mod adabelief;
53pub mod adabound;
54pub mod adadelta;
55pub mod adagrad;
56pub mod adahessian;
57pub mod adam;
58pub mod adamax;
59pub mod advanced;
60pub mod asgd;
61pub mod bayesian_optimization;
62pub mod benchmarks;
63pub mod checkpointing;
64pub mod composition;
65pub mod continual_learning;
66pub mod cross_framework_validation;
67pub mod debugging;
68pub mod differential_privacy;
69pub mod distributed;
70pub mod evolutionary_strategies;
71pub mod ftrl;
72pub mod fused_kernels;
73pub mod grad_accumulation;
74pub mod gradient_free;
75pub mod green_ai;
76pub mod hyperparameter_tuning;
77pub mod kfac;
78pub mod lamb;
79pub mod lazy_updates;
80pub mod lbfgs;
81pub mod lion;
82pub mod lookahead;
83pub mod low_precision;
84pub mod lr_scheduler;
85pub mod lr_scheduler_additional;
86pub mod lr_scheduler_enhanced;
87pub mod memory_efficient;
88pub mod memory_mapped;
89pub mod mixed_precision;
90pub mod nadam;
91pub mod natural_gradient;
92pub mod neural_optimizer;
93pub mod neuromorphic;
94pub mod newton_cg;
95pub mod numerical_stability_tests;
96pub mod online_learning;
97pub mod optimizer;
98pub mod param_update;
99pub mod prodigy;
100pub mod quantum_inspired;
101pub mod radam;
102pub mod ranger;
103pub mod rmsprop;
104pub mod robustness;
105pub mod rprop;
106pub mod schedule_free;
107pub mod sgd;
108pub mod shampoo;
109pub mod sophia;
110pub mod sparse_adam;
111pub mod sparse_updates;
112pub mod state_dict_ops;
113pub mod stress_tests;
114pub mod trust_region;
115pub mod yellowfin;
116
117use parking_lot::RwLock;
118use std::collections::HashMap;
119use std::sync::Arc;
120use torsh_core::error::{Result, TorshError};
121use torsh_tensor::Tensor;
122
123#[derive(Debug, thiserror::Error)]
125pub enum OptimizerError {
126 #[error("Tensor operation failed: {0}")]
127 TensorError(#[from] torsh_core::error::TorshError),
128
129 #[error("Invalid parameter: {0}")]
130 InvalidParameter(String),
131
132 #[error("Serialization error: {0}")]
133 SerializationError(String),
134
135 #[error("IO error: {0}")]
136 IoError(#[from] std::io::Error),
137
138 #[error("Checkpoint error: {0}")]
139 CheckpointError(String),
140
141 #[error("Configuration error: {0}")]
142 ConfigError(String),
143
144 #[error("State error: {0}")]
145 StateError(String),
146
147 #[error("Invalid input: {0}")]
148 InvalidInput(String),
149
150 #[error("Numerical error: {0}")]
151 NumericalError(String),
152
153 #[error("Memory map error: {0}")]
154 MemoryMapError(String),
155}
156
157impl From<OptimizerError> for torsh_core::error::TorshError {
158 fn from(err: OptimizerError) -> Self {
159 match err {
160 OptimizerError::TensorError(e) => e,
161 OptimizerError::InvalidParameter(msg) => {
162 torsh_core::error::TorshError::InvalidArgument(msg)
163 }
164 OptimizerError::SerializationError(msg) => {
165 torsh_core::error::TorshError::SerializationError(msg)
166 }
167 OptimizerError::IoError(e) => torsh_core::error::TorshError::IoError(e.to_string()),
168 OptimizerError::CheckpointError(msg) => {
169 torsh_core::error::TorshError::RuntimeError(msg)
170 }
171 OptimizerError::ConfigError(msg) => torsh_core::error::TorshError::ConfigError(msg),
172 OptimizerError::StateError(msg) => torsh_core::error::TorshError::RuntimeError(msg),
173 OptimizerError::InvalidInput(msg) => {
174 torsh_core::error::TorshError::InvalidArgument(msg)
175 }
176 OptimizerError::NumericalError(msg) => torsh_core::error::TorshError::RuntimeError(msg),
177 OptimizerError::MemoryMapError(msg) => torsh_core::error::TorshError::RuntimeError(msg),
178 }
179 }
180}
181
182pub type OptimizerResult<T> = std::result::Result<T, OptimizerError>;
184
185pub const VERSION: &str = env!("CARGO_PKG_VERSION");
187pub const VERSION_MAJOR: u32 = 0;
188pub const VERSION_MINOR: u32 = 1;
189pub const VERSION_PATCH: u32 = 0;
190
191pub trait Optimizer {
196 fn step(&mut self) -> OptimizerResult<()>;
198
199 fn zero_grad(&mut self);
201
202 fn get_lr(&self) -> Vec<f32>;
204
205 fn set_lr(&mut self, lr: f32);
207
208 fn set_lrs(&mut self, lrs: &[f32]) {
223 if let Some(&lr) = lrs.first() {
224 self.set_lr(lr);
225 }
226 }
227
228 fn add_param_group(&mut self, params: Vec<Arc<RwLock<Tensor>>>, options: HashMap<String, f32>);
230
231 fn parameters(&self) -> Vec<Arc<RwLock<Tensor>>> {
251 Vec::new()
252 }
253
254 fn state_dict(&self) -> OptimizerResult<OptimizerState>;
256
257 fn load_state_dict(&mut self, state: OptimizerState) -> OptimizerResult<()>;
259}
260
261#[derive(Debug, Clone)]
263pub struct OptimizerState {
264 pub optimizer_type: String,
266 pub version: String,
268 pub param_groups: Vec<ParamGroupState>,
270 pub state: HashMap<String, HashMap<String, Tensor>>,
272 pub global_state: HashMap<String, f32>,
274}
275
276#[derive(Debug, Clone)]
278pub struct ParamGroupState {
279 pub lr: f32,
281 pub options: HashMap<String, f32>,
283 pub param_count: usize,
285}
286
287impl OptimizerState {
288 pub fn new(optimizer_type: String) -> Self {
290 Self {
291 optimizer_type,
292 version: VERSION.to_string(),
293 param_groups: Vec::new(),
294 state: HashMap::new(),
295 global_state: HashMap::new(),
296 }
297 }
298
299 pub fn validate(&self) -> Result<()> {
301 if self.optimizer_type.is_empty() {
302 return Err(TorshError::InvalidArgument(
303 "Optimizer type cannot be empty".to_string(),
304 ));
305 }
306
307 for (i, group) in self.param_groups.iter().enumerate() {
309 if !group.lr.is_finite() || group.lr <= 0.0 {
310 return Err(TorshError::InvalidArgument(format!(
311 "Invalid learning rate in group {}",
312 i
313 )));
314 }
315 }
316
317 for (param_id, param_state) in &self.state {
319 for (state_name, tensor) in param_state {
320 if param_id.is_empty() || state_name.is_empty() {
322 return Err(TorshError::InvalidArgument(
323 "State keys cannot be empty".to_string(),
324 ));
325 }
326 }
327 }
328
329 Ok(())
330 }
331
332 pub fn total_param_count(&self) -> usize {
334 self.param_groups.iter().map(|g| g.param_count).sum()
335 }
336
337 pub fn is_compatible_with(&self, other: &OptimizerState) -> bool {
339 self.optimizer_type == other.optimizer_type
340 && self.param_groups.len() == other.param_groups.len()
341 && self
342 .param_groups
343 .iter()
344 .zip(other.param_groups.iter())
345 .all(|(a, b)| a.param_count == b.param_count)
346 }
347}
348
349impl ParamGroupState {
350 pub fn new(lr: f32, param_count: usize) -> Self {
352 Self {
353 lr,
354 options: HashMap::new(),
355 param_count,
356 }
357 }
358
359 pub fn from_param_group(group: &ParamGroup) -> Self {
361 Self {
362 lr: group.lr,
363 options: group.options.clone(),
364 param_count: group.params.len(),
365 }
366 }
367
368 pub fn get_option(&self, key: &str, default: f32) -> f32 {
370 self.options.get(key).copied().unwrap_or(default)
371 }
372
373 pub fn set_option(&mut self, key: String, value: f32) {
375 self.options.insert(key, value);
376 }
377}
378
379#[derive(Debug, Clone)]
381pub struct ParamGroup {
382 pub params: Vec<Arc<RwLock<Tensor>>>,
383 pub lr: f32,
384 pub options: HashMap<String, f32>,
385}
386
387#[derive(Debug)]
389pub struct ParamGroupBuilder {
390 params: Vec<Arc<RwLock<Tensor>>>,
391 lr: f32,
392 options: HashMap<String, f32>,
393}
394
395impl ParamGroupBuilder {
396 pub fn new(lr: f32) -> Self {
398 Self {
399 params: Vec::new(),
400 lr,
401 options: HashMap::new(),
402 }
403 }
404
405 pub fn params(mut self, params: Vec<Arc<RwLock<Tensor>>>) -> Self {
407 self.params = params;
408 self
409 }
410
411 pub fn add_param(mut self, param: Arc<RwLock<Tensor>>) -> Self {
413 self.params.push(param);
414 self
415 }
416
417 pub fn weight_decay(mut self, weight_decay: f32) -> Self {
419 self.options
420 .insert("weight_decay".to_string(), weight_decay);
421 self
422 }
423
424 pub fn eps(mut self, eps: f32) -> Self {
426 self.options.insert("eps".to_string(), eps);
427 self
428 }
429
430 pub fn option(mut self, key: String, value: f32) -> Self {
432 self.options.insert(key, value);
433 self
434 }
435
436 pub fn from_options(mut self, options: &OptimizerOptions) -> Self {
438 self.lr = options.lr;
439 self.options = options.to_hashmap();
440 self.options.remove("lr"); self
442 }
443
444 pub fn build(self) -> ParamGroup {
446 ParamGroup {
447 params: self.params,
448 lr: self.lr,
449 options: self.options,
450 }
451 }
452}
453
454impl ParamGroup {
455 pub fn new(params: Vec<Arc<RwLock<Tensor>>>, lr: f32) -> Self {
456 Self {
457 params,
458 lr,
459 options: HashMap::new(),
460 }
461 }
462
463 pub fn with_options(mut self, options: HashMap<String, f32>) -> Self {
464 self.options = options;
465 self
466 }
467
468 pub fn add_param(&mut self, param: Arc<RwLock<Tensor>>) {
470 self.params.push(param);
471 }
472
473 pub fn get_option(&self, key: &str, default: f32) -> f32 {
475 self.options.get(key).copied().unwrap_or(default)
476 }
477
478 pub fn set_option(&mut self, key: String, value: f32) {
480 self.options.insert(key, value);
481 }
482
483 pub fn param_count(&self) -> usize {
485 self.params.len()
486 }
487
488 pub fn is_empty(&self) -> bool {
490 self.params.is_empty()
491 }
492
493 pub fn params_with_grads(&self) -> Vec<&Arc<RwLock<Tensor>>> {
495 self.params
496 .iter()
497 .filter(|param| param.read().has_grad())
498 .collect()
499 }
500
501 pub fn validate(&self) -> bool {
503 !self.params.is_empty() && self.lr.is_finite() && self.lr > 0.0
504 }
505
506 pub fn get_shape_counts(&self) -> HashMap<Vec<usize>, usize> {
508 let mut shape_counts = HashMap::new();
509 for param in &self.params {
510 let shape = param.read().shape().dims().to_vec();
511 *shape_counts.entry(shape).or_insert(0) += 1;
512 }
513 shape_counts
514 }
515
516 pub fn total_param_count(&self) -> usize {
518 self.params.iter().map(|param| param.read().numel()).sum()
519 }
520
521 pub fn zero_grad(&self) {
523 for param in &self.params {
524 param.write().zero_grad();
525 }
526 }
527
528 pub fn has_any_grads(&self) -> bool {
530 self.params.iter().any(|param| param.read().has_grad())
531 }
532
533 pub fn grad_norm(&self) -> Result<f32> {
535 let mut total_norm_sq = 0.0f32;
536
537 for param in &self.params {
538 let param_guard = param.read();
539 if let Some(grad) = param_guard.grad() {
540 let grad_norm = grad.norm().map_err(|e| {
541 TorshError::Other(format!("Failed to compute gradient norm: {}", e))
542 })?;
543 let norm_value = grad_norm.to_vec().map_err(|e| {
544 TorshError::Other(format!("Failed to extract norm value: {}", e))
545 })?[0];
546 total_norm_sq += norm_value * norm_value;
547 }
548 }
549
550 Ok(total_norm_sq.sqrt())
551 }
552
553 pub fn clip_grads(&self, max_norm: f32) -> Result<f32> {
555 let total_norm = self.grad_norm()?;
556
557 if total_norm > max_norm {
558 let scale = max_norm / total_norm;
559 for param in &self.params {
560 let mut param_guard = param.write();
561 if let Some(grad) = param_guard.grad() {
562 let clipped_grad = grad.mul_scalar(scale).map_err(|e| {
563 TorshError::Other(format!("Failed to clip gradient: {}", e))
564 })?;
565 param_guard.set_grad(Some(clipped_grad));
566 }
567 }
568 }
569
570 Ok(total_norm)
571 }
572}
573
574#[derive(Debug, Clone)]
576pub struct OptimizerOptions {
577 pub lr: f32,
578 pub weight_decay: f32,
579 pub eps: f32,
580 pub maximize: bool,
581}
582
583impl Default for OptimizerOptions {
584 fn default() -> Self {
585 Self {
586 lr: 1e-3,
587 weight_decay: 0.0,
588 eps: 1e-8,
589 maximize: false,
590 }
591 }
592}
593
594impl OptimizerOptions {
595 pub fn new(lr: f32) -> Self {
597 Self {
598 lr,
599 ..Default::default()
600 }
601 }
602
603 pub fn with_weight_decay(mut self, weight_decay: f32) -> Self {
605 self.weight_decay = weight_decay;
606 self
607 }
608
609 pub fn with_eps(mut self, eps: f32) -> Self {
611 self.eps = eps;
612 self
613 }
614
615 pub fn with_maximize(mut self, maximize: bool) -> Self {
617 self.maximize = maximize;
618 self
619 }
620
621 pub fn to_hashmap(&self) -> HashMap<String, f32> {
623 let mut map = HashMap::new();
624 map.insert("lr".to_string(), self.lr);
625 map.insert("weight_decay".to_string(), self.weight_decay);
626 map.insert("eps".to_string(), self.eps);
627 map.insert(
628 "maximize".to_string(),
629 if self.maximize { 1.0 } else { 0.0 },
630 );
631 map
632 }
633
634 pub fn from_hashmap(map: &HashMap<String, f32>) -> Self {
636 Self {
637 lr: map.get("lr").copied().unwrap_or(1e-3),
638 weight_decay: map.get("weight_decay").copied().unwrap_or(0.0),
639 eps: map.get("eps").copied().unwrap_or(1e-8),
640 maximize: map.get("maximize").copied().unwrap_or(0.0) > 0.0,
641 }
642 }
643
644 pub fn validate(&self) -> Result<()> {
646 if !self.lr.is_finite() || self.lr <= 0.0 {
647 return Err(TorshError::InvalidArgument(
648 "Learning rate must be positive and finite".to_string(),
649 ));
650 }
651 if !self.weight_decay.is_finite() || self.weight_decay < 0.0 {
652 return Err(TorshError::InvalidArgument(
653 "Weight decay must be non-negative and finite".to_string(),
654 ));
655 }
656 if !self.eps.is_finite() || self.eps <= 0.0 {
657 return Err(TorshError::InvalidArgument(
658 "Epsilon must be positive and finite".to_string(),
659 ));
660 }
661 Ok(())
662 }
663
664 pub fn create_standard_state_dict(
666 optimizer_type: &str,
667 version: Option<&str>,
668 param_groups: &[ParamGroup],
669 state: &HashMap<String, HashMap<String, Tensor>>,
670 global_state: Option<HashMap<String, f32>>,
671 ) -> OptimizerState {
672 let param_group_states = param_groups
673 .iter()
674 .map(|g| ParamGroupState::from_param_group(g))
675 .collect();
676
677 let mut optimizer_state = OptimizerState {
678 optimizer_type: optimizer_type.to_string(),
679 version: version.unwrap_or("1.0").to_string(),
680 param_groups: param_group_states,
681 state: state.clone(),
682 global_state: global_state.unwrap_or_default(),
683 };
684
685 optimizer_state
686 }
687
688 pub fn validate_state_compatibility(
690 current_groups: &[ParamGroup],
691 state_groups: &[ParamGroupState],
692 ) -> Result<()> {
693 if current_groups.len() != state_groups.len() {
694 return Err(TorshError::InvalidArgument(format!(
695 "Parameter group count mismatch: expected {}, got {}",
696 current_groups.len(),
697 state_groups.len()
698 )));
699 }
700
701 for (i, (current_group, state_group)) in
702 current_groups.iter().zip(state_groups.iter()).enumerate()
703 {
704 if current_group.params.len() != state_group.param_count {
705 return Err(TorshError::InvalidArgument(format!(
706 "Parameter count mismatch in group {}: expected {}, got {}",
707 i,
708 current_group.params.len(),
709 state_group.param_count
710 )));
711 }
712 }
713
714 Ok(())
715 }
716}
717
718#[cfg(test)]
721pub mod convergence_tests {
722 use super::*;
723 use parking_lot::RwLock;
724 use std::ops::Add;
725 use std::sync::Arc;
726 use torsh_tensor::{
727 creation::{randn, zeros},
728 Tensor,
729 };
730
731 pub fn test_quadratic_convergence<O: Optimizer>(
733 create_optimizer: impl Fn(Vec<Arc<RwLock<Tensor>>>) -> O,
734 tolerance: f32,
735 max_iterations: usize,
736 ) -> Result<()> {
737 let x = Arc::new(RwLock::new(Tensor::scalar(2.0)?));
739 let y = Arc::new(RwLock::new(Tensor::scalar(2.0)?));
740 let params = vec![x.clone(), y.clone()];
741
742 let mut optimizer = create_optimizer(params);
743
744 for i in 0..max_iterations {
745 {
747 let x_val = x.read().clone();
748 let y_val = y.read().clone();
749
750 let x_grad = x_val.mul_scalar(2.0)?;
751 let y_grad = y_val.mul_scalar(2.0)?;
752
753 x.write().set_grad(Some(x_grad));
754 y.write().set_grad(Some(y_grad));
755 }
756
757 optimizer
759 .step()
760 .map_err(|e| TorshError::Other(format!("Optimizer step failed: {}", e)))?;
761
762 let x_val = x.read().to_vec()?[0];
764 let y_val = y.read().to_vec()?[0];
765 let loss = x_val * x_val + y_val * y_val;
766
767 if loss < tolerance {
768 return Ok(());
769 }
770
771 optimizer.zero_grad();
773 }
774
775 Err(TorshError::Other(format!(
776 "Failed to converge within {} iterations",
777 max_iterations
778 )))
779 }
780
781 pub fn test_linear_regression_convergence<O: Optimizer>(
783 create_optimizer: impl Fn(Vec<Arc<RwLock<Tensor>>>) -> O,
784 tolerance: f32,
785 max_iterations: usize,
786 ) -> Result<()> {
787 let true_weight = 2.0;
789 let true_bias = 1.0;
790
791 let n_samples = 100;
793 let x_data = randn::<f32>(&[n_samples, 1])?;
794 let noise = randn::<f32>(&[n_samples, 1])?.mul_scalar(0.1)?;
795 let y_data = x_data
796 .mul_scalar(true_weight)?
797 .add_scalar(true_bias)?
798 .add(&noise)?;
799
800 let weight = Arc::new(RwLock::new(zeros(&[1, 1])?));
802 let bias = Arc::new(RwLock::new(zeros(&[1])?));
803 let params = vec![weight.clone(), bias.clone()];
804
805 let mut optimizer = create_optimizer(params);
806
807 for i in 0..max_iterations {
808 let w_val = weight.read().clone();
810 let b_val = bias.read().clone();
811
812 let y_pred = x_data.matmul(&w_val)?.add(&b_val)?;
813
814 let diff = y_pred.sub(&y_data)?;
816 let loss_tensor = diff.pow(2.0)?.mean(Some(&[0]), false)?;
817 let loss = loss_tensor.to_vec()?[0];
818
819 let grad_scale = 2.0 / n_samples as f32;
821 let weight_grad = x_data
822 .transpose(0, 1)?
823 .matmul(&diff)?
824 .mul_scalar(grad_scale)?;
825 let bias_grad = diff.sum()?.mul_scalar(grad_scale)?;
826
827 weight.write().set_grad(Some(weight_grad));
828 bias.write().set_grad(Some(bias_grad));
829
830 optimizer
832 .step()
833 .map_err(|e| TorshError::Other(format!("Optimizer step failed: {}", e)))?;
834
835 if loss < tolerance {
837 let learned_weight = weight.read().to_vec()?[0];
839 let learned_bias = bias.read().to_vec()?[0];
840
841 if (learned_weight - true_weight).abs() < 0.1
842 && (learned_bias - true_bias).abs() < 0.1
843 {
844 return Ok(());
845 }
846 }
847
848 optimizer.zero_grad();
850 }
851
852 Err(TorshError::Other(format!(
853 "Failed to converge within {} iterations",
854 max_iterations
855 )))
856 }
857
858 pub fn test_optimizer_consistency<O: Optimizer>(
860 create_optimizer: impl Fn(Vec<Arc<RwLock<Tensor>>>) -> O,
861 n_runs: usize,
862 tolerance: f32,
863 ) -> Result<()> {
864 let mut final_values = Vec::new();
865
866 for run in 0..n_runs {
867 let param = Arc::new(RwLock::new(Tensor::scalar(1.0)?));
868 let params = vec![param.clone()];
869 let mut optimizer = create_optimizer(params);
870
871 for _ in 0..10 {
873 {
874 let param_val = param.read().clone();
875 let grad = param_val.mul_scalar(2.0)?; param.write().set_grad(Some(grad));
877 }
878
879 optimizer
880 .step()
881 .map_err(|e| TorshError::Other(format!("Optimizer step failed: {}", e)))?;
882 optimizer.zero_grad();
883 }
884
885 final_values.push(param.read().to_vec()?[0]);
886 }
887
888 let mean_value = final_values.iter().sum::<f32>() / final_values.len() as f32;
890 for &value in &final_values {
891 if (value - mean_value).abs() > tolerance {
892 return Err(TorshError::Other(format!(
893 "Inconsistent optimizer behavior: values vary by more than {}",
894 tolerance
895 )));
896 }
897 }
898
899 Ok(())
900 }
901}
902
903pub mod prelude {
904 pub use crate::adabelief::AdaBelief;
905 pub use crate::adabound::AdaBound;
906 pub use crate::adadelta::AdaDelta;
907 pub use crate::adagrad::AdaGrad;
908 pub use crate::adahessian::{AdaHessian, AdaHessianBuilder};
909 pub use crate::adam::{Adam, AdamW};
910 pub use crate::adamax::AdaMax;
911 pub use crate::asgd::ASGD;
912 pub use crate::checkpointing::{
913 Checkpoint, CheckpointConfig, CheckpointManager, CheckpointMetadata, CheckpointStatistics,
914 CheckpointSupport, CheckpointingOptimizer,
915 };
916 pub use crate::composition::{
917 CombinationMethod, ComposedOptimizer, CompositionBuilder, CompositionStrategy,
918 OptimizerMetrics, SwitchCriterion, VotingMethod,
919 };
920 pub use crate::debugging::{
921 AnalysisReport, AnalyzerConfig, ConvergenceTracker, GradientFlowPoint, GradientStatistics,
922 HyperparameterSensitivity, OptimizationRecommendation, OptimizationStep, OptimizerAnalyzer,
923 ParameterStatistics, RecommendationCategory, SensitivityReport, SensitivityResult,
924 Severity,
925 };
926 pub use crate::distributed::{
927 utils as distributed_utils, AsyncConfig, AsyncSGD, CommunicationStats, DistributedBackend,
928 DistributedConfig, DistributedOptimizer, ElasticAveragingSGD, SyncStrategy,
929 };
930 pub use crate::ftrl::{FTRLBuilder, FTRL};
931 pub use crate::fused_kernels::{
932 fused_adadelta_step, fused_adagrad_step, fused_adam_step, fused_rmsprop_step,
933 fused_sgd_step, FusedKernelSupport, FusedStats,
934 };
935 pub use crate::grad_accumulation::{
936 with_gradient_accumulation, AccumulatingOptimizer, GradientAccumulationSupport,
937 GradientAccumulator,
938 };
939 pub use crate::kfac::{KFACBuilder, KFAC};
940 pub use crate::lamb::LAMB;
941 pub use crate::lazy_updates::{
942 LazyUpdateConfig, LazyUpdateDecision, LazyUpdateManager, LazyUpdateOptimizer,
943 LazyUpdateStatistics, LazyUpdateSupport, ParameterImportance, PendingUpdate,
944 UpdatePriority,
945 };
946 pub use crate::lbfgs::LBFGS;
947 pub use crate::lion::{Lion, LionBuilder, LionConfig};
948 pub use crate::lookahead::{lookahead_adam, lookahead_radam, lookahead_sgd, Lookahead};
949 pub use crate::low_precision::{
950 LowPrecisionConvertible, LowPrecisionOptimizer, LowPrecisionState, PrecisionType,
951 StateStatistics,
952 };
953 pub use crate::lr_scheduler::{
954 CosineAnnealingLR, ExponentialLR, LRScheduler, OneCycleLR, ReduceLROnPlateau, StepLR,
955 };
956 pub use crate::lr_scheduler_additional::{
957 ConstantLR, CosineAnnealingWarmRestarts, CyclicLR, LinearLR, MultiStepLR, PolynomialLR,
958 };
959 pub use crate::lr_scheduler_enhanced::{
960 utils as lr_enhanced_utils, AdaptiveLRScheduler, AdaptiveSchedulerStats, AdaptiveStrategy,
961 CosineAnnealingWarmRestartsWithWarmup, PolynomialDecayWithWarmup, WarmupStrategy,
962 };
963 pub use crate::memory_efficient::{
964 CircularBuffer, MemoryConfig, MemoryEfficientAdam, MemoryEfficientLBFGS,
965 MemoryEfficientOptimizerBuilder, MemoryPool,
966 };
967 pub use crate::memory_mapped::{
968 MemoryMappedConfig, MemoryMappedFile, MemoryMappedOptimizer, MemoryMappedStateStorage,
969 MemoryMappedSupport, StorageStatistics,
970 };
971 pub use crate::mixed_precision::{
972 with_mixed_precision, MixedPrecisionConfig, MixedPrecisionOptimizer,
973 };
974 pub use crate::nadam::NAdam;
975 pub use crate::natural_gradient::{NaturalGradient, NaturalGradientBuilder};
976 pub use crate::newton_cg::{NewtonCG, NewtonCGBuilder, NewtonCGConfig};
977 pub use crate::online_learning::{
978 OnlineGradientDescent, ProximalGradient, ProximalOperator, SAGA, SVRG,
979 };
980 pub use crate::prodigy::{Prodigy, ProdigyBuilder, ProdigyConfig};
981 pub use crate::radam::RAdam;
982 pub use crate::ranger::{Ranger, RangerBuilder};
983 pub use crate::rmsprop::RMSprop;
984 pub use crate::rprop::Rprop;
985 pub use crate::schedule_free::{ScheduleFreeAdamW, ScheduleFreeAdamWBuilder};
986 pub use crate::sgd::SGD;
987 pub use crate::shampoo::{Shampoo, ShampooBuilder};
988 pub use crate::sophia::{Sophia, SophiaBuilder, SophiaConfig};
989 pub use crate::sparse_adam::SparseAdam;
990 pub use crate::state_dict_ops::{
991 CompressionMethod, CompressionStats, MemoryEstimate, SerializationFormat, StateDictConfig,
992 StateDictManager,
993 };
994 pub use crate::trust_region::{
995 SubproblemSolver, TrustRegionBuilder, TrustRegionConfig, TrustRegionMethod,
996 TrustRegionStrategy,
997 };
998 pub use crate::yellowfin::{YellowFin, YellowFinBuilder, YellowFinConfig};
999 pub use crate::{Optimizer, OptimizerOptions, OptimizerState, ParamGroup, ParamGroupBuilder};
1000 pub use crate::{OptimizerError, OptimizerResult};
1001}
1002
1003pub use adam::{Adam, AdamW};
1005pub use distributed::{DistributedBackend, DistributedConfig, DistributedOptimizer, SyncStrategy};
1006pub use rmsprop::RMSprop;
1007pub use sgd::SGD;
1008
1009#[cfg(test)]
1010mod tests {
1011 use super::*;
1012
1013 #[test]
1014 fn test_param_group() {
1015 let params = vec![];
1016 let group = ParamGroup::new(params, 0.01);
1017 assert_eq!(group.lr, 0.01);
1018 }
1019}