/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include // Declares the operator #include #include #include #include #include #include #include using namespace ::testing; using exec_aten::ArrayRef; using exec_aten::Scalar; using exec_aten::ScalarType; using exec_aten::Tensor; using torch::executor::native::quantize_per_channel_out; using torch::executor::native::quantize_per_tensor_out; using torch::executor::native::quantize_per_tensor_tensor_args_out; using torch::executor::testing::TensorFactory; /// A generic smoke test that works for any dtype that supports ones() and /// zeros(). template void test_dtype() { TensorFactory tf; Tensor input = tf.full({3, 5}, 4); double scale = 0.5; int64_t zero_point = 108; int64_t quant_min = 0; int64_t quant_max = 127; TensorFactory tfo; Tensor out = tfo.zeros({3, 5}); // 4 / 0.5 + 127 Tensor expected = tfo.full({3, 5}, 116); quantize_per_tensor_out( input, scale, zero_point, quant_min, quant_max, DTYPE, out); EXPECT_TENSOR_EQ(out, expected); } TEST(OpQuantizeOutTest, AllDtypesSupported) { test_dtype(); test_dtype(); test_dtype(); test_dtype(); test_dtype(); test_dtype(); } TEST(OpQuantizeOutTest, TensorArgOverload) { TensorFactory tf_float; TensorFactory tf_double; TensorFactory tf_long; Tensor input = tf_float.full({3, 5}, 4); Tensor scale = tf_double.make({1}, {0.5}); Tensor zero_point = tf_long.make({1}, {127}); int64_t quant_min = 0; int64_t quant_max = 255; TensorFactory tfo; Tensor out = tfo.zeros({3, 5}); // 4 / 0.5 + 127 Tensor expected = tfo.full({3, 5}, 135); auto context = torch::executor::KernelRuntimeContext(); quantize_per_tensor_tensor_args_out( context, input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); EXPECT_TENSOR_EQ(out, expected); } TEST(OpQuantizeOutTest, TestOutOfBounds) { // Test where 1.0 / epsilon is larger than 8bit integer. TensorFactory tf_float; TensorFactory tf_double; TensorFactory tf_long; Tensor input = tf_float.ones({1, 3, 256, 256}); Tensor scale = tf_double.make({1}, {0.0011316323652863503}); Tensor zero_point = tf_long.make({1}, {0}); int64_t quant_min = -128; int64_t quant_max = 127; TensorFactory tfo; Tensor out = tfo.zeros({1, 3, 256, 256}); Tensor expected = tfo.full({1, 3, 256, 256}, 127); auto context = torch::executor::KernelRuntimeContext(); quantize_per_tensor_tensor_args_out( context, input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); EXPECT_TENSOR_EQ(out, expected); } TEST(OpQuantizeOutTest, QuantizePerChannel) { TensorFactory tf_float; TensorFactory tf_double; TensorFactory tf_long; Tensor input = tf_float.full({3, 2}, 4); Tensor scale = tf_double.make({2}, {0.5, 1}); Tensor zero_point = tf_long.make({2}, {127, 63}); int64_t quant_min = 0; int64_t quant_max = 255; TensorFactory tfo; Tensor out = tfo.zeros({3, 2}); // 4 / 0.5 + 127 // 4 / 1 + 63 Tensor expected = tfo.make({3, 2}, {135, 67, 135, 67, 135, 67}); quantize_per_channel_out( input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); EXPECT_TENSOR_EQ(out, expected); }