1#![allow(dead_code)]
18
19use anyhow::{anyhow, Result};
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use trustformers_core::tensor::Tensor;
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct EWCConfig {
27 pub learning_rate: f32,
29 pub lambda: f32,
31 pub fisher_method: FisherMethod,
33 pub fisher_samples: usize,
35 pub online: bool,
37 pub decay_factor: f32,
39}
40
41impl Default for EWCConfig {
42 fn default() -> Self {
43 Self {
44 learning_rate: 1e-3,
45 lambda: 1000.0,
46 fisher_method: FisherMethod::Empirical,
47 fisher_samples: 1000,
48 online: false,
49 decay_factor: 0.9,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub enum FisherMethod {
57 Empirical,
59 True,
61 Diagonal,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct PackNetConfig {
68 pub learning_rate: f32,
70 pub sparsity_level: f32,
72 pub num_tasks: usize,
74 pub allocation_strategy: AllocationStrategy,
76}
77
78impl Default for PackNetConfig {
79 fn default() -> Self {
80 Self {
81 learning_rate: 1e-3,
82 sparsity_level: 0.5,
83 num_tasks: 10,
84 allocation_strategy: AllocationStrategy::Sequential,
85 }
86 }
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub enum AllocationStrategy {
92 Sequential,
94 Random,
96 ImportanceBased,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct L2RegularizationConfig {
103 pub learning_rate: f32,
105 pub reg_strength: f32,
107 pub update_strategy: UpdateStrategy,
109}
110
111impl Default for L2RegularizationConfig {
112 fn default() -> Self {
113 Self {
114 learning_rate: 1e-3,
115 reg_strength: 0.1,
116 update_strategy: UpdateStrategy::EMA,
117 }
118 }
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123pub enum UpdateStrategy {
124 Fixed,
126 EMA,
128 TaskBoundary,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct MemoryReplayConfig {
135 pub learning_rate: f32,
137 pub memory_size: usize,
139 pub replay_frequency: usize,
141 pub replay_batch_size: usize,
143 pub selection_strategy: MemorySelectionStrategy,
145}
146
147impl Default for MemoryReplayConfig {
148 fn default() -> Self {
149 Self {
150 learning_rate: 1e-3,
151 memory_size: 1000,
152 replay_frequency: 10,
153 replay_batch_size: 32,
154 selection_strategy: MemorySelectionStrategy::Random,
155 }
156 }
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub enum MemorySelectionStrategy {
162 Random,
164 GradientBased,
166 UncertaintyBased,
168}
169
170pub struct EWC {
172 config: EWCConfig,
173 parameters: Vec<Tensor>,
174 importance_weights: Vec<Tensor>,
175 anchor_parameters: Vec<Tensor>,
176 current_task: usize,
177 accumulated_importance: Vec<Tensor>,
178}
179
180impl EWC {
181 pub fn new(config: EWCConfig, initial_parameters: Vec<Tensor>) -> Result<Self> {
183 let param_count = initial_parameters.len();
184
185 let importance_weights: Result<Vec<Tensor>> = (0..param_count)
186 .map(|i| {
187 Tensor::zeros(&initial_parameters[i].shape())
188 .map_err(|e| anyhow::anyhow!("{:?}", e))
189 })
190 .collect();
191
192 let accumulated_importance: Result<Vec<Tensor>> = (0..param_count)
193 .map(|i| {
194 Tensor::zeros(&initial_parameters[i].shape())
195 .map_err(|e| anyhow::anyhow!("{:?}", e))
196 })
197 .collect();
198
199 Ok(Self {
200 config,
201 parameters: initial_parameters.clone(),
202 importance_weights: importance_weights?,
203 anchor_parameters: initial_parameters.clone(),
204 current_task: 0,
205 accumulated_importance: accumulated_importance?,
206 })
207 }
208
209 pub fn compute_fisher_information(&mut self, gradients_samples: &[Vec<Tensor>]) -> Result<()> {
211 let num_samples = gradients_samples.len();
212 if num_samples == 0 {
213 return Err(anyhow!("No gradient samples provided"));
214 }
215
216 for importance in self.importance_weights.iter_mut() {
218 *importance = Tensor::zeros(&importance.shape())?;
219 }
220
221 for gradient_sample in gradients_samples {
223 for (i, gradient) in gradient_sample.iter().enumerate() {
224 if i < self.importance_weights.len() {
225 let squared_grad = gradient.mul(gradient)?;
226 self.importance_weights[i] = self.importance_weights[i].add(&squared_grad)?;
227 }
228 }
229 }
230
231 for importance in self.importance_weights.iter_mut() {
233 *importance = importance.div_scalar(num_samples as f32)?;
234 }
235
236 if self.config.online {
238 for i in 0..self.accumulated_importance.len() {
239 let decayed =
240 self.accumulated_importance[i].mul_scalar(self.config.decay_factor)?;
241 self.accumulated_importance[i] = decayed.add(&self.importance_weights[i])?;
242 }
243 }
244
245 Ok(())
246 }
247
248 pub fn finish_task(&mut self) -> Result<()> {
250 self.anchor_parameters = self.parameters.clone();
252 self.current_task += 1;
253 Ok(())
254 }
255
256 pub fn step(&mut self, gradients: &[Tensor]) -> Result<()> {
258 for (i, gradient) in gradients.iter().enumerate() {
259 if i < self.parameters.len() {
260 let param_diff = self.parameters[i].sub(&self.anchor_parameters[i])?;
262 let importance = if self.config.online {
263 &self.accumulated_importance[i]
264 } else {
265 &self.importance_weights[i]
266 };
267 let ewc_grad = param_diff.mul(importance)?.mul_scalar(self.config.lambda)?;
268
269 let total_grad = gradient.add(&ewc_grad)?;
271
272 let update = total_grad.mul_scalar(self.config.learning_rate)?;
274 self.parameters[i] = self.parameters[i].sub(&update)?;
275 }
276 }
277 Ok(())
278 }
279
280 pub fn get_parameters(&self) -> &[Tensor] {
282 &self.parameters
283 }
284
285 pub fn get_importance_weights(&self) -> &[Tensor] {
287 &self.importance_weights
288 }
289}
290
291pub struct PackNet {
293 config: PackNetConfig,
294 parameters: Vec<Tensor>,
295 parameter_masks: Vec<Tensor>,
296 task_allocations: HashMap<usize, Vec<Tensor>>,
297 current_task: usize,
298 available_capacity: Vec<f32>,
299}
300
301impl PackNet {
302 pub fn new(config: PackNetConfig, initial_parameters: Vec<Tensor>) -> Result<Self> {
304 let param_count = initial_parameters.len();
305
306 let parameter_masks: Result<Vec<Tensor>> = (0..param_count)
307 .map(|i| {
308 Tensor::ones(&initial_parameters[i].shape()).map_err(|e| anyhow::anyhow!("{:?}", e))
309 })
310 .collect();
311
312 Ok(Self {
313 config,
314 parameters: initial_parameters.clone(),
315 parameter_masks: parameter_masks?,
316 task_allocations: HashMap::new(),
317 current_task: 0,
318 available_capacity: vec![1.0; param_count],
319 })
320 }
321
322 pub fn allocate_task(&mut self, task_id: usize) -> Result<()> {
324 if self.available_capacity.iter().any(|&cap| cap < self.config.sparsity_level) {
325 return Err(anyhow!("Insufficient parameter capacity for new task"));
326 }
327
328 let mut task_masks = Vec::new();
329
330 for (i, param) in self.parameters.iter().enumerate() {
331 let shape = param.shape();
332 let total_params = shape.iter().product::<usize>();
333 let allocated_params = (total_params as f32 * self.config.sparsity_level) as usize;
334
335 let mut mask_data = vec![0.0; total_params];
337
338 match self.config.allocation_strategy {
339 AllocationStrategy::Sequential => {
340 let start_idx =
341 ((1.0 - self.available_capacity[i]) * total_params as f32) as usize;
342 let end_idx = (start_idx + allocated_params).min(total_params);
343 for idx in start_idx..end_idx {
344 mask_data[idx] = 1.0;
345 }
346 },
347 AllocationStrategy::Random => {
348 use scirs2_core::random::*; let mut indices: Vec<usize> = (0..total_params).collect();
350 let mut rng = thread_rng();
351 indices.shuffle(rng.rng_mut());
352 for &idx in indices.iter().take(allocated_params) {
353 mask_data[idx] = 1.0;
354 }
355 },
356 AllocationStrategy::ImportanceBased => {
357 for idx in 0..allocated_params.min(total_params) {
360 mask_data[idx] = 1.0;
361 }
362 },
363 }
364
365 let task_mask = Tensor::new(mask_data)?;
366 task_masks.push(task_mask);
367
368 self.available_capacity[i] -= self.config.sparsity_level;
370 }
371
372 self.task_allocations.insert(task_id, task_masks);
373 self.current_task = task_id;
374 Ok(())
375 }
376
377 pub fn step(&mut self, gradients: &[Tensor]) -> Result<()> {
379 let task_masks = self
380 .task_allocations
381 .get(&self.current_task)
382 .ok_or_else(|| anyhow!("No allocation for current task"))?;
383
384 for (i, gradient) in gradients.iter().enumerate() {
385 if i < self.parameters.len() && i < task_masks.len() {
386 let masked_grad = gradient.mul(&task_masks[i])?;
388
389 let update = masked_grad.mul_scalar(self.config.learning_rate)?;
391 self.parameters[i] = self.parameters[i].sub(&update)?;
392 }
393 }
394 Ok(())
395 }
396
397 pub fn get_parameters(&self) -> &[Tensor] {
399 &self.parameters
400 }
401
402 pub fn get_available_capacity(&self) -> &[f32] {
404 &self.available_capacity
405 }
406}
407
408pub struct L2Regularization {
410 config: L2RegularizationConfig,
411 parameters: Vec<Tensor>,
412 anchor_parameters: Vec<Tensor>,
413 ema_decay: f32,
414}
415
416impl L2Regularization {
417 pub fn new(config: L2RegularizationConfig, initial_parameters: Vec<Tensor>) -> Self {
419 Self {
420 config,
421 parameters: initial_parameters.clone(),
422 anchor_parameters: initial_parameters,
423 ema_decay: 0.999,
424 }
425 }
426
427 pub fn step(&mut self, gradients: &[Tensor]) -> Result<()> {
429 for (i, gradient) in gradients.iter().enumerate() {
430 if i < self.parameters.len() {
431 let param_diff = self.parameters[i].sub(&self.anchor_parameters[i])?;
433 let reg_grad = param_diff.mul_scalar(self.config.reg_strength)?;
434
435 let total_grad = gradient.add(®_grad)?;
437
438 let update = total_grad.mul_scalar(self.config.learning_rate)?;
440 self.parameters[i] = self.parameters[i].sub(&update)?;
441
442 match self.config.update_strategy {
444 UpdateStrategy::Fixed => {
445 },
447 UpdateStrategy::EMA => {
448 let anchor_update = self.parameters[i].mul_scalar(1.0 - self.ema_decay)?;
450 let anchor_keep = self.anchor_parameters[i].mul_scalar(self.ema_decay)?;
451 self.anchor_parameters[i] = anchor_update.add(&anchor_keep)?;
452 },
453 UpdateStrategy::TaskBoundary => {
454 },
456 }
457 }
458 }
459 Ok(())
460 }
461
462 pub fn finish_task(&mut self) -> Result<()> {
464 if matches!(self.config.update_strategy, UpdateStrategy::TaskBoundary) {
465 self.anchor_parameters = self.parameters.clone();
466 }
467 Ok(())
468 }
469
470 pub fn get_parameters(&self) -> &[Tensor] {
472 &self.parameters
473 }
474}
475
476pub struct MemoryReplay {
478 config: MemoryReplayConfig,
479 parameters: Vec<Tensor>,
480 memory_buffer: Vec<Vec<Tensor>>, step_count: usize,
482}
483
484impl MemoryReplay {
485 pub fn new(config: MemoryReplayConfig, initial_parameters: Vec<Tensor>) -> Self {
487 Self {
488 config,
489 parameters: initial_parameters,
490 memory_buffer: Vec::new(),
491 step_count: 0,
492 }
493 }
494
495 pub fn store_gradient(&mut self, gradients: &[Tensor]) -> Result<()> {
497 if self.memory_buffer.len() >= self.config.memory_size {
498 match self.config.selection_strategy {
500 MemorySelectionStrategy::Random => {
501 use scirs2_core::random::*; let idx = thread_rng().random_range(0..self.memory_buffer.len());
503 self.memory_buffer.remove(idx);
504 },
505 _ => {
506 self.memory_buffer.remove(0); },
508 }
509 }
510
511 self.memory_buffer.push(gradients.to_vec());
512 Ok(())
513 }
514
515 pub fn step(&mut self, gradients: &[Tensor]) -> Result<()> {
517 for (i, gradient) in gradients.iter().enumerate() {
519 if i < self.parameters.len() {
520 let update = gradient.mul_scalar(self.config.learning_rate)?;
521 self.parameters[i] = self.parameters[i].sub(&update)?;
522 }
523 }
524
525 self.store_gradient(gradients)?;
527
528 if self.step_count.is_multiple_of(self.config.replay_frequency)
530 && !self.memory_buffer.is_empty()
531 {
532 self.replay_step()?;
533 }
534
535 self.step_count += 1;
536 Ok(())
537 }
538
539 fn replay_step(&mut self) -> Result<()> {
540 let batch_size = self.config.replay_batch_size.min(self.memory_buffer.len());
541
542 use scirs2_core::random::*; let mut indices: Vec<usize> = (0..self.memory_buffer.len()).collect();
545 let mut rng = thread_rng();
546 indices.shuffle(rng.rng_mut());
547
548 for &idx in indices.iter().take(batch_size) {
549 let replay_gradients = &self.memory_buffer[idx];
550
551 let replay_lr = self.config.learning_rate * 0.5;
553 for (i, gradient) in replay_gradients.iter().enumerate() {
554 if i < self.parameters.len() {
555 let update = gradient.mul_scalar(replay_lr)?;
556 self.parameters[i] = self.parameters[i].sub(&update)?;
557 }
558 }
559 }
560
561 Ok(())
562 }
563
564 pub fn get_parameters(&self) -> &[Tensor] {
566 &self.parameters
567 }
568
569 pub fn memory_size(&self) -> usize {
571 self.memory_buffer.len()
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578
579 #[test]
580 fn test_ewc_config() {
581 let config = EWCConfig::default();
582 assert_eq!(config.learning_rate, 1e-3);
583 assert_eq!(config.lambda, 1000.0);
584 assert!(!config.online);
585 }
586
587 #[test]
588 fn test_packnet_config() {
589 let config = PackNetConfig::default();
590 assert_eq!(config.sparsity_level, 0.5);
591 assert_eq!(config.num_tasks, 10);
592 }
593
594 #[test]
595 fn test_l2_regularization_config() {
596 let config = L2RegularizationConfig::default();
597 assert_eq!(config.reg_strength, 0.1);
598 assert!(matches!(config.update_strategy, UpdateStrategy::EMA));
599 }
600
601 #[test]
602 fn test_memory_replay_config() {
603 let config = MemoryReplayConfig::default();
604 assert_eq!(config.memory_size, 1000);
605 assert_eq!(config.replay_frequency, 10);
606 assert!(matches!(
607 config.selection_strategy,
608 MemorySelectionStrategy::Random
609 ));
610 }
611
612 #[test]
613 fn test_fisher_methods() {
614 assert!(matches!(FisherMethod::Empirical, FisherMethod::Empirical));
615 assert!(matches!(FisherMethod::True, FisherMethod::True));
616 assert!(matches!(FisherMethod::Diagonal, FisherMethod::Diagonal));
617 }
618}