optirs_core/second_order/kfac/
config.rs1use scirs2_core::numeric::Float;
7use std::fmt::Debug;
8
9#[derive(Debug, Clone)]
11pub struct KFACConfig<T: Float + Debug + Send + Sync + 'static> {
12 pub learning_rate: T,
14
15 pub damping: T,
17
18 pub weight_decay: T,
20
21 pub cov_update_freq: usize,
23
24 pub inv_update_freq: usize,
26
27 pub stat_decay: T,
29
30 pub min_eigenvalue: T,
32
33 pub max_inv_iterations: usize,
35
36 pub inv_tolerance: T,
38
39 pub use_tikhonov: bool,
41
42 pub auto_damping: bool,
44
45 pub target_acceptance_ratio: T,
47}
48
49impl<T: Float + Debug + Send + Sync + 'static> Default for KFACConfig<T> {
50 fn default() -> Self {
51 Self {
52 learning_rate: T::from(0.001).unwrap_or_else(|| T::zero()),
53 damping: T::from(0.001).unwrap_or_else(|| T::zero()),
54 weight_decay: T::from(0.0).unwrap_or_else(|| T::zero()),
55 cov_update_freq: 10,
56 inv_update_freq: 100,
57 stat_decay: T::from(0.95).unwrap_or_else(|| T::zero()),
58 min_eigenvalue: T::from(1e-7).unwrap_or_else(|| T::zero()),
59 max_inv_iterations: 50,
60 inv_tolerance: T::from(1e-6).unwrap_or_else(|| T::zero()),
61 use_tikhonov: true,
62 auto_damping: true,
63 target_acceptance_ratio: T::from(0.75).unwrap_or_else(|| T::zero()),
64 }
65 }
66}
67
68#[derive(Debug, Clone)]
70pub struct LayerInfo {
71 pub name: String,
73
74 pub input_dim: usize,
76
77 pub output_dim: usize,
79
80 pub layer_type: LayerType,
82
83 pub has_bias: bool,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq)]
89pub enum LayerType {
90 Dense,
92
93 Convolution,
95
96 GroupedConvolution { groups: usize },
98
99 Embedding,
101
102 BatchNorm,
104}
105
106#[derive(Debug, Clone, Default)]
108pub struct KFACStats<T: Float + Debug + Send + Sync + 'static> {
109 pub total_steps: usize,
111
112 pub cov_updates: usize,
114
115 pub inv_updates: usize,
117
118 pub avg_condition_number: T,
120
121 pub time_cov_update: u64,
123 pub time_inv_update: u64,
124 pub time_gradient_update: u64,
125
126 pub memory_usage: usize,
128}
129
130impl<T: Float + Debug + Send + Sync + 'static> KFACConfig<T> {
131 pub fn for_large_model() -> Self {
133 Self {
134 cov_update_freq: 20,
135 inv_update_freq: 200,
136 stat_decay: T::from(0.99).unwrap_or_else(|| T::zero()),
137 damping: T::from(0.01).unwrap_or_else(|| T::zero()),
138 ..Default::default()
139 }
140 }
141
142 pub fn for_small_model() -> Self {
144 Self {
145 cov_update_freq: 5,
146 inv_update_freq: 50,
147 stat_decay: T::from(0.9).unwrap_or_else(|| T::zero()),
148 damping: T::from(0.001).unwrap_or_else(|| T::zero()),
149 ..Default::default()
150 }
151 }
152
153 pub fn for_stability() -> Self {
155 Self {
156 damping: T::from(0.1).unwrap_or_else(|| T::zero()),
157 min_eigenvalue: T::from(1e-5).unwrap_or_else(|| T::zero()),
158 auto_damping: false,
159 use_tikhonov: true,
160 ..Default::default()
161 }
162 }
163
164 pub fn validate(&self) -> Result<(), String> {
166 if self.learning_rate <= T::zero() {
167 return Err("Learning rate must be positive".to_string());
168 }
169 if self.damping < T::zero() {
170 return Err("Damping must be non-negative".to_string());
171 }
172 if self.weight_decay < T::zero() {
173 return Err("Weight decay must be non-negative".to_string());
174 }
175 if self.cov_update_freq == 0 {
176 return Err("Covariance update frequency must be positive".to_string());
177 }
178 if self.inv_update_freq == 0 {
179 return Err("Inverse update frequency must be positive".to_string());
180 }
181 if self.stat_decay < T::zero() || self.stat_decay > T::one() {
182 return Err("Statistics decay must be between 0 and 1".to_string());
183 }
184 if self.min_eigenvalue <= T::zero() {
185 return Err("Minimum eigenvalue must be positive".to_string());
186 }
187 if self.inv_tolerance <= T::zero() {
188 return Err("Inverse tolerance must be positive".to_string());
189 }
190 if self.target_acceptance_ratio <= T::zero() || self.target_acceptance_ratio >= T::one() {
191 return Err("Target acceptance ratio must be between 0 and 1".to_string());
192 }
193 Ok(())
194 }
195}
196
197impl LayerInfo {
198 pub fn dense(name: String, input_dim: usize, output_dim: usize, has_bias: bool) -> Self {
200 Self {
201 name,
202 input_dim,
203 output_dim,
204 layer_type: LayerType::Dense,
205 has_bias,
206 }
207 }
208
209 pub fn convolution(name: String, input_dim: usize, output_dim: usize, has_bias: bool) -> Self {
211 Self {
212 name,
213 input_dim,
214 output_dim,
215 layer_type: LayerType::Convolution,
216 has_bias,
217 }
218 }
219
220 pub fn input_cov_size(&self) -> usize {
222 match self.layer_type {
223 LayerType::Dense => {
224 if self.has_bias {
225 self.input_dim + 1
226 } else {
227 self.input_dim
228 }
229 }
230 LayerType::Convolution => {
231 self.input_dim
234 }
235 LayerType::GroupedConvolution { .. } => self.input_dim,
236 LayerType::Embedding => self.input_dim,
237 LayerType::BatchNorm => self.input_dim,
238 }
239 }
240
241 pub fn output_cov_size(&self) -> usize {
243 self.output_dim
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_config_default() {
253 let config = KFACConfig::<f32>::default();
254 assert!(config.learning_rate > 0.0);
255 assert!(config.damping >= 0.0);
256 assert!(config.cov_update_freq > 0);
257 assert!(config.inv_update_freq > 0);
258 assert!(config.validate().is_ok());
259 }
260
261 #[test]
262 fn test_config_presets() {
263 let large_config = KFACConfig::<f64>::for_large_model();
264 assert!(large_config.validate().is_ok());
265 assert_eq!(large_config.cov_update_freq, 20);
266
267 let small_config = KFACConfig::<f64>::for_small_model();
268 assert!(small_config.validate().is_ok());
269 assert_eq!(small_config.cov_update_freq, 5);
270
271 let stable_config = KFACConfig::<f64>::for_stability();
272 assert!(stable_config.validate().is_ok());
273 assert!(!stable_config.auto_damping);
274 }
275
276 #[test]
277 fn test_layer_info_creation() {
278 let dense_layer = LayerInfo::dense("layer1".to_string(), 128, 64, true);
279 assert_eq!(dense_layer.layer_type, LayerType::Dense);
280 assert_eq!(dense_layer.input_cov_size(), 129); let conv_layer = LayerInfo::convolution("conv1".to_string(), 64, 32, false);
283 assert_eq!(conv_layer.layer_type, LayerType::Convolution);
284 assert_eq!(conv_layer.input_cov_size(), 64);
285 }
286
287 #[test]
288 fn test_config_validation() {
289 let mut config = KFACConfig::<f32> {
290 learning_rate: -0.1,
291 ..Default::default()
292 };
293
294 assert!(config.validate().is_err());
295
296 config.learning_rate = 0.001;
297 config.damping = -0.1;
298 assert!(config.validate().is_err());
299
300 config.damping = 0.001;
301 config.stat_decay = 1.5;
302 assert!(config.validate().is_err());
303
304 config.stat_decay = 0.95;
305 assert!(config.validate().is_ok());
306 }
307}