tflite: Compute numbers in float16 to match the NPU behavior If we compute numbers in float32, the error will accumulate, so there are chances that it eventually exceed the threshold. For example, when computing 0.375732 + 0.298828 - 0.641113 in float32, the result is 0.0334473, but it will be 0.0336914 in float16. Note that 0.375732 + 0.298828 = 0.674561(fp32) or 0.674805(fp16). To address the issue, we compute numbers in float16 to mimic the same calculation in NPU. BUG=b:430326201 TEST=`./async_delegate_test --stable_delegate_settings_file=/etc/ml_core/stable_delegate_settings.json;` on screebo and hylia passes 3000 times. Change-Id: Iea8c46ce83150cc592ddb8c114287b00f63ab67f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tflite/+/6719772 Auto-Submit: Tommy Chiang <ototot@google.com> Commit-Queue: Shik Chen <shik@chromium.org> Tested-by: Tommy Chiang <ototot@google.com> Reviewed-by: Shik Chen <shik@chromium.org>
diff --git a/common/async_delegate_test.cc b/common/async_delegate_test.cc index 2db4a1d..8015a97 100644 --- a/common/async_delegate_test.cc +++ b/common/async_delegate_test.cc
@@ -6,6 +6,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> + #include <vector> #include "absl/random/random.h" @@ -112,10 +113,19 @@ std::vector<float> c_data(n); std::vector<float> d_data(n); for (int i = 0; i < n; ++i) { - a_data[i] = absl::Uniform(gen, 0.0, 1.0); - b_data[i] = absl::Uniform(gen, 0.0, 1.0); - c_data[i] = absl::Uniform(gen, 0.0, 1.0); - d_data[i] = a_data[i] + b_data[i] - c_data[i]; + // Limit the input precision to float16 since we are comparing the + // computation in fp16. + const _Float16 a = absl::Uniform(gen, 0.0, 1.0); + const _Float16 b = absl::Uniform(gen, 0.0, 1.0); + const _Float16 c = absl::Uniform(gen, 0.0, 1.0); + // If we do not cast back to float16 first, the result will be casted back + // to float16 only after the full computation. + const _Float16 d = static_cast<_Float16>(a + b) - c; + + a_data[i] = a; + b_data[i] = b; + c_data[i] = c; + d_data[i] = d; } EXPECT_EQ(driver->SetInputTensorData("a", a_data), kTfLiteOk); EXPECT_EQ(driver->SetInputTensorData("b", b_data), kTfLiteOk);
diff --git a/common/sync_driver_test.cc b/common/sync_driver_test.cc index e2efb2a..b75b307 100644 --- a/common/sync_driver_test.cc +++ b/common/sync_driver_test.cc
@@ -6,6 +6,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> + #include <vector> #include "absl/random/random.h" @@ -84,10 +85,19 @@ std::vector<float> c_data(n); std::vector<float> d_data(n); for (int i = 0; i < n; ++i) { - a_data[i] = absl::Uniform(gen, 0.0, 1.0); - b_data[i] = absl::Uniform(gen, 0.0, 1.0); - c_data[i] = absl::Uniform(gen, 0.0, 1.0); - d_data[i] = a_data[i] + b_data[i] - c_data[i]; + // Limit the input precision to float16 since we are comparing the + // computation in fp16. + const _Float16 a = absl::Uniform(gen, 0.0, 1.0); + const _Float16 b = absl::Uniform(gen, 0.0, 1.0); + const _Float16 c = absl::Uniform(gen, 0.0, 1.0); + // If we do not cast back to float16 first, the result will be casted back + // to float16 only after the full computation. + const _Float16 d = static_cast<_Float16>(a + b) - c; + + a_data[i] = a; + b_data[i] = b; + c_data[i] = c; + d_data[i] = d; } EXPECT_EQ(driver->SetInputTensorData("a", a_data), kTfLiteOk); EXPECT_EQ(driver->SetInputTensorData("b", b_data), kTfLiteOk);