1use burn::{
2 optim::SimpleOptimizer, prelude::Backend, record::Record, tensor::Tensor, optim::LearningRate,
3};
4
5pub trait SimpleHessianOptimizer<B>: Send + Sync + Clone + SimpleOptimizer<B>
7where
8 B: Backend,
9{
10 type StateWithHessian<const D: usize, const H: usize>: Record<B>
12 + Clone
13 + From<Self::State<D>>
14 + Into<Self::State<D>>
15 + 'static;
16
17 fn step_with_hessian<const D: usize, const H: usize>(
22 &self,
23 lr: LearningRate,
24 tensor: Tensor<B, D>,
25 grad: Tensor<B, D>,
26 hessian: Tensor<B, H>,
27 state: Option<Self::StateWithHessian<D, H>>,
28 ) -> (Tensor<B, D>, Option<Self::StateWithHessian<D, H>>);
29
30 fn step<const D: usize, const H: usize>(
35 &self,
36 lr: LearningRate,
37 tensor: Tensor<B, D>,
38 grad: Tensor<B, D>,
39 hessian: Option<Tensor<B, H>>,
40 state: Option<Self::StateWithHessian<D, H>>,
41 ) -> (Tensor<B, D>, Option<Self::StateWithHessian<D, H>>) {
42 if let Some(hessian) = hessian {
43 self.step_with_hessian(lr, tensor, grad, hessian, state)
44 } else {
45 let (new_pt, new_state) =
46 SimpleOptimizer::step(self, lr, tensor, grad, state.map(Into::into));
47 (new_pt, new_state.map(Into::into))
48 }
49 }
50
51 fn to_device<const D: usize, const H: usize>(
56 state: Self::StateWithHessian<D, H>,
57 device: &B::Device,
58 ) -> Self::StateWithHessian<D, H>;
59}
60
61impl<B: Backend, T: SimpleOptimizer<B>> SimpleHessianOptimizer<B> for T {
63 type StateWithHessian<const D: usize, const H: usize> = <T as SimpleOptimizer<B>>::State<D>;
64
65 fn step_with_hessian<const D: usize, const H: usize>(
66 &self,
67 lr: LearningRate,
68 tensor: Tensor<B, D>,
69 grad: Tensor<B, D>,
70 _hessian: Tensor<B, H>,
71 state: Option<Self::StateWithHessian<D, H>>,
72 ) -> (Tensor<B, D>, Option<Self::StateWithHessian<D, H>>) {
73 self.step(lr, tensor, grad, state)
74 }
75
76 fn to_device<const D: usize, const H: usize>(
77 state: Self::StateWithHessian<D, H>,
78 device: &<B as Backend>::Device,
79 ) -> Self::StateWithHessian<D, H> {
80 <T as SimpleOptimizer<B>>::to_device(state, device)
81 }
82}
83
84pub trait LessSimpleHessianOptimizer<B: Backend>: SimpleHessianOptimizer<B> {
89 fn many_steps<const D: usize, const H: usize>(
90 &self,
91 lr_function: impl FnMut(usize) -> LearningRate,
92 num_steps: usize,
93 grad_function: impl FnMut(Tensor<B, D>) -> Tensor<B, D>,
94 hessian_function: impl FnMut(Tensor<B, D>) -> Option<Tensor<B, H>>,
95 tensor: Tensor<B, D>,
96 state: Option<Self::StateWithHessian<D, H>>,
97 ) -> (Tensor<B, D>, Option<Self::StateWithHessian<D, H>>);
98}
99
100impl<B: Backend, T: SimpleHessianOptimizer<B>> LessSimpleHessianOptimizer<B> for T {
105 #[inline]
106 fn many_steps<const D: usize, const H: usize>(
107 &self,
108 mut lr_function: impl FnMut(usize) -> LearningRate,
109 num_steps: usize,
110 mut grad_function: impl FnMut(Tensor<B, D>) -> Tensor<B, D>,
111 mut hessian_function: impl FnMut(Tensor<B, D>) -> Option<Tensor<B, H>>,
112 mut tensor: Tensor<B, D>,
113 mut state: Option<Self::StateWithHessian<D, H>>,
114 ) -> (Tensor<B, D>, Option<Self::StateWithHessian<D, H>>) {
115 for step in 0..num_steps {
117 let cur_grad = grad_function(tensor.clone());
119 let cur_hessian = hessian_function(tensor.clone());
121 let cur_lr = lr_function(step);
123 let (new_x, new_state) = SimpleHessianOptimizer::step(
125 self,
126 cur_lr,
127 tensor.clone(),
128 cur_grad,
129 cur_hessian,
130 state,
131 );
132 tensor = new_x.detach().require_grad();
133 state = new_state;
134 }
135 (tensor, state)
136 }
137}