1use crate::{
2 BinaryOp, Bool, DTypeKind, Device, Float, FloatUnaryOp, Int, Op, ReduceOp, Tensor, TensorId, TensorImpl, UnaryOp, is_grad_enabled,
3};
4use std::sync::{Arc, RwLock};
5
6pub trait TensorMeta<D: Device, K: DTypeKind<D> + Sized>: Default + Send + Sync {
8 fn on_binary(lhs: &Tensor<D, K>, rhs: &Tensor<D, K>, op: BinaryOp) -> Self;
10 fn on_binary_scalar(lhs: &Tensor<D, K>, rhs: K::Scalar, op: BinaryOp) -> Self;
11
12 fn on_unary(t: &Tensor<D, K>, op: UnaryOp<K::Scalar>) -> Self;
14 fn on_float_unary(t: &Tensor<D, K>, op: FloatUnaryOp) -> Self;
15
16 fn on_reduce(t: &Tensor<D, K>, dims: &[usize], op: ReduceOp) -> Self;
18
19 fn on_matmul(lhs: &Tensor<D, K>, rhs: &Tensor<D, K>) -> Self;
21
22 fn on_broadcast(t: &Tensor<D, K>) -> Self;
24 fn on_narrow(t: &Tensor<D, K>, dim: usize, start: usize, len: usize) -> Self;
25 fn on_slice(t: &Tensor<D, K>, dim: usize, start: usize, end: usize, step: usize) -> Self;
26 fn on_reshape(t: &Tensor<D, K>) -> Self;
27 fn on_transpose(t: &Tensor<D, K>, dim1: usize, dim2: usize) -> Self;
28 fn on_permute(t: &Tensor<D, K>, dims: Vec<usize>) -> Self;
29 fn on_cat<A: AsRef<Tensor<D, K>>>(args: &[A], dim: usize) -> Self;
30 fn on_copy(t: &Tensor<D, K>) -> Self;
31
32 fn on_cast(t: &Tensor<D, K>) -> Self;
34
35 fn on_index_select(t: &Tensor<D, K>, idx: &Tensor<D, Int>, dim: usize) -> Self;
37 fn on_gather(src: &Tensor<D, K>, idx: &Tensor<D, Int>, dim: usize) -> Self;
38 fn on_index_add(init: &Tensor<D, K>, idx: &Tensor<D, Int>, src: &Tensor<D, K>, dim: usize) -> Self;
39 fn on_scatter_add(init: &Tensor<D, K>, idx: &Tensor<D, Int>, src: &Tensor<D, K>, dim: usize) -> Self;
40
41 fn on_pick(mask: &Tensor<D, Bool>, tv: Option<&Tensor<D, K>>, fv: Option<&Tensor<D, K>>) -> Self;
43
44 fn on_rms_norm(input: &Tensor<D, K>, weight: &Tensor<D, K>, eps: f64) -> Self;
46 fn on_softmax(input: &Tensor<D, K>, dim: usize) -> Self;
47}
48
49pub struct FloatMeta<D: Device> {
50 pub op: Option<Op<D>>,
51 pub requires_grad: RwLock<bool>,
52}
53
54impl<D: Device> FloatMeta<D> {
55 pub fn var() -> Self {
57 Self { op: None, requires_grad: RwLock::new(true) }
58 }
59
60 pub fn val() -> Self {
62 Self { op: None, requires_grad: RwLock::new(false) }
63 }
64
65 pub fn from_op(op: Op<D>) -> Self {
67 Self { op: Some(op), requires_grad: RwLock::new(true) }
68 }
69
70 pub fn op(&self) -> Option<&Op<D>> {
71 self.op.as_ref()
72 }
73
74 pub fn requires_grad(&self) -> bool {
75 *self.requires_grad.read().unwrap()
76 }
77
78 pub fn set_requires_grad(&self, mode: bool) {
79 *self.requires_grad.write().unwrap() = mode;
80 }
81
82 pub fn is_leaf(&self) -> bool {
84 self.requires_grad() && self.op.is_none()
85 }
86}
87
88impl<D: Device> Default for FloatMeta<D> {
89 fn default() -> Self {
90 Self::val()
91 }
92}
93
94impl<D: Device> FloatMeta<D> {
97 fn record(record: bool, op: impl FnOnce() -> Op<D>) -> Self {
98 if is_grad_enabled() && record { Self::from_op(op()) } else { Self::val() }
99 }
100
101 pub fn on_binary(lhs: &Tensor<D, Float>, rhs: &Tensor<D, Float>, op: BinaryOp) -> Self {
102 Self::record(lhs.requires_grad() || rhs.requires_grad(), || Op::Binary(lhs.clone(), rhs.clone(), op))
103 }
104
105 pub fn on_binary_scalar(lhs: &Tensor<D, Float>, rhs: f64, op: BinaryOp) -> Self {
106 Self::record(lhs.requires_grad(), || Op::BinaryScalarRhs(lhs.clone(), rhs, op))
107 }
108
109 pub fn on_unary(t: &Tensor<D, Float>, op: UnaryOp<f64>) -> Self {
110 Self::record(t.requires_grad(), || Op::Unary(t.clone(), op))
111 }
112
113 pub fn on_float_unary(t: &Tensor<D, Float>, op: FloatUnaryOp) -> Self {
114 Self::record(t.requires_grad(), || Op::FloatUnary(t.clone(), op))
115 }
116
117 pub fn on_broadcast(t: &Tensor<D, Float>) -> Self {
118 Self::record(t.requires_grad(), || Op::Broadcast(t.clone()))
119 }
120
121 pub fn on_reduce(t: &Tensor<D, Float>, dims: &[usize], op: ReduceOp) -> Self {
122 Self::record(t.requires_grad(), || Op::Reduce(t.clone(), op, dims.to_vec()))
123 }
124
125 pub fn on_matmul(lhs: &Tensor<D, Float>, rhs: &Tensor<D, Float>) -> Self {
126 Self::record(lhs.requires_grad() || rhs.requires_grad(), || Op::Matmul(lhs.clone(), rhs.clone()))
127 }
128
129 pub fn on_narrow(t: &Tensor<D, Float>, dim: usize, start: usize, len: usize) -> Self {
130 Self::record(t.requires_grad(), || Op::Narrow(t.clone(), dim, start, len))
131 }
132
133 pub fn on_slice(t: &Tensor<D, Float>, dim: usize, start: usize, end: usize, step: usize) -> Self {
134 Self::record(t.requires_grad(), || Op::Slice(t.clone(), dim, start, end, step))
135 }
136
137 pub fn on_reshape(t: &Tensor<D, Float>) -> Self {
138 Self::record(t.requires_grad(), || Op::Reshape(t.clone()))
139 }
140
141 pub fn on_transpose(t: &Tensor<D, Float>, dim1: usize, dim2: usize) -> Self {
142 Self::record(t.requires_grad(), || Op::Transpose(t.clone(), dim1, dim2))
143 }
144
145 pub fn on_permute(t: &Tensor<D, Float>, dims: Vec<usize>) -> Self {
146 Self::record(t.requires_grad(), || Op::Permute(t.clone(), dims))
147 }
148
149 pub fn on_cat<A: AsRef<Tensor<D, Float>>>(args: &[A], dim: usize) -> Self {
150 let record = args.iter().any(|t| t.as_ref().requires_grad());
151 Self::record(record, || {
152 let vec = args.iter().map(|a| a.as_ref().clone()).collect();
153 Op::Cat(vec, dim)
154 })
155 }
156
157 pub fn on_copy(t: &Tensor<D, Float>) -> Self {
158 Self::record(t.requires_grad(), || Op::Copy(t.clone()))
159 }
160
161 pub fn on_cast(t: &Tensor<D, Float>) -> Self {
162 Self::record(t.requires_grad(), || Op::Cast(t.clone()))
163 }
164
165 pub fn on_pick(mask: &Tensor<D, Bool>, tv: Option<&Tensor<D, Float>>, fv: Option<&Tensor<D, Float>>) -> Self {
166 let record = tv.map(|t| t.requires_grad()).unwrap_or(false) || fv.map(|f| f.requires_grad()).unwrap_or(false);
167 Self::record(record, || Op::Pick(mask.clone(), tv.cloned(), fv.cloned()))
168 }
169
170 pub fn on_index_select(t: &Tensor<D, Float>, idx: &Tensor<D, Int>, dim: usize) -> Self {
171 Self::record(t.requires_grad(), || Op::IndexSelect(t.clone(), idx.clone(), dim))
172 }
173
174 pub fn on_index_add(init: &Tensor<D, Float>, idx: &Tensor<D, Int>, src: &Tensor<D, Float>, dim: usize) -> Self {
175 Self::record(init.requires_grad() || src.requires_grad(), || Op::IndexAdd(init.clone(), idx.clone(), src.clone(), dim))
176 }
177
178 pub fn on_scatter_add(init: &Tensor<D, Float>, idx: &Tensor<D, Int>, src: &Tensor<D, Float>, dim: usize) -> Self {
179 Self::record(init.requires_grad() || src.requires_grad(), || Op::ScatterAdd(init.clone(), idx.clone(), src.clone(), dim))
180 }
181
182 pub fn on_gather(src: &Tensor<D, Float>, idx: &Tensor<D, Int>, dim: usize) -> Self {
183 Self::record(src.requires_grad(), || Op::Gather(src.clone(), idx.clone(), dim))
184 }
185
186 pub fn on_rms_norm(input: &Tensor<D, Float>, weight: &Tensor<D, Float>, eps: f64) -> Self {
187 Self::record(input.requires_grad() || weight.requires_grad(), || Op::RmsNorm(input.clone(), weight.clone(), eps))
188 }
189
190 pub fn on_softmax(input: &Tensor<D, Float>, dim: usize) -> Self {
191 Self::record(input.requires_grad(), || Op::Softmax(input.clone(), dim))
192 }
193}
194
195impl<D: Device> Tensor<D, Float> {
197 pub fn detach(&self) -> Self {
198 if !self.requires_grad() {
199 self.clone()
200 } else {
201 Self(Arc::new(TensorImpl {
202 id: TensorId::new(),
203 storage: self.0.storage.clone(),
204 layout: self.layout().clone(),
205 dtype: self.dtype(),
206 device: self.device().clone(),
207 meta: FloatMeta::val(),
208 }))
209 }
210 }
211
212 pub fn requires_grad(&self) -> bool {
213 self.0.meta.requires_grad()
214 }
215
216 pub fn set_requires_grad(&self, mode: bool) {
217 self.0.meta.set_requires_grad(mode)
218 }
219
220 pub fn is_leaf(&self) -> bool {
221 self.0.meta.is_leaf()
222 }
223
224 pub fn op(&self) -> Option<&Op<D>> {
225 self.0.meta.op()
226 }
227}
228
229impl<D: Device> TensorMeta<D, Float> for FloatMeta<D> {
234 fn on_binary(lhs: &Tensor<D, Float>, rhs: &Tensor<D, Float>, op: BinaryOp) -> Self {
235 FloatMeta::on_binary(lhs, rhs, op)
236 }
237
238 fn on_binary_scalar(lhs: &Tensor<D, Float>, rhs: f64, op: BinaryOp) -> Self {
239 FloatMeta::on_binary_scalar(lhs, rhs, op)
240 }
241
242 fn on_unary(t: &Tensor<D, Float>, op: UnaryOp<f64>) -> Self {
243 FloatMeta::on_unary(t, op)
244 }
245
246 fn on_float_unary(t: &Tensor<D, Float>, op: FloatUnaryOp) -> Self {
247 FloatMeta::on_float_unary(t, op)
248 }
249
250 fn on_reduce(t: &Tensor<D, Float>, dims: &[usize], op: ReduceOp) -> Self {
251 FloatMeta::on_reduce(t, dims, op)
252 }
253
254 fn on_matmul(lhs: &Tensor<D, Float>, rhs: &Tensor<D, Float>) -> Self {
255 FloatMeta::on_matmul(lhs, rhs)
256 }
257
258 fn on_broadcast(t: &Tensor<D, Float>) -> Self {
259 FloatMeta::on_broadcast(t)
260 }
261
262 fn on_narrow(t: &Tensor<D, Float>, dim: usize, start: usize, len: usize) -> Self {
263 FloatMeta::on_narrow(t, dim, start, len)
264 }
265
266 fn on_slice(t: &Tensor<D, Float>, dim: usize, start: usize, end: usize, step: usize) -> Self {
267 FloatMeta::on_slice(t, dim, start, end, step)
268 }
269
270 fn on_reshape(t: &Tensor<D, Float>) -> Self {
271 FloatMeta::on_reshape(t)
272 }
273
274 fn on_transpose(t: &Tensor<D, Float>, dim1: usize, dim2: usize) -> Self {
275 FloatMeta::on_transpose(t, dim1, dim2)
276 }
277
278 fn on_permute(t: &Tensor<D, Float>, dims: Vec<usize>) -> Self {
279 FloatMeta::on_permute(t, dims)
280 }
281
282 fn on_cat<A: AsRef<Tensor<D, Float>>>(args: &[A], dim: usize) -> Self {
283 FloatMeta::on_cat(args, dim)
284 }
285
286 fn on_copy(t: &Tensor<D, Float>) -> Self {
287 FloatMeta::on_copy(t)
288 }
289
290 fn on_cast(t: &Tensor<D, Float>) -> Self {
291 FloatMeta::on_cast(t)
292 }
293
294 fn on_index_select(t: &Tensor<D, Float>, idx: &Tensor<D, Int>, dim: usize) -> Self {
295 FloatMeta::on_index_select(t, idx, dim)
296 }
297
298 fn on_gather(src: &Tensor<D, Float>, idx: &Tensor<D, Int>, dim: usize) -> Self {
299 FloatMeta::on_gather(src, idx, dim)
300 }
301
302 fn on_index_add(init: &Tensor<D, Float>, idx: &Tensor<D, Int>, src: &Tensor<D, Float>, dim: usize) -> Self {
303 FloatMeta::on_index_add(init, idx, src, dim)
304 }
305
306 fn on_scatter_add(init: &Tensor<D, Float>, idx: &Tensor<D, Int>, src: &Tensor<D, Float>, dim: usize) -> Self {
307 FloatMeta::on_scatter_add(init, idx, src, dim)
308 }
309
310 fn on_pick(mask: &Tensor<D, Bool>, tv: Option<&Tensor<D, Float>>, fv: Option<&Tensor<D, Float>>) -> Self {
311 FloatMeta::on_pick(mask, tv, fv)
312 }
313
314 fn on_rms_norm(input: &Tensor<D, Float>, weight: &Tensor<D, Float>, eps: f64) -> Self {
315 FloatMeta::on_rms_norm(input, weight, eps)
316 }
317
318 fn on_softmax(input: &Tensor<D, Float>, dim: usize) -> Self {
319 FloatMeta::on_softmax(input, dim)
320 }
321}
322
323impl<D: Device, K: crate::DTypeKind<D>> TensorMeta<D, K> for () {
328 fn on_binary(_: &Tensor<D, K>, _: &Tensor<D, K>, _: BinaryOp) -> Self {}
329 fn on_binary_scalar(_: &Tensor<D, K>, _: K::Scalar, _: BinaryOp) -> Self {}
330 fn on_unary(_: &Tensor<D, K>, _: UnaryOp<K::Scalar>) -> Self {}
331 fn on_float_unary(_: &Tensor<D, K>, _: FloatUnaryOp) -> Self {}
332 fn on_reduce(_: &Tensor<D, K>, _: &[usize], _: ReduceOp) -> Self {}
333 fn on_matmul(_: &Tensor<D, K>, _: &Tensor<D, K>) -> Self {}
334 fn on_broadcast(_: &Tensor<D, K>) -> Self {}
335 fn on_narrow(_: &Tensor<D, K>, _: usize, _: usize, _: usize) -> Self {}
336 fn on_slice(_: &Tensor<D, K>, _: usize, _: usize, _: usize, _: usize) -> Self {}
337 fn on_reshape(_: &Tensor<D, K>) -> Self {}
338 fn on_transpose(_: &Tensor<D, K>, _: usize, _: usize) -> Self {}
339 fn on_permute(_: &Tensor<D, K>, _: Vec<usize>) -> Self {}
340 fn on_cat<A: AsRef<Tensor<D, K>>>(_: &[A], _: usize) -> Self {}
341 fn on_copy(_: &Tensor<D, K>) -> Self {}
342 fn on_cast(_: &Tensor<D, K>) -> Self {}
343 fn on_index_select(_: &Tensor<D, K>, _: &Tensor<D, Int>, _: usize) -> Self {}
344 fn on_gather(_: &Tensor<D, K>, _: &Tensor<D, Int>, _: usize) -> Self {}
345 fn on_index_add(_: &Tensor<D, K>, _: &Tensor<D, Int>, _: &Tensor<D, K>, _: usize) -> Self {}
346 fn on_scatter_add(_: &Tensor<D, K>, _: &Tensor<D, Int>, _: &Tensor<D, K>, _: usize) -> Self {}
347 fn on_pick(_: &Tensor<D, Bool>, _: Option<&Tensor<D, K>>, _: Option<&Tensor<D, K>>) -> Self {}
348 fn on_rms_norm(_: &Tensor<D, K>, _: &Tensor<D, K>, _: f64) -> Self {}
349 fn on_softmax(_: &Tensor<D, K>, _: usize) -> Self {}
350}