MCPcopy Create free account
hub / github.com/pytorch/executorch / _dequantize_affine_handler

Function _dequantize_affine_handler

backends/mlx/ops.py:3770–3867  ·  view source on GitHub ↗

Handle standalone torchao.dequantize_affine (not fused with linear/embedding). MLX's dequantize always operates along the last axis. When the quantized dimension is not last (e.g. Conv2d with block_size=[1,32,1,1]), we permute the constant weight/scale/zero_point tensors at compile tim

(P: MLXProgramBuilder, n: Node)

Source from the content-addressed store, hash-verified

3768
3769@REGISTRY.register(target=[torch.ops.torchao.dequantize_affine.default])
3770def _dequantize_affine_handler(P: MLXProgramBuilder, n: Node) -> Slot:
3771 """Handle standalone torchao.dequantize_affine (not fused with linear/embedding).
3772
3773 MLX's dequantize always operates along the last axis. When the quantized
3774 dimension is not last (e.g. Conv2d with block_size=[1,32,1,1]), we permute
3775 the constant weight/scale/zero_point tensors at compile time so the
3776 quantized dim becomes last, emit the DequantizeNode, then emit a
3777 TransposeNode with the inverse permutation to restore the original layout.
3778 """
3779 parsed = parse_dequant_node(n)
3780 if parsed is None:
3781 raise NotImplementedError(
3782 f"dequantize_affine: unsupported quantization config at {n}"
3783 )
3784 (
3785 qdata_node,
3786 scale_node,
3787 zero_point_node,
3788 group_size,
3789 bits,
3790 out_dtype,
3791 quantized_dim,
3792 ) = parsed
3793
3794 qdata_target, qdata = P.get_placeholder_target_and_tensor(qdata_node)
3795 zero_point_target, zero_point = P.get_placeholder_target_and_tensor(zero_point_node)
3796 scale_target, scale = P.get_placeholder_target_and_tensor(scale_node)
3797
3798 if out_dtype is None:
3799 out_dtype = scale_node.meta["val"].dtype
3800 out_scalar_type = torch_dtype_to_scalar_type(out_dtype)
3801
3802 ndim = qdata.ndim
3803 needs_permute = quantized_dim != ndim - 1
3804
3805 if needs_permute:
3806 perm = list(range(ndim))
3807 perm.remove(quantized_dim)
3808 perm.append(quantized_dim)
3809 qdata = qdata.permute(perm).contiguous()
3810 scale = scale.permute(perm).contiguous()
3811 zero_point = zero_point.permute(perm).contiguous()
3812
3813 # to_mlx_qparams expects 2D tensors; flatten N-D to 2D for packing,
3814 # then restore the (possibly permuted) leading dimensions afterward.
3815 permuted_shape = qdata.shape
3816 qdata_2d = qdata.reshape(-1, qdata.shape[-1])
3817 scale_2d = scale.reshape(-1, scale.shape[-1])
3818 zero_point_2d = zero_point.reshape(-1, zero_point.shape[-1])
3819
3820 Q, B = to_mlx_qparams(qdata_2d, scale_2d, zero_point_2d, bits)
3821
3822 leading_dims = permuted_shape[:-1]
3823 Q = Q.reshape(*leading_dims, Q.shape[-1])
3824 scale_nd = scale_2d.reshape(*leading_dims, scale_2d.shape[-1])
3825 if B is not None:
3826 B = B.reshape(*leading_dims, B.shape[-1])
3827

Callers

nothing calls this directly

Calls 13

parse_dequant_nodeFunction · 0.90
to_mlx_qparamsFunction · 0.90
emit_quantized_biasesFunction · 0.90
removeMethod · 0.80
make_or_get_constantMethod · 0.80
emitMethod · 0.80
slot_to_tidMethod · 0.80
appendMethod · 0.45
permuteMethod · 0.45
make_tmp_slotMethod · 0.45

Tested by

no test coverage detected