use cubecl::{
features::TypeUsage,
ir::ElemType,
prelude::*,
quant::scheme::{QuantScheme, QuantStore, QuantValue, ScaleDtype},
};
use cubek_tile::{
Axis, DequantAt, KernelForm, Launcher, Partitioning, QuantTileArg, Space, StridedOperand,
TileArg,
};
const M: Axis = Axis(0);
const N: Axis = Axis(1);
pub fn launch_ref(
client: &Client,
input: TensorBinding,
output: TensorBinding,
scales: TensorBinding,
scheme: &QuantScheme,
output_dtype: ElemType,
) -> Result<(), LaunchError> {
assert!(
scheme.store == QuantStore::Native,
"only native quantization is supported for now."
);
assert!(
scheme.num_levels() == 1 && scheme.block_size().is_none(),
"only per tensor quantization is supported for now."
);
assert!(
scheme.scale_dtype() == ScaleDtype::F32,
"only f32 scales are supported for now."
);
check_i8_supported(client, scheme);
assert!(
input.shape.len() == 2 && output.shape.len() == 2,
"dequantize_tiled: both operands must be plain 2-D tensors, got {:?} and {:?}",
input.shape,
output.shape
);
let extents = [(M, input.shape[0]), (N, input.shape[1])];
let space = Space::new(&extents);
let plane_size = client.properties().hardware.plane_size_max;
let (cube_count, cube_dim) = (CubeCount::Static(1, 1, 1), CubeDim::new_2d(plane_size, 1));
let launch = Launcher::new(
client,
space.clone(),
(cube_count.clone(), cube_dim),
KernelForm::Dynamic,
);
let input_dtype = ElemType::from_quant_value(scheme.value);
let input_op = StridedOperand::source(input)
.space(&space)
.subspace(&[M, N])
.checked(false)
.quantized(&[scales], *scheme, DequantAt::Read)
.build();
let output_op = StridedOperand::source(output)
.space(&space)
.subspace(&[M, N])
.checked(false)
.build();
dequantize::launch(
client,
cube_count,
cube_dim,
input_op.arg(),
output_op.arg(),
launch.partitioning_arg(),
input_dtype,
output_dtype,
);
Ok(())
}
fn check_i8_supported(client: &Client, scheme: &QuantScheme) {
match scheme {
QuantScheme {
value: QuantValue::Q8F | QuantValue::Q8S | QuantValue::E4M3 | QuantValue::E5M2,
store: QuantStore::Native,
..
}
| QuantScheme {
value: QuantValue::E2M1,
store: QuantStore::PackedNative(_),
..
} if !i8::supported_uses(client).contains(TypeUsage::Conversion) => {
panic!(
"{:?} is not supported for native quantization",
scheme.value
);
}
_ => {}
}
}
#[cube(launch)]
pub fn dequantize<I: Numeric, O: Numeric>(
input: &QuantTileArg<'_, I, Const<1>>,
output: &TileArg<'_, O, Const<1>>,
space: Partitioning,
#[define(I)] _input_dtype: ElemType,
#[define(O)] _output_dtype: ElemType,
) {
let input = input.tile::<O>(comptime!(space.clone()));
let mut output = output.tile(comptime!(space.clone()));
output.copy_from(&input);
}