def test_invalid_inputs(self): input_value = constant_op.constant([-0.8, -0.5, 0, 0.3, 0.8, -2.0], shape=(6, ), dtype=dtypes.float32), input_min = constant_op.constant(-127, shape=(), dtype=dtypes.float32) input_max = constant_op.constant(127, shape=(), dtype=dtypes.float32) # Tensor with invalid shape and invalid number of elements. num_bits = constant_op.constant([], shape=(0, ), dtype=dtypes.int32) # Test that running the op raises error. It raises different errors # depending on whether the shape inference is run first or the op's # Compute() is run first. try: array_ops.quantize_and_dequantize_v3(input_value, input_min, input_max, num_bits, signed_input=True) except Exception as ex: # pylint: disable=broad-except if isinstance(ex, errors.InvalidArgumentError): self.assertRegex(str(ex), "The `num_bits` tensor should be a scalar.") elif isinstance(ex, ValueError): self.assertRegex(str(ex), "Shape must be rank 0") else: self.fail( "Raised exception other than expected: %s. " "Expected exceptions are errors.InvalidArgumentError or ValueError", ex.__name__) else: self.fail( "Did not raise an exception where it is expected to raise either " "a ValueError or errors.InvalidArgumentError.")
def quantize_and_dequantize_v3(x): return array_ops.quantize_and_dequantize_v3(x, -127, 127, num_bits=8, signed_input=True, range_given=False)
def _FakeQuantWithMinMaxVars(inputs, min_var, max_var, per_channel, num_bits, narrow_range, use_qdq=False): """Adds a fake quantization operation. Depending on value of per_channel, this operation may do global quantization or per channel quantization. min_var and max_var should have corresponding shapes: [1] when per_channel == False and [d] when per_channel == True. Args: inputs: a tensor containing values to be quantized. min_var: a variable containing quantization range lower end(s). max_var: a variable containing quantization range upper end(s). per_channel: a boolean specifying whether to use per-channel quantization. num_bits: Number of bits to use for quantization, must be between 2 and 8. narrow_range: Whether to use the narrow quantization range [1; 2^num_bits - 1] or wide range [0; 2^num_bits - 1]. use_qdq: Use tf.quantize_and_dequantize_v3 op instead of fake_quant_with_min_max_vars for quantization. The qdq op is used for scaling with no zero point. Returns: a tensor containing quantized values. """ if per_channel: assert len(min_var.get_shape()) == 1 assert len(max_var.get_shape()) == 1 return array_ops.fake_quant_with_min_max_vars_per_channel( inputs, min_var, max_var, num_bits=num_bits, narrow_range=narrow_range) else: assert min_var.get_shape() == [] # pylint: disable=g-explicit-bool-comparison assert max_var.get_shape() == [] # pylint: disable=g-explicit-bool-comparison if use_qdq: return array_ops.quantize_and_dequantize_v3(inputs, min_var, max_var, num_bits=num_bits) return array_ops.fake_quant_with_min_max_vars( inputs, min_var, max_var, num_bits=num_bits, narrow_range=narrow_range)
def test_valid(self): with ops.Graph().as_default(), context.eager_mode(): input_value = constant_op.constant([-0.8, -0.5, 0, 0.3, 0.8, -2.0], shape=(6, ), dtype=dtypes.float32), input_min = constant_op.constant(-127, shape=(), dtype=dtypes.float32) input_max = constant_op.constant(127, shape=(), dtype=dtypes.float32) num_bits = constant_op.constant(8, shape=(), dtype=dtypes.int32) quantized = array_ops.quantize_and_dequantize_v3(input_value, input_min, input_max, num_bits, signed_input=True, range_given=False) self.assertSequenceAlmostEqual(input_value[0].numpy(), quantized.numpy()[0], delta=0.05)
def quantize_and_dequantize_v3(x): return array_ops.quantize_and_dequantize_v3( x, -127, 127, num_bits=8, signed_input=True, range_given=False)