1use core::marker::PhantomData;
18use teeny_core::dtype::Num;
19use teeny_macros::kernel;
20use teeny_triton::triton::{
21 types::{AddOffsets, Comparison},
22 *,
23};
24
25#[kernel]
40pub fn channel_chunk_forward<T: Triton, D: Num, const BLOCK_SIZE: i32>(
41 x_ptr: T::Pointer<D>, y_ptr: T::Pointer<D>, c_total: i32, chunk_c: i32, chunk_offset: i32, ) where
47 T::I32Tensor: types::Tensor<i32, 1>,
48 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
49 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
50{
51 let pid = T::program_id(Axis::X);
52 let num_c_tiles = T::cdiv(chunk_c, BLOCK_SIZE);
53 let pid_n = pid / num_c_tiles;
54 let ci_tile = pid % num_c_tiles;
55 let ci_start = ci_tile * BLOCK_SIZE;
56
57 let ci_offsets = T::arange(0, BLOCK_SIZE) + ci_start;
58 let in_bounds = ci_offsets.lt(chunk_c);
59
60 let in_offsets = ci_offsets + (pid_n * c_total + chunk_offset);
61 let out_offsets = ci_offsets + (pid_n * chunk_c);
62
63 let x = T::load(
64 x_ptr.add_offsets(in_offsets),
65 Some(in_bounds),
66 None,
67 &[],
68 None,
69 None,
70 None,
71 false,
72 );
73 T::store(
74 y_ptr.add_offsets(out_offsets),
75 x,
76 Some(in_bounds),
77 &[],
78 None,
79 None,
80 );
81}
82
83#[kernel]
94pub fn channel_chunk_backward<T: Triton, D: Num, const BLOCK_SIZE: i32>(
95 dy_ptr: T::Pointer<D>, dx_ptr: T::Pointer<D>, c_total: i32,
98 chunk_c: i32,
99 chunk_offset: i32,
100) where
101 T::I32Tensor: types::Tensor<i32, 1>,
102 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
103 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
104{
105 let pid = T::program_id(Axis::X);
106 let num_c_tiles = T::cdiv(chunk_c, BLOCK_SIZE);
107 let pid_n = pid / num_c_tiles;
108 let ci_tile = pid % num_c_tiles;
109 let ci_start = ci_tile * BLOCK_SIZE;
110
111 let ci_offsets = T::arange(0, BLOCK_SIZE) + ci_start;
112 let in_bounds = ci_offsets.lt(chunk_c);
113
114 let dy_offsets = ci_offsets + (pid_n * chunk_c);
115 let dx_offsets = ci_offsets + (pid_n * c_total + chunk_offset);
116
117 let grad = T::load(
118 dy_ptr.add_offsets(dy_offsets),
119 Some(in_bounds),
120 None,
121 &[],
122 None,
123 None,
124 None,
125 false,
126 );
127 T::store(
128 dx_ptr.add_offsets(dx_offsets),
129 grad,
130 Some(in_bounds),
131 &[],
132 None,
133 None,
134 );
135}
136
137pub struct ChannelChunkOp<'a, D: Num> {
138 pub forward: ChannelChunkForward<D>,
139 pub backward: ChannelChunkBackward<D>,
140 _marker: PhantomData<&'a ()>,
141}
142
143pub struct ChannelChunkRuntimeOp<D: Num + Send + Sync + 'static> {
149 fwd: ChannelChunkForward<D>,
150 bwd: ChannelChunkBackward<D>,
151 chunk_c: usize,
152 chunk_offset: usize,
153}
154
155impl<D: Num + Send + Sync + 'static> ChannelChunkRuntimeOp<D> {
156 pub fn new(block_size: i32, chunk_c: usize, chunk_offset: usize) -> Self {
157 Self {
158 fwd: ChannelChunkForward::<D>::new(block_size),
159 bwd: ChannelChunkBackward::<D>::new(block_size),
160 chunk_c,
161 chunk_offset,
162 }
163 }
164
165 pub fn forward_source(&self) -> &str {
166 &self.fwd.source
167 }
168 pub fn backward_source(&self) -> &str {
169 &self.bwd.source
170 }
171 pub fn kernel_name(&self) -> &str {
172 self.fwd.name
173 }
174}
175
176impl<D: Num + Send + Sync + 'static> teeny_core::model::RuntimeOp for ChannelChunkRuntimeOp<D> {
177 fn n_activation_inputs(&self) -> usize {
178 1
179 }
180
181 fn param_shapes(&self, _: &[&[usize]], _: &[usize]) -> Vec<Vec<usize>> {
182 Vec::new()
183 }
184
185 fn pack_args(
186 &self,
187 inputs: &[(teeny_core::model::RawPtr, &[usize])],
188 _params: &[teeny_core::model::RawPtr],
189 output: teeny_core::model::RawPtr,
190 _output_shape: &[usize],
191 _output_row_stride: i32,
192 visitor: &mut dyn teeny_core::device::program::ArgVisitor,
193 ) {
194 let input_shape = inputs[0].1;
196 let c_total = (input_shape[1] * input_shape[2] * input_shape[3]) as i32;
197 let chunk_c = self.chunk_c as i32;
198 let h = input_shape[2];
200 let w = input_shape[3];
201 let chunk_offset = (self.chunk_offset * h * w) as i32;
202
203 visitor.visit_ptr(inputs[0].0);
204 visitor.visit_ptr(output);
205 visitor.visit_i32(c_total);
206 visitor.visit_i32(chunk_c * (h as i32) * (w as i32)); visitor.visit_i32(chunk_offset);
208 }
209
210 fn block(&self) -> [u32; 3] {
211 [self.fwd.block_size as u32, 1, 1]
212 }
213
214 fn grid(&self, output_shape: &[usize]) -> [u32; 3] {
215 let n_spatial = output_shape[0];
218 let chunk_c_nc = output_shape[1] * output_shape[2] * output_shape[3];
219 let num_tiles = chunk_c_nc.div_ceil(self.fwd.block_size as usize);
220 [(n_spatial * num_tiles) as u32, 1, 1]
221 }
222
223 #[cfg(feature = "training")]
224 fn has_backward(&self) -> bool {
225 true
226 }
227
228 #[cfg(feature = "training")]
229 fn pack_backward_args(
230 &self,
231 inputs: &[(teeny_core::model::RawPtr, &[usize])],
232 _params: &[teeny_core::model::RawPtr],
233 _output: teeny_core::model::RawPtr,
234 _output_shape: &[usize],
235 grad_output: teeny_core::model::RawPtr,
236 _grad_output_row_stride: i32,
237 grad_inputs: &[teeny_core::model::RawPtr],
238 _grad_params: &[teeny_core::model::RawPtr],
239 visitor: &mut dyn teeny_core::device::program::ArgVisitor,
240 ) {
241 let input_shape = inputs[0].1; let h = input_shape[2];
246 let w = input_shape[3];
247 let c_total = (input_shape[1] * h * w) as i32;
248 let chunk_c_nc = (self.chunk_c * h * w) as i32;
249 let chunk_offset = (self.chunk_offset * h * w) as i32;
250
251 visitor.visit_ptr(grad_output);
252 visitor.visit_ptr(grad_inputs[0]);
253 visitor.visit_i32(c_total);
254 visitor.visit_i32(chunk_c_nc);
255 visitor.visit_i32(chunk_offset);
256 }
257
258 #[cfg(feature = "training")]
259 fn backward_grid(&self, input_shapes: &[&[usize]], _output_shape: &[usize]) -> [u32; 3] {
260 let s = input_shapes[0];
262 let n_spatial = s[0];
263 let chunk_c_nc = self.chunk_c * s[2] * s[3];
264 let num_tiles = chunk_c_nc.div_ceil(self.fwd.block_size as usize);
265 [(n_spatial * num_tiles) as u32, 1, 1]
266 }
267}