tenflowers_neural/layers/pooling/
pool2d.rs1use crate::layers::Layer;
2use scirs2_core::num_traits::{Float, FromPrimitive, One, Zero};
3use tenflowers_core::{Result, Tensor};
4
5#[derive(Clone)]
6pub struct MaxPool2D {
7 #[allow(dead_code)]
8 kernel_size: (usize, usize),
9 #[allow(dead_code)]
10 stride: (usize, usize),
11 #[allow(dead_code)]
12 padding: String,
13}
14
15impl MaxPool2D {
16 pub fn new(kernel_size: (usize, usize), stride: Option<(usize, usize)>) -> Self {
17 Self {
18 kernel_size,
19 stride: stride.unwrap_or(kernel_size),
20 padding: "valid".to_string(),
21 }
22 }
23}
24
25impl<T> Layer<T> for MaxPool2D
26where
27 T: Clone
28 + Default
29 + Zero
30 + PartialOrd
31 + Send
32 + Sync
33 + 'static
34 + bytemuck::Pod
35 + bytemuck::Zeroable,
36{
37 fn forward(&self, input: &Tensor<T>) -> Result<Tensor<T>> {
38 tenflowers_core::ops::max_pool2d(input, self.kernel_size, self.stride, &self.padding)
39 }
40
41 fn parameters(&self) -> Vec<&Tensor<T>> {
42 vec![]
43 }
44
45 fn parameters_mut(&mut self) -> Vec<&mut Tensor<T>> {
46 vec![]
47 }
48
49 fn set_training(&mut self, _training: bool) {
50 }
52
53 fn clone_box(&self) -> Box<dyn Layer<T>> {
54 Box::new(self.clone())
55 }
56}
57
58fn adaptive_max_pool2d_forward<T>(
60 input: &Tensor<T>,
61 output_size: (usize, usize),
62 input_shape: (usize, usize, usize, usize), ) -> Result<Tensor<T>>
64where
65 T: Clone + Default + Zero + One + PartialOrd + Send + Sync + 'static,
66{
67 let (batch_size, channels, input_height, input_width) = input_shape;
68 let (output_height, output_width) = output_size;
69
70 let input_data = input.as_slice().ok_or_else(|| {
72 tenflowers_core::TensorError::device_error_simple(
73 "Cannot access input tensor data".to_string(),
74 )
75 })?;
76
77 let total_output_elements = batch_size * channels * output_height * output_width;
79 let mut output_data = vec![T::zero(); total_output_elements];
80
81 for b in 0..batch_size {
83 for c in 0..channels {
84 for oh in 0..output_height {
85 for ow in 0..output_width {
86 let ih_start = (oh * input_height) / output_height;
88 let ih_end = ((oh + 1) * input_height + output_height - 1) / output_height;
89 let iw_start = (ow * input_width) / output_width;
90 let iw_end = ((ow + 1) * input_width + output_width - 1) / output_width;
91
92 let mut max_val = T::zero();
94 let mut first = true;
95
96 for ih in ih_start..ih_end {
97 for iw in iw_start..iw_end {
98 if ih < input_height && iw < input_width {
99 let input_idx = b * channels * input_height * input_width
100 + c * input_height * input_width
101 + ih * input_width
102 + iw;
103
104 if first || input_data[input_idx] > max_val {
105 max_val = input_data[input_idx].clone();
106 first = false;
107 }
108 }
109 }
110 }
111
112 let output_idx = b * channels * output_height * output_width
114 + c * output_height * output_width
115 + oh * output_width
116 + ow;
117 output_data[output_idx] = max_val;
118 }
119 }
120 }
121 }
122
123 Tensor::from_data(
124 output_data,
125 &[batch_size, channels, output_height, output_width],
126 )
127}
128
129fn adaptive_avg_pool2d_forward<T>(
131 input: &Tensor<T>,
132 output_size: (usize, usize),
133 input_shape: (usize, usize, usize, usize), ) -> Result<Tensor<T>>
135where
136 T: Clone + Default + Zero + One + Float + FromPrimitive + Send + Sync + 'static,
137{
138 let (batch_size, channels, input_height, input_width) = input_shape;
139 let (output_height, output_width) = output_size;
140
141 let input_data = input.as_slice().ok_or_else(|| {
143 tenflowers_core::TensorError::device_error_simple(
144 "Cannot access input tensor data".to_string(),
145 )
146 })?;
147
148 let total_output_elements = batch_size * channels * output_height * output_width;
150 let mut output_data = vec![T::zero(); total_output_elements];
151
152 for b in 0..batch_size {
154 for c in 0..channels {
155 for oh in 0..output_height {
156 for ow in 0..output_width {
157 let ih_start = (oh * input_height) / output_height;
159 let ih_end = ((oh + 1) * input_height + output_height - 1) / output_height;
160 let iw_start = (ow * input_width) / output_width;
161 let iw_end = ((ow + 1) * input_width + output_width - 1) / output_width;
162
163 let mut sum = T::zero();
165 let mut count = 0;
166
167 for ih in ih_start..ih_end {
168 for iw in iw_start..iw_end {
169 if ih < input_height && iw < input_width {
170 let input_idx = b * channels * input_height * input_width
171 + c * input_height * input_width
172 + ih * input_width
173 + iw;
174
175 sum = sum + input_data[input_idx];
176 count += 1;
177 }
178 }
179 }
180
181 let avg = if count > 0 {
183 sum / T::from_usize(count).unwrap_or(T::one())
184 } else {
185 T::zero()
186 };
187
188 let output_idx = b * channels * output_height * output_width
190 + c * output_height * output_width
191 + oh * output_width
192 + ow;
193 output_data[output_idx] = avg;
194 }
195 }
196 }
197 }
198
199 Tensor::from_data(
200 output_data,
201 &[batch_size, channels, output_height, output_width],
202 )
203}
204
205#[derive(Clone)]
206pub struct AvgPool2D {
207 #[allow(dead_code)]
208 kernel_size: (usize, usize),
209 #[allow(dead_code)]
210 stride: (usize, usize),
211 #[allow(dead_code)]
212 padding: String,
213}
214
215impl AvgPool2D {
216 pub fn new(kernel_size: (usize, usize), stride: Option<(usize, usize)>) -> Self {
217 Self {
218 kernel_size,
219 stride: stride.unwrap_or(kernel_size),
220 padding: "valid".to_string(),
221 }
222 }
223}
224
225impl<T> Layer<T> for AvgPool2D
226where
227 T: Clone
228 + Default
229 + Zero
230 + Float
231 + FromPrimitive
232 + Send
233 + Sync
234 + 'static
235 + bytemuck::Pod
236 + bytemuck::Zeroable,
237{
238 fn forward(&self, input: &Tensor<T>) -> Result<Tensor<T>> {
239 tenflowers_core::ops::avg_pool2d(input, self.kernel_size, self.stride, &self.padding)
240 }
241
242 fn parameters(&self) -> Vec<&Tensor<T>> {
243 vec![]
244 }
245
246 fn parameters_mut(&mut self) -> Vec<&mut Tensor<T>> {
247 vec![]
248 }
249
250 fn set_training(&mut self, _training: bool) {
251 }
253
254 fn clone_box(&self) -> Box<dyn Layer<T>> {
255 Box::new(self.clone())
256 }
257}
258
259#[derive(Clone)]
260pub struct AdaptiveMaxPool2D {
261 output_size: (usize, usize),
262}
263
264impl AdaptiveMaxPool2D {
265 pub fn new(output_size: (usize, usize)) -> Self {
266 Self { output_size }
267 }
268}
269
270impl<T> Layer<T> for AdaptiveMaxPool2D
271where
272 T: Clone + Default + Zero + One + PartialOrd + Send + Sync + 'static,
273{
274 fn forward(&self, input: &Tensor<T>) -> Result<Tensor<T>> {
275 let input_shape = input.shape().dims();
276 if input_shape.len() != 4 {
277 return Err(tenflowers_core::TensorError::invalid_shape(
278 "AdaptiveMaxPool2D",
279 "4D tensor [batch, channels, height, width]",
280 &format!("{}D tensor", input_shape.len()),
281 ));
282 }
283
284 let shape_tuple = (
285 input_shape[0],
286 input_shape[1],
287 input_shape[2],
288 input_shape[3],
289 );
290 adaptive_max_pool2d_forward(input, self.output_size, shape_tuple)
291 }
292
293 fn parameters(&self) -> Vec<&Tensor<T>> {
294 vec![]
295 }
296
297 fn parameters_mut(&mut self) -> Vec<&mut Tensor<T>> {
298 vec![]
299 }
300
301 fn set_training(&mut self, _training: bool) {
302 }
304
305 fn clone_box(&self) -> Box<dyn Layer<T>> {
306 Box::new(self.clone())
307 }
308}
309
310#[derive(Clone)]
311pub struct AdaptiveAvgPool2D {
312 output_size: (usize, usize),
313}
314
315impl AdaptiveAvgPool2D {
316 pub fn new(output_size: (usize, usize)) -> Self {
317 Self { output_size }
318 }
319}
320
321impl<T> Layer<T> for AdaptiveAvgPool2D
322where
323 T: Clone + Default + Zero + One + Float + FromPrimitive + Send + Sync + 'static,
324{
325 fn forward(&self, input: &Tensor<T>) -> Result<Tensor<T>> {
326 let input_shape = input.shape().dims();
327 if input_shape.len() != 4 {
328 return Err(tenflowers_core::TensorError::invalid_shape(
329 "AdaptiveAvgPool2D",
330 "4D tensor [batch, channels, height, width]",
331 &format!("{}D tensor", input_shape.len()),
332 ));
333 }
334
335 let shape_tuple = (
336 input_shape[0],
337 input_shape[1],
338 input_shape[2],
339 input_shape[3],
340 );
341 adaptive_avg_pool2d_forward(input, self.output_size, shape_tuple)
342 }
343
344 fn parameters(&self) -> Vec<&Tensor<T>> {
345 vec![]
346 }
347
348 fn parameters_mut(&mut self) -> Vec<&mut Tensor<T>> {
349 vec![]
350 }
351
352 fn set_training(&mut self, _training: bool) {
353 }
355
356 fn clone_box(&self) -> Box<dyn Layer<T>> {
357 Box::new(self.clone())
358 }
359}