use std::collections::HashMap;
use crate::Optimizer;
use crate::common::{zeros_entry, zip3_for_each};
#[derive(Debug, Clone)]
pub struct Lion {
pub lr: f32,
pub beta1: f32,
pub beta2: f32,
pub weight_decay: f32,
m: HashMap<String, Vec<f32>>,
}
impl Lion {
pub fn new(lr: f32) -> Self {
Self {
lr,
beta1: 0.9,
beta2: 0.99,
weight_decay: 0.0,
m: HashMap::new(),
}
}
pub fn with_betas(mut self, b1: f32, b2: f32) -> Self {
self.beta1 = b1;
self.beta2 = b2;
self
}
pub fn with_weight_decay(mut self, wd: f32) -> Self {
self.weight_decay = wd;
self
}
}
impl Optimizer for Lion {
fn set_lr(&mut self, lr: f32) {
self.lr = lr;
}
fn step(&mut self, name: &str, _shape: &[usize], param: &mut [f32], grad: &[f32]) {
debug_assert_eq!(param.len(), grad.len());
let b1 = self.beta1;
let b2 = self.beta2;
let lr = self.lr;
let wd = self.weight_decay;
let m = zeros_entry(&mut self.m, name, param.len());
zip3_for_each(param, m, grad, |p, mi, gi| {
let c = b1 * *mi + (1.0 - b1) * gi;
let sign = if c > 0.0 {
1.0
} else if c < 0.0 {
-1.0
} else {
0.0
};
*p -= lr * (sign + wd * *p);
*mi = b2 * *mi + (1.0 - b2) * gi;
});
}
}