From 189f748e1a79ed88044efbe7137963bca830cbb5 Mon Sep 17 00:00:00 2001 From: Diqing Zhong Date: Tue, 26 Jan 2021 12:12:51 +0100 Subject: MLBEDSW-3224: Support HardSwish Change-Id: If49abc31f093f1bd3393bee86f821fd35972086f Signed-off-by: Diqing Zhong --- ethosu/vela/test/test_fp_math.py | 78 +++++++++++++++++++--------- ethosu/vela/test/test_supported_operators.py | 23 ++++++++ 2 files changed, 76 insertions(+), 25 deletions(-) (limited to 'ethosu/vela/test') diff --git a/ethosu/vela/test/test_fp_math.py b/ethosu/vela/test/test_fp_math.py index 905826f4..355d3ae6 100644 --- a/ethosu/vela/test/test_fp_math.py +++ b/ethosu/vela/test/test_fp_math.py @@ -64,52 +64,80 @@ EXP_LUT = [ def test_saturating_rounding_mul(): i32info = np.iinfo(np.int32) + i16info = np.iinfo(np.int16) + # Saturation - assert fp_math.saturating_rounding_mul(i32info.min, i32info.min) == i32info.max - assert fp_math.saturating_rounding_mul(i32info.min, i32info.max) == -i32info.max - assert fp_math.saturating_rounding_mul(i32info.max, i32info.min) == -i32info.max + assert fp_math.saturating_rounding_mul32(i32info.min, i32info.min) == i32info.max + assert fp_math.saturating_rounding_mul32(i32info.min, i32info.max) == -i32info.max + assert fp_math.saturating_rounding_mul32(i32info.max, i32info.min) == -i32info.max + + assert fp_math.saturating_rounding_mul16(i16info.min, i16info.min) == i16info.max + assert fp_math.saturating_rounding_mul16(i16info.min, i16info.max) == -i16info.max + assert fp_math.saturating_rounding_mul16(i16info.max, i16info.min) == -i16info.max # Multiply by zero - assert fp_math.saturating_rounding_mul(0, fp_math.from_float(1.0)) == 0 - assert fp_math.saturating_rounding_mul(0, fp_math.from_float(-1.0)) == 0 - assert fp_math.saturating_rounding_mul(fp_math.from_float(1.0), 0) == 0 - assert fp_math.saturating_rounding_mul(fp_math.from_float(-1.0), 0) == 0 + assert fp_math.saturating_rounding_mul32(0, fp_math.from_float(1.0)) == 0 + assert fp_math.saturating_rounding_mul32(0, fp_math.from_float(-1.0)) == 0 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(1.0), 0) == 0 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(-1.0), 0) == 0 + + assert fp_math.saturating_rounding_mul16(0, i16info.max) == 0 + assert fp_math.saturating_rounding_mul16(0, i16info.min) == 0 + assert fp_math.saturating_rounding_mul16(i16info.max, 0) == 0 + assert fp_math.saturating_rounding_mul16(i16info.min, 0) == 0 # Multiply positive/negative - assert fp_math.saturating_rounding_mul(fp_math.from_float(1.0), fp_math.from_float(1.0)) == fp_math.from_float( + assert fp_math.saturating_rounding_mul32(fp_math.from_float(1.0), fp_math.from_float(1.0)) == fp_math.from_float( 1.0, 5 + 5 ) - assert fp_math.saturating_rounding_mul(fp_math.from_float(-1.0), fp_math.from_float(1.0)) == fp_math.from_float( + assert fp_math.saturating_rounding_mul32(fp_math.from_float(-1.0), fp_math.from_float(1.0)) == fp_math.from_float( -1.0, 5 + 5 ) - assert fp_math.saturating_rounding_mul(fp_math.from_float(1.0), fp_math.from_float(-1.0)) == fp_math.from_float( + assert fp_math.saturating_rounding_mul32(fp_math.from_float(1.0), fp_math.from_float(-1.0)) == fp_math.from_float( -1.0, 5 + 5 ) - assert fp_math.saturating_rounding_mul(fp_math.from_float(-1.0), fp_math.from_float(-1.0)) == fp_math.from_float( + assert fp_math.saturating_rounding_mul32(fp_math.from_float(-1.0), fp_math.from_float(-1.0)) == fp_math.from_float( 1.0, 5 + 5 ) # Rounding - assert fp_math.saturating_rounding_mul(fp_math.from_float(16.0), 1) == 1 - assert fp_math.saturating_rounding_mul(fp_math.from_float(-16.0), 1) == 0 - assert fp_math.saturating_rounding_mul(fp_math.from_float(16.0) - 1, 1) == 0 - assert fp_math.saturating_rounding_mul(fp_math.from_float(-16.0) - 1, 1) == -1 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(16.0), 1) == 1 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(-16.0), 1) == 0 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(16.0) - 1, 1) == 0 + assert fp_math.saturating_rounding_mul32(fp_math.from_float(-16.0) - 1, 1) == -1 + + assert fp_math.saturating_rounding_mul16(fp_math.from_float(16.0, 21), 1) == 1 + assert fp_math.saturating_rounding_mul16(fp_math.from_float(-16.0, 21), 1) == 0 + assert fp_math.saturating_rounding_mul16(fp_math.from_float(16.0, 21) - 1, 1) == 0 + assert fp_math.saturating_rounding_mul16(fp_math.from_float(-16.0, 21) - 1, 1) == -1 def test_shift_left(): i32info = np.iinfo(np.int32) - assert fp_math.shift_left(1, i32info.bits) == i32info.max - assert fp_math.shift_left(-1, i32info.bits) == i32info.min - assert fp_math.shift_left(1, i32info.bits - 2) == (i32info.max + 1) / 2 - assert fp_math.shift_left(-1, i32info.bits - 2) == i32info.min // 2 - - assert fp_math.shift_left(fp_math.from_float(1.0), 5) == i32info.max - assert fp_math.shift_left(fp_math.from_float(-1.0), 5) == i32info.min - assert fp_math.shift_left(fp_math.from_float(1.0), 4) == 16 * fp_math.from_float(1.0) - assert fp_math.shift_left(fp_math.from_float(-1.0), 4) == 16 * fp_math.from_float(-1.0) + i16info = np.iinfo(np.int16) + assert fp_math.shift_left32(1, i32info.bits) == i32info.max + assert fp_math.shift_left32(-1, i32info.bits) == i32info.min + assert fp_math.shift_left32(1, i32info.bits - 2) == (i32info.max + 1) / 2 + assert fp_math.shift_left32(-1, i32info.bits - 2) == i32info.min // 2 + + assert fp_math.shift_left16(1, i16info.bits) == i16info.max + assert fp_math.shift_left16(-1, i16info.bits) == i16info.min + assert fp_math.shift_left16(1, i16info.bits - 2) == (i16info.max + 1) / 2 + assert fp_math.shift_left16(-1, i16info.bits - 2) == i16info.min // 2 + + assert fp_math.shift_left32(fp_math.from_float(1.0), 5) == i32info.max + assert fp_math.shift_left32(fp_math.from_float(-1.0), 5) == i32info.min + assert fp_math.shift_left32(fp_math.from_float(1.0), 4) == 16 * fp_math.from_float(1.0) + assert fp_math.shift_left32(fp_math.from_float(-1.0), 4) == 16 * fp_math.from_float(-1.0) + + assert fp_math.shift_left16(fp_math.from_float(1.0, 21), 5) == i16info.max + assert fp_math.shift_left16(fp_math.from_float(-1.0, 21), 5) == i16info.min + assert fp_math.shift_left16(fp_math.from_float(1.0, 21), 4) == 16 * fp_math.from_float(1.0, 21) + assert fp_math.shift_left16(fp_math.from_float(-1.0, 21), 4) == 16 * fp_math.from_float(-1.0, 21) with pytest.raises(AssertionError): - fp_math.shift_left(1, -1) + fp_math.shift_left32(1, -1) + fp_math.shift_left16(1, -1) def test_rounding_divide_by_pot(): diff --git a/ethosu/vela/test/test_supported_operators.py b/ethosu/vela/test/test_supported_operators.py index 36213b73..5c01027d 100644 --- a/ethosu/vela/test/test_supported_operators.py +++ b/ethosu/vela/test/test_supported_operators.py @@ -834,3 +834,26 @@ def test_constraint_alpha_valid(): assert support.is_operator_supported(op) op.attrs["alpha"] = -1 assert not support.is_operator_supported(op) + + +def test_constraint_hardswish_dtype(): + # HardSwish operator dtype should be int8 or uint8, and input dtype must match output + # UINT8 + op = testutil.create_op_with_quant_tensors(Op.HardSwish, [1, 8, 8, 8], [1, 8, 8, 8]) + assert support.is_operator_supported(op) + # INT8 + op = testutil.create_op_with_quant_tensors(Op.HardSwish, [1, 8, 8, 8], [1, 8, 8, 8], datatype=DataType.int8) + assert support.is_operator_supported(op) + + # Invalid + op = testutil.create_op_with_quant_tensors(Op.HardSwish, [1, 8, 8, 8], [1, 8, 8, 8], datatype=DataType.int16) + assert not support.is_operator_supported(op) + op = testutil.create_op_with_quant_tensors(Op.HardSwish, [1, 8, 8, 8], [1, 8, 8, 8], datatype=DataType.uint16) + assert not support.is_operator_supported(op) + op = testutil.create_op_with_quant_tensors(Op.HardSwish, [1, 8, 8, 8], [1, 8, 8, 8], datatype=DataType.int32) + assert not support.is_operator_supported(op) + + in_tens = Tensor([1, 8, 8, 8], DataType.int8, "in") + out_tens = Tensor([1, 8, 8, 8], DataType.uint8, "out") + op = testutil.create_op(Op.HardSwish, [in_tens], out_tens) + assert not support.is_operator_supported(op) -- cgit v1.2.1