ferrotensor_backend/engine/
training.rs1use super::{groups64, uniform, ComputeEngine};
4use crate::{UnifiedTensor, WgpuContext};
5
6#[repr(C)]
9#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
10pub struct AdamParams {
11 pub lr: f32,
13 pub beta1: f32,
15 pub beta2: f32,
17 pub eps: f32,
19 pub weight_decay: f32,
21 pub t: f32,
23 pub _pad: [f32; 2],
25}
26
27impl ComputeEngine {
28 pub fn sgd_update(
30 &self,
31 ctx: &WgpuContext,
32 weight: &UnifiedTensor,
33 grad: &UnifiedTensor,
34 lr: f32,
35 ) {
36 let lr_buf = uniform(ctx, bytemuck::cast_slice(&[lr]));
37 self.run(
38 ctx,
39 &self.sgd,
40 &[(0, weight.buffer()), (1, grad.buffer()), (2, &lr_buf)],
41 groups64(weight.shape.iter().product()),
42 );
43 }
44
45 pub fn adamw_update(
48 &self,
49 ctx: &WgpuContext,
50 weight: &UnifiedTensor,
51 grad: &UnifiedTensor,
52 m: &UnifiedTensor,
53 v: &UnifiedTensor,
54 params: &AdamParams,
55 ) {
56 let params_buf = uniform(ctx, bytemuck::bytes_of(params));
57 self.run(
58 ctx,
59 &self.adamw,
60 &[
61 (0, weight.buffer()),
62 (1, grad.buffer()),
63 (3, m.buffer()),
64 (4, v.buffer()),
65 (5, ¶ms_buf),
66 ],
67 groups64(weight.shape.iter().product()),
68 );
69 }
70
71 pub fn mse_loss(
73 &self,
74 ctx: &WgpuContext,
75 pred: &UnifiedTensor,
76 target: &UnifiedTensor,
77 out: &UnifiedTensor,
78 ) {
79 self.binary(ctx, &self.mse_loss, pred, target, out);
80 }
81
82 pub fn mse_loss_backward(
84 &self,
85 ctx: &WgpuContext,
86 pred: &UnifiedTensor,
87 target: &UnifiedTensor,
88 grad_in: &UnifiedTensor,
89 ) {
90 self.run(
91 ctx,
92 &self.mse_loss_bw,
93 &[
94 (0, pred.buffer()),
95 (1, target.buffer()),
96 (3, grad_in.buffer()),
97 ],
98 groups64(pred.shape.iter().product()),
99 );
100 }
101
102 pub fn cross_entropy_loss(
104 &self,
105 ctx: &WgpuContext,
106 logits: &UnifiedTensor,
107 target: u32,
108 loss_out: &UnifiedTensor,
109 ) {
110 let vocab_size = logits.shape.iter().product::<usize>() as u32;
111 let params = uniform(ctx, bytemuck::cast_slice(&[target, vocab_size, 0, 0]));
112 self.run(
113 ctx,
114 &self.ce_loss,
115 &[(0, logits.buffer()), (1, loss_out.buffer()), (2, ¶ms)],
116 (1, 1, 1),
117 );
118 }
119
120 pub fn cross_entropy_backward(
122 &self,
123 ctx: &WgpuContext,
124 logits: &UnifiedTensor,
125 target: u32,
126 grad_out: &UnifiedTensor,
127 ) {
128 let vocab_size = logits.shape.iter().product::<usize>() as u32;
129 let params = uniform(ctx, bytemuck::cast_slice(&[target, vocab_size, 0, 0]));
130 self.run(
131 ctx,
132 &self.ce_loss_bw,
133 &[(0, logits.buffer()), (1, grad_out.buffer()), (2, ¶ms)],
134 groups64(vocab_size as usize),
135 );
136 }
137
138 pub fn gradient_norm_squared(
140 &self,
141 ctx: &WgpuContext,
142 input: &UnifiedTensor,
143 out: &UnifiedTensor,
144 ) {
145 self.run(
146 ctx,
147 &self.grad_norm,
148 &[(0, input.buffer()), (1, out.buffer())],
149 groups64(input.shape.iter().product()),
150 );
151 }
152
153 pub fn clip_grad_by_norm(&self, ctx: &WgpuContext, grad: &UnifiedTensor, scale: f32) {
155 let params = uniform(ctx, bytemuck::cast_slice(&[scale]));
156 self.run(
157 ctx,
158 &self.grad_clip,
159 &[(0, grad.buffer()), (1, ¶ms)],
160 groups64(grad.shape.iter().product()),
161 );
162 }
163
164 pub fn gradient_accumulate(
167 &self,
168 ctx: &WgpuContext,
169 accum_grad: &UnifiedTensor,
170 new_grad: &UnifiedTensor,
171 ) {
172 self.run(
173 ctx,
174 &self.grad_accum,
175 &[(0, accum_grad.buffer()), (1, new_grad.buffer())],
176 groups64(accum_grad.shape.iter().product()),
177 );
178 }
179
180 pub fn gradient_scale(&self, ctx: &WgpuContext, grad: &UnifiedTensor, scale: f32) {
183 let params = uniform(ctx, bytemuck::cast_slice(&[scale]));
184 self.run(
185 ctx,
186 &self.grad_scale,
187 &[(0, grad.buffer()), (1, ¶ms)],
188 groups64(grad.shape.iter().product()),
189 );
190 }
191}