From 93313dff09d1eaf4b96d071125c8b23cf47a8345 Mon Sep 17 00:00:00 2001 From: tguerand Date: Fri, 2 Feb 2024 13:43:07 +0800 Subject: [PATCH] feat: implement QuantizedUnfold --- src/concrete/ml/onnx/ops_impl.py | 4 +--- src/concrete/ml/quantization/quantized_ops.py | 20 +------------------ tests/quantization/test_quantized_ops.py | 14 +++---------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/src/concrete/ml/onnx/ops_impl.py b/src/concrete/ml/onnx/ops_impl.py index 20fbf70f9..ed0db0be3 100644 --- a/src/concrete/ml/onnx/ops_impl.py +++ b/src/concrete/ml/onnx/ops_impl.py @@ -2077,7 +2077,6 @@ def numpy_expand(x: numpy.ndarray, shape: Optional[Tuple[int]] = None) -> Tuple[ def numpy_unfold( x: numpy.ndarray, *, - ceil_mode: int, kernel_shape: Tuple[int, ...], pads: Tuple[int, ...] = None, strides: Tuple[int, ...] = None, @@ -2090,7 +2089,6 @@ def numpy_unfold( Args: x (numpy.ndarray): input data (many dtypes are supported). Shape is N x C x H x W for 2d - ceil_mode (int): ONNX rounding parameter, expected 0 (torch style dimension computation) kernel_shape (Tuple[int, ...]): shape of the kernel. Should have 2 elements for 2d conv pads (Tuple[int, ...]): padding in ONNX format (begin, end) on each axis strides (Tuple[int, ...]): stride of the convolution on each axis @@ -2135,7 +2133,7 @@ def numpy_unfold( kernels = numpy.concatenate(numpy.array(kernels_list), axis=0) # Pad the input tensor - pool_pads = compute_onnx_pool_padding(x.shape, kernel_shape, pads, strides, ceil_mode) + pool_pads = compute_onnx_pool_padding(x.shape, kernel_shape, pads, strides, ceil_mode=0) q_input_pad = numpy_onnx_pad(x, pool_pads) # Compute the kernels of input values for each kernel position diff --git a/src/concrete/ml/quantization/quantized_ops.py b/src/concrete/ml/quantization/quantized_ops.py index 575f42810..c5e782a4b 100644 --- a/src/concrete/ml/quantization/quantized_ops.py +++ b/src/concrete/ml/quantization/quantized_ops.py @@ -2507,7 +2507,6 @@ def __init__( ) # Get the ONNX parameters - self.ceil_mode = attrs.get("ceil_mode", None) self.kernel_shape = attrs.get("kernel_shape", None) self.pads = attrs.get("pads", tuple([0] * 2 * (len(self.kernel_shape) - 2))) self.dilations = attrs.get("dilations", tuple([1] * len(self.kernel_shape))) @@ -2565,7 +2564,7 @@ def q_impl( # Compute padding with floor and apply it to the input, pad with the input zero-point pool_pads = compute_onnx_pool_padding( - q_input.qvalues.shape, self.kernel_shape, self.pads, self.strides, 0 + q_input.qvalues.shape, self.kernel_shape, self.pads, self.strides, ceil_mode=0 ) # Can only pad with scalar zero-points, but zero-points can be float in special cases @@ -2574,23 +2573,6 @@ def q_impl( pad_value = int(q_input.quantizer.zero_point) q_input_pad = numpy_onnx_pad(q_input.qvalues, pool_pads, pad_value, int_only=True) - if self.ceil_mode == 1: - # Padding for TensorFlow style - - # Compute padding with ceil and apply it to the input, pad with zeros, the zeros - # will be ignored in the computation - pool_pads_ceil = compute_onnx_pool_padding( - q_input.qvalues.shape, self.kernel_shape, self.pads, self.strides, 1 - ) - - # Can only pad with scalar zero-points, but zero-points can be float in special cases - # for output layers - q_input_pad_ceil = numpy_onnx_pad(q_input.qvalues, pool_pads_ceil, 0, True) - - # Copy the PyTorch style padded input to the larger 0 padded tensor - q_input_pad_ceil[:, :, 0 : q_input_pad.shape[2], 0 : q_input_pad.shape[3]] = q_input_pad - q_input_pad = q_input_pad_ceil - # Remark that here, we are _not_ using Concrete pad, since it would pad with # 0's while we want to pad with zero-point's. So, instead, he have done the padding # on our side, with q_input_pad diff --git a/tests/quantization/test_quantized_ops.py b/tests/quantization/test_quantized_ops.py index fbdaae125..4fa475b27 100644 --- a/tests/quantization/test_quantized_ops.py +++ b/tests/quantization/test_quantized_ops.py @@ -1993,56 +1993,48 @@ def test_quantized_shape(shape): (3, 3), (2, 2), (0, 0, 0, 0), - 0, ), ( numpy.random.uniform(low=-1.2, high=0.2, size=(10, 1, 16, 16)), (2, 2), (1, 1), (0, 0, 0, 0), - 0, ), ( numpy.random.uniform(low=-2.0, high=2.0, size=(2, 32, 4, 4)), (2, 2), (1, 1), (0, 0, 0, 0), - 0, ), ( numpy.random.uniform(low=-2.0, high=2.0, size=(2, 32, 4, 4)), (2, 4), (1, 1), (1, 2, 1, 2), - 1, ), ( numpy.random.uniform(low=-2.0, high=2.0, size=(2, 32, 4, 4)), (2, 4), (1, 1), (0, 2, 0, 2), - 1, ), ( numpy.random.uniform(low=-2.0, high=2.0, size=(2, 32, 5, 5)), (3, 3), (1, 1), (1, 1, 1, 1), - 1, ), ( numpy.random.uniform(low=-2.0, high=2.0, size=(2, 1, 7, 5)), (5, 1), (1, 1), (1, 2, 0, 4), - 1, ), - ( # this test fails because of padding + ( numpy.random.uniform(low=-2.0, high=2.0, size=(1, 1, 16, 16)), (2, 2), (4, 4), (1, 2, 0, 4), - 1, ), ], ) @@ -2051,7 +2043,7 @@ def test_quantized_unfold(params, n_bits, is_signed, check_r2_score, check_float """Test the quantized average pool operator.""" # Retrieve arguments - net_input, kernel_shape, strides, pads, ceil_mode = params + net_input, kernel_shape, strides, pads = params # Create quantized data q_input = QuantizedArray(n_bits, net_input, is_signed=is_signed) @@ -2062,7 +2054,7 @@ def test_quantized_unfold(params, n_bits, is_signed, check_r2_score, check_float strides=strides, pads=pads, kernel_shape=kernel_shape, - ceil_mode=ceil_mode, + # ceil_mode=ceil_mode, input_quant_opts=q_input.quantizer.quant_options, )