|
1 | | -# TODO: We want to define directly on `single_train_step!` to compile the update function |
2 | | -# as well. |
3 | 1 | function Lux.Training.compute_gradients_impl( |
4 | 2 | backend::ReactantBackend, objective_function::F, |
5 | 3 | data, ts::Training.TrainState) where {F} |
@@ -36,3 +34,60 @@ function compute_gradients_internal( |
36 | 34 | Duplicated(ps, dps), Const(st), Const(data)) |
37 | 35 | return dps, loss, stats, stₙ |
38 | 36 | end |
| 37 | + |
| 38 | +for inplace in ("!", "") |
| 39 | + fname = Symbol(:single_train_step_impl, inplace) |
| 40 | + internal_fn = Symbol(:compute_gradients_internal_and_step, inplace) |
| 41 | + |
| 42 | + @eval function Lux.Training.$(fname)(backend::ReactantBackend, objective_function::F, |
| 43 | + data, ts::Training.TrainState) where {F} |
| 44 | + dps = Lux.recursive_make_zero(ts.parameters) |
| 45 | + |
| 46 | + compiled_grad_and_step_function = @compile $(internal_fn)( |
| 47 | + objective_function, ts.model, data, ts.parameters, dps, ts.states, |
| 48 | + ts.optimizer_state) |
| 49 | + |
| 50 | + grads, ps, loss, stats, st, opt_state = compiled_grad_and_step_function( |
| 51 | + objective_function, ts.model, data, ts.parameters, dps, ts.states, |
| 52 | + ts.optimizer_state) |
| 53 | + |
| 54 | + cache = TrainingBackendCache( |
| 55 | + backend, False(), dps, (; compiled_grad_and_step_function)) |
| 56 | + @set! ts.cache = cache |
| 57 | + @set! ts.objective_function = objective_function |
| 58 | + @set! ts.states = st |
| 59 | + @set! ts.parameters = ps |
| 60 | + @set! ts.optimizer_state = opt_state |
| 61 | + @set! ts.step = ts.step + 1 |
| 62 | + |
| 63 | + return grads, loss, stats, ts |
| 64 | + end |
| 65 | + |
| 66 | + @eval function Lux.Training.$(fname)(::ReactantBackend, obj_fn::F, data, |
| 67 | + ts::Training.TrainState{<:TrainingBackendCache{ReactantBackend}, F}) where {F} |
| 68 | + dps = Lux.recursive_make_zero!!(ts.cache.dparameters) |
| 69 | + |
| 70 | + grads, ps, loss, stats, st, opt_state = ts.cache.extras.compiled_grad_and_step_function( |
| 71 | + obj_fn, ts.model, data, ts.parameters, dps, ts.states, ts.optimizer_state) |
| 72 | + |
| 73 | + @set! ts.states = st |
| 74 | + @set! ts.parameters = ps |
| 75 | + @set! ts.optimizer_state = opt_state |
| 76 | + @set! ts.step = ts.step + 1 |
| 77 | + |
| 78 | + return grads, loss, stats, ts |
| 79 | + end |
| 80 | +end |
| 81 | + |
| 82 | +for inplace in ("!", "") |
| 83 | + fname = Symbol(:compute_gradients_internal_and_step, inplace) |
| 84 | + update_fn = Symbol(:update, inplace) |
| 85 | + @eval function $(fname)(objective_function::F, model, data, ps, dps, |
| 86 | + st, opt_state) where {F} |
| 87 | + _, (loss, stₙ, stats) = Enzyme.autodiff( |
| 88 | + Enzyme.ReverseWithPrimal, Const(objective_function), Active, Const(model), |
| 89 | + Duplicated(ps, dps), Const(st), Const(data)) |
| 90 | + opt_state, ps = Optimisers.$(update_fn)(opt_state, ps, dps) |
| 91 | + return dps, ps, loss, stats, stₙ, opt_state |
| 92 | + end |
| 93 | +end |
0 commit comments