burn_cubecl/kernel/mask/
mask_fill.rs1use burn_backend::DType;
2use burn_backend::cubecl::dtype_to_storage_type;
3use cubecl::{
4 calculate_cube_count_elemwise,
5 prelude::*,
6 std::tensor::layout::linear::{LinearView, LinearViewMut},
7};
8
9use crate::{
10 kernel::utils::{address_type, broadcast_shape},
11 ops::{max_vector_size_many, numeric::empty_device_dtype},
12 tensor::CubeTensor,
13};
14
15#[cube(launch_unchecked, address_type = "dynamic")]
16fn mask_fill_kernel<T: Numeric, B: Int, N: Size>(
17 input: LinearView<'_, Vector<T, N>>,
18 mask: LinearView<'_, Vector<B, N>>,
19 mut output: LinearViewMut<'_, Vector<T, N>>,
20 value: InputScalar,
21 #[define(T, B)] _dtypes: [ElemType; 2],
22) {
23 if !output.is_in_bounds(ABSOLUTE_POS) {
24 terminate!();
25 }
26
27 let mask = Vector::cast_from(mask.read(ABSOLUTE_POS));
28 let input = input.read(ABSOLUTE_POS);
29 let value = Vector::new(value.get::<T>());
30
31 output.write(ABSOLUTE_POS, select_many(mask, value, input));
32}
33
34#[derive(Clone, Copy, Debug)]
35pub enum MaskFillStrategy {
41 Readonly,
43 Inplace,
45}
46
47pub fn mask_fill(
49 input: CubeTensor,
50 mask: CubeTensor,
51 value: InputScalar,
52 strategy: MaskFillStrategy,
53 dtype_bool: DType,
54) -> CubeTensor {
55 let ndims = input.meta.num_dims();
56 let out_shape = broadcast_shape(&[&input, &mask]);
57 if out_shape.num_elements() == 0 {
58 return empty_device_dtype(
59 input.client.clone(),
60 input.device.clone(),
61 out_shape,
62 input.dtype,
63 );
64 }
65
66 let vector_size = max_vector_size_many(&[&input, &mask], ndims - 1);
67 let working_units = out_shape.num_elements() / vector_size as usize;
68 let cube_dim = CubeDim::new(&input.client, working_units);
69 let cube_count = calculate_cube_count_elemwise(&input.client, working_units, cube_dim);
70
71 let output = match strategy {
72 MaskFillStrategy::Readonly => empty_device_dtype(
73 input.client.clone(),
74 input.device.clone(),
75 out_shape,
76 input.dtype,
77 ),
78 MaskFillStrategy::Inplace => input.clone(),
79 };
80
81 let out_arg = match strategy {
82 MaskFillStrategy::Readonly => output.clone().into_linear_view(),
83 MaskFillStrategy::Inplace => output.as_linear_view_alias(0),
84 };
85
86 let at = address_type!(input, mask, output);
87 let mask = mask.into_linear_view_like(&output);
88
89 unsafe {
90 mask_fill_kernel::launch_unchecked(
91 &output.client,
92 cube_count,
93 cube_dim,
94 at,
95 vector_size,
96 input.into_linear_view_like(&output),
97 mask,
98 out_arg,
99 value,
100 [
101 dtype_to_storage_type(output.dtype),
102 dtype_to_storage_type(dtype_bool),
103 ],
104 );
105 }
106
107 output
108}