1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <algorithm>
20 #include <string>
21
22 #include "TestNeuralNetworksWrapper.h"
23 #include "fuzzing/OperationManager.h"
24 #include "fuzzing/RandomGraphGenerator.h"
25 #include "fuzzing/RandomGraphGeneratorUtils.h"
26
27 #ifndef NNTEST_CTS
28 #include <android-base/properties.h>
29 #include <vector>
30 #include "Manager.h"
31 #include "SampleDriverFull.h"
32
33 using android::nn::sample_driver::SampleDriverFull;
34
35 #endif
36
37 namespace android {
38 namespace nn {
39 namespace fuzzing_test {
40
41 using test_wrapper::Result;
42 constexpr char kRefDeviceName[] = "nnapi-reference";
43
44 #ifndef NNTEST_CTS
45 class TestDriverV1_2 : public SampleDriverFull {
46 public:
TestDriverV1_2()47 TestDriverV1_2() : SampleDriverFull(name, {.execTime = 0.9f, .powerUsage = 0.9f}) {}
48 static constexpr char name[] = "TestDriverV1_2";
49 };
50
51 // Like SampleDriverFull, but implementing 1.1
52 class TestDriverV1_1 : public V1_1::IDevice {
53 public:
TestDriverV1_1()54 TestDriverV1_1()
55 : mDriverV1_2(new SampleDriverFull(name, {.execTime = 0.8f, .powerUsage = 0.8f})) {}
56 static constexpr char name[] = "TestDriverV1_1";
getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb)57 Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override {
58 return mDriverV1_2->getCapabilities_1_1(_hidl_cb);
59 }
getSupportedOperations_1_1(const V1_1::Model & model,getSupportedOperations_1_1_cb _hidl_cb)60 Return<void> getSupportedOperations_1_1(const V1_1::Model& model,
61 getSupportedOperations_1_1_cb _hidl_cb) override {
62 return mDriverV1_2->getSupportedOperations_1_1(model, _hidl_cb);
63 }
prepareModel_1_1(const V1_1::Model & model,ExecutionPreference preference,const sp<V1_0::IPreparedModelCallback> & actualCallback)64 Return<ErrorStatus> prepareModel_1_1(
65 const V1_1::Model& model, ExecutionPreference preference,
66 const sp<V1_0::IPreparedModelCallback>& actualCallback) override {
67 return mDriverV1_2->prepareModel_1_1(model, preference, actualCallback);
68 }
getStatus()69 Return<DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); }
getCapabilities(getCapabilities_cb _hidl_cb)70 Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override {
71 return mDriverV1_2->getCapabilities(_hidl_cb);
72 }
getSupportedOperations(const V1_0::Model & model,getSupportedOperations_cb _hidl_cb)73 Return<void> getSupportedOperations(const V1_0::Model& model,
74 getSupportedOperations_cb _hidl_cb) override {
75 return mDriverV1_2->getSupportedOperations(model, _hidl_cb);
76 }
prepareModel(const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & actualCallback)77 Return<ErrorStatus> prepareModel(
78 const V1_0::Model& model,
79 const sp<V1_0::IPreparedModelCallback>& actualCallback) override {
80 return mDriverV1_2->prepareModel(model, actualCallback);
81 }
82
83 private:
84 const sp<V1_2::IDevice> mDriverV1_2;
85 };
86
87 // Like SampleDriverFull, but implementing 1.0
88 class TestDriverV1_0 : public V1_0::IDevice {
89 public:
TestDriverV1_0()90 TestDriverV1_0()
91 : mDriverV1_2(new SampleDriverFull(name, {.execTime = 0.7f, .powerUsage = 0.7f})) {}
92 static constexpr char name[] = "TestDriverV1_0";
getCapabilities(getCapabilities_cb _hidl_cb)93 Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override {
94 return mDriverV1_2->getCapabilities(_hidl_cb);
95 }
getSupportedOperations(const V1_0::Model & model,getSupportedOperations_cb _hidl_cb)96 Return<void> getSupportedOperations(const V1_0::Model& model,
97 getSupportedOperations_cb _hidl_cb) override {
98 return mDriverV1_2->getSupportedOperations(model, _hidl_cb);
99 }
prepareModel(const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & actualCallback)100 Return<ErrorStatus> prepareModel(
101 const V1_0::Model& model,
102 const sp<V1_0::IPreparedModelCallback>& actualCallback) override {
103 return mDriverV1_2->prepareModel(model, actualCallback);
104 }
getStatus()105 Return<DeviceStatus> getStatus() override { return mDriverV1_2->getStatus(); }
106
107 private:
108 const sp<V1_2::IDevice> mDriverV1_2;
109 };
110
111 template <class T_TestDriver>
makeTestDevice()112 std::shared_ptr<Device> makeTestDevice() {
113 return DeviceManager::forTest_makeDriverDevice(T_TestDriver::name, new T_TestDriver);
114 }
115
116 #endif
117
118 // Manages compilation on one single device.
119 class CompilationForDevice : public test_wrapper::Compilation {
120 public:
121 CompilationForDevice() = default;
122 CompilationForDevice(const CompilationForDevice&) = delete;
123 CompilationForDevice& operator=(const CompilationForDevice&) = delete;
124
initialize(const test_wrapper::Model * model,const ANeuralNetworksDevice * device)125 bool initialize(const test_wrapper::Model* model, const ANeuralNetworksDevice* device) {
126 int ret = ANeuralNetworksCompilation_createForDevices(model->getHandle(), &device, 1,
127 &mCompilation);
128 return ret == ANEURALNETWORKS_NO_ERROR;
129 }
130 };
131
132 // NN API fuzzer logging setting comes from system property debug.nn.fuzzer.log and
133 // debug.nn.fuzzer.dumpspec.
134 // * setprop debug.nn.fuzzer.log 1 : enable logging.
135 // * setprop debug.nn.fuzzer.log 0 : silence logging.
136 // * setprop debug.nn.fuzzer.dumpspec 1 : dump the randomly generated graph to a spec file.
137 // * setprop debug.nn.fuzzer.dumpspec 0 : do not dump the graph.
138 //
139 // Logs and spec files are dumped to /data/local/tmp/${testname}.{log,mod.py},
140 // e.g. for test case TestRandomGraph/RandomGraphTest/Large/0,
141 // log : /data/local/tmp/TestRandomGraph_RandomGraphTest_Large_0.log
142 // spec: /data/local/tmp/TestRandomGraph_RandomGraphTest_Large_0.mod.py
143 //
144 class RandomGraphTest : public ::testing::TestWithParam<uint32_t> {
145 public:
SetUpTestCase()146 static void SetUpTestCase() {
147 #ifndef NNTEST_CTS
148 mEnableLog = ::android::base::GetProperty("debug.nn.fuzzer.log", "") == "1";
149 mDumpSpec = ::android::base::GetProperty("debug.nn.fuzzer.dumpspec", "") == "1";
150
151 mStandardDevices = DeviceManager::get()->forTest_getDevices();
152 mSyntheticDevices.push_back(makeTestDevice<TestDriverV1_2>());
153 mSyntheticDevices.push_back(makeTestDevice<TestDriverV1_1>());
154 mSyntheticDevices.push_back(makeTestDevice<TestDriverV1_0>());
155 #endif
156
157 // Get all the devices and device names.
158 mStandardDevicesFeatureLevel = __ANDROID_API_FUTURE__;
159 uint32_t numDevices = 0;
160 ASSERT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
161 for (uint32_t i = 0; i < numDevices; i++) {
162 ANeuralNetworksDevice* device = nullptr;
163 const char* name = nullptr;
164 int64_t featureLevel;
165 ASSERT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
166 ASSERT_EQ(ANeuralNetworksDevice_getName(device, &name), ANEURALNETWORKS_NO_ERROR);
167 ASSERT_EQ(ANeuralNetworksDevice_getFeatureLevel(device, &featureLevel),
168 ANEURALNETWORKS_NO_ERROR);
169 mDevices.emplace(name, device);
170 mStandardDevicesFeatureLevel = std::min(mStandardDevicesFeatureLevel, featureLevel);
171 }
172 }
173
174 protected:
SetUp()175 virtual void SetUp() override {
176 // Initialize logging.
177 const ::testing::TestInfo* const testInfo =
178 ::testing::UnitTest::GetInstance()->current_test_info();
179 mTestName = mTestName + testInfo->test_case_name() + "_" + testInfo->name();
180 std::replace(mTestName.begin(), mTestName.end(), '/', '_');
181 if (mEnableLog) NN_FUZZER_LOG_INIT("/data/local/tmp/" + mTestName + ".log");
182 }
183
TearDown()184 virtual void TearDown() override {
185 if (::testing::Test::HasFailure() || mDumpSpec) {
186 mGraph.dumpSpecFile("/data/local/tmp/" + mTestName + ".mod.py", mTestName);
187 }
188 NN_FUZZER_LOG_CLOSE;
189 }
190
shouldSkipTest(int64_t featureLevel)191 bool shouldSkipTest(int64_t featureLevel) {
192 static const std::set<std::string> kDisabledTests = {
193 // In this test, the RGG produces a non-sensible graph with extreme large output
194 // gain and highly clamped output range.
195 // TODO: Currently quantized buffer values are uniformly distributed within
196 // [0, 255]. We should investigate on a better buffer value generation
197 // algorithm that represents the real-world cases.
198 "TestRandomGraph_SingleOperationTest_CONV_2D_V1_2_12",
199 };
200 if (kDisabledTests.find(mTestName) != kDisabledTests.end()) return true;
201 if (featureLevel >= __ANDROID_API_Q__) return false;
202 const auto& operations = mGraph.getOperations();
203 for (const auto& op : operations) {
204 // Skip if testing BATCH_TO_SPACE_ND with batch dimension == 1.
205 if (op.opType == ANEURALNETWORKS_BATCH_TO_SPACE_ND &&
206 op.inputs[0]->dimensions[0].getValue() == 1)
207 return true;
208 }
209 return false;
210 }
211
212 // Compile and execute the generated graph on a device selected by name.
computeAndVerifyResultsForDevice(const test_wrapper::Model * model,uint32_t numOps,const std::string & name)213 void computeAndVerifyResultsForDevice(const test_wrapper::Model* model, uint32_t numOps,
214 const std::string& name) {
215 SCOPED_TRACE("Device: " + name);
216 ASSERT_TRUE(mDevices.find(name) != mDevices.end());
217 const auto device = mDevices[name];
218 bool isRef = name.compare(kRefDeviceName) == 0;
219
220 // Check if the device fully supports the graph.
221 constexpr int kMaxNumberOperations = 1000;
222 ASSERT_TRUE(numOps <= kMaxNumberOperations);
223 bool supported[kMaxNumberOperations] = {false};
224 ASSERT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(model->getHandle(), &device,
225 1, supported),
226 ANEURALNETWORKS_NO_ERROR);
227 if (!std::all_of(supported, supported + numOps, [](bool v) { return v; })) {
228 // The reference device should always support all operations.
229 ASSERT_FALSE(isRef);
230 std::cout << "[ ] SKIP: " << name << " does not support the graph.\n";
231 return;
232 }
233
234 // Since this test is introduced in Android Q, we only assert no compilation or execution
235 // failure if the device has feature level >= Q (API level 29). For pre-Q devices, we allow
236 // them to fail with OP_FAILED, but must not hang or crash.
237 int64_t featureLevel;
238 ASSERT_EQ(ANeuralNetworksDevice_getFeatureLevel(device, &featureLevel),
239 ANEURALNETWORKS_NO_ERROR);
240 if (shouldSkipTest(featureLevel)) return;
241
242 // Create compilation for device.
243 CompilationForDevice compilation;
244 ASSERT_TRUE(compilation.initialize(model, device));
245 Result compileReturn = compilation.finish();
246 // Even if the model is fully supported, the compilation may still fail, e.g. each operation
247 // is supported, but model is too big (too many operations and/or too-large constants) for
248 // device.
249 if (compileReturn == Result::OP_FAILED) {
250 ASSERT_FALSE(isRef);
251 std::cout << "[ ] SKIP: " << name << " failed at compilation step.\n";
252 return;
253 }
254 ASSERT_EQ(compileReturn, Result::NO_ERROR);
255
256 // Create request.
257 test_wrapper::Execution execution(&compilation);
258 std::vector<OperandBuffer> outputs;
259 if (isRef) {
260 mGraph.createRequest(&execution);
261 } else {
262 mGraph.createRequest(&execution, &outputs);
263 }
264
265 // Compute result.
266 Result executeReturn = execution.compute();
267 // Even if the model is fully supported and the compilation succeeds, the execution may
268 // still fail, e.g. there may be operand shapes that are unknown until execution time, and
269 // at execution time turn out to be too big.
270 if (executeReturn == Result::OP_FAILED) {
271 ASSERT_FALSE(isRef);
272 std::cout << "[ ] SKIP: " << name << " failed at execution step.\n";
273 return;
274 }
275 ASSERT_EQ(executeReturn, Result::NO_ERROR);
276 if (featureLevel >= __ANDROID_API_Q__ && !isRef) {
277 mGraph.checkResults(outputs, mCriteria);
278 }
279 }
280
281 // Compile and execute the generated graph normally (i.e., allow runtime to
282 // distribute across devices).
computeAndVerifyResults(const test_wrapper::Model * model,bool checkResults)283 void computeAndVerifyResults(const test_wrapper::Model* model, bool checkResults) {
284 // Because we're not using the introspection/control API, the CpuDevice
285 // is available as a fallback, and hence we assume that compilation and
286 // execution will succeed.
287
288 // Create compilation.
289 test_wrapper::Compilation compilation(model);
290 ASSERT_EQ(compilation.finish(), Result::NO_ERROR);
291
292 // Create request.
293 test_wrapper::Execution execution(&compilation);
294 std::vector<OperandBuffer> outputs;
295 mGraph.createRequest(&execution, &outputs);
296
297 // Compute and verify result.
298 ASSERT_EQ(execution.compute(), Result::NO_ERROR);
299 if (checkResults) {
300 mGraph.checkResults(outputs, mCriteria);
301 }
302 }
303
304 // Main test entrance.
testRandomGraph(uint32_t numOperations,uint32_t dimensionRange)305 void testRandomGraph(uint32_t numOperations, uint32_t dimensionRange) {
306 // Generate a random graph.
307 ASSERT_TRUE(mGraph.generate(kSeed, numOperations, dimensionRange));
308
309 // Create a model from the random graph.
310 test_wrapper::Model model;
311 mGraph.createModel(&model);
312 ASSERT_TRUE(model.isValid());
313 ASSERT_EQ(model.finish(), Result::NO_ERROR);
314
315 // Compute reference result.
316 computeAndVerifyResultsForDevice(&model, numOperations, kRefDeviceName);
317
318 // Compute on each available device.
319 for (auto& pair : mDevices) {
320 // Skip the nnapi reference device.
321 if (pair.first.compare(kRefDeviceName) == 0) continue;
322 computeAndVerifyResultsForDevice(&model, numOperations, pair.first);
323 }
324
325 if (numOperations > 1) {
326 if (!shouldSkipTest(mStandardDevicesFeatureLevel)) {
327 // Compute normally (i.e., allow runtime to distribute across
328 // devices).
329 SCOPED_TRACE("Compute normally");
330 computeAndVerifyResults(&model, mStandardDevicesFeatureLevel >= __ANDROID_API_Q__);
331 }
332
333 #ifndef NNTEST_CTS
334 {
335 // Stress partitioner by allowing runtime to distribute across
336 // three synthetic devices. The synthetic devices use the
337 // CpuExecutor for execution, so we always check results, even
338 // though some are of feature level < __ANDROID_API_Q__: In this
339 // case, we don't take feature level as an indication of
340 // reliability, as we do with real devices.
341 SCOPED_TRACE("Compute across synthetic devices");
342 DeviceManager::get()->forTest_setDevices(mSyntheticDevices);
343 computeAndVerifyResults(&model, true);
344 DeviceManager::get()->forTest_setDevices(mStandardDevices);
345 }
346 #endif
347 }
348 }
349
350 enum GraphSize : uint32_t { SINGLE = 1, SMALL = 5, LARGE = 40 };
351 enum DimensionRange : uint32_t { NARROW = 10, WIDE = 1000 };
352
353 static bool mEnableLog;
354 static bool mDumpSpec;
355 static std::map<std::string, ANeuralNetworksDevice*> mDevices;
356
357 const uint32_t kSeed = GetParam();
358 std::string mTestName;
359 RandomGraph mGraph;
360 AccuracyCriteria mCriteria;
361
362 static int64_t mStandardDevicesFeatureLevel; // minimum across all devices
363 #ifndef NNTEST_CTS
364 static std::vector<std::shared_ptr<Device>> mStandardDevices;
365 static std::vector<std::shared_ptr<Device>> mSyntheticDevices;
366 #endif
367 };
368
369 bool RandomGraphTest::mEnableLog = false;
370 bool RandomGraphTest::mDumpSpec = false;
371 std::map<std::string, ANeuralNetworksDevice*> RandomGraphTest::mDevices;
372
373 int64_t RandomGraphTest::mStandardDevicesFeatureLevel;
374 #ifndef NNTEST_CTS
375 std::vector<std::shared_ptr<Device>> RandomGraphTest::mStandardDevices;
376 std::vector<std::shared_ptr<Device>> RandomGraphTest::mSyntheticDevices;
377 #endif
378
379 // Single-op graph with dimensions in range [1, 1000].
380 class SingleOperationTest : public RandomGraphTest {};
381 #define TEST_SINGLE_OPERATION(operation, halVersion, criteria) \
382 TEST_P(SingleOperationTest, operation##_##halVersion) { \
383 OperationFilter filter = {.opcodes = {ANEURALNETWORKS_##operation}, \
384 .versions = {HalVersion::halVersion}}; \
385 OperationManager::get()->applyFilter(filter); \
386 mCriteria = (criteria); \
387 testRandomGraph(GraphSize::SINGLE, DimensionRange::WIDE); \
388 }
389
390 // TODO: Adjust the accuracy criteria based on testing.
391 // We define three sets of accuracy criteria for single-operation tests.
392
393 // This is for operations that only copy buffers around without any computation on buffer values.
394 // Most of these operations fall into categories of reshape or selection, e.g. RESHAPE, GATHER.
395 // Additionally, operations with only logical or comparison arithmetic also use this criteria, e.g.
396 // EQUAL, ARGMAX, TOPK_V2.
397 const AccuracyCriteria kStrictCriteria = {
398 .float32 = {.atol = 1e-6f, .rtol = 1e-6f, .bias = 1e-7f, .mse = 1e-10f},
399 .float16 = {.atol = 1e-3f, .rtol = 1e-3f, .bias = 1e-4f, .mse = 1e-8f},
400 .int32 = {.atol = 1},
401 .quant8Asymm = {.atol = 1, .bias = 0.1f, .mse = 0.1f},
402 .quant8Symm = {.atol = 1, .bias = 0.1f, .mse = 0.1f},
403 .quant16Asymm = {.atol = 1, .bias = 0.1f, .mse = 0.1f},
404 .quant16Symm = {.atol = 1, .bias = 0.1f, .mse = 0.1f}};
405
406 // This is for operations that only do simple and single computation on buffer values, such as
407 // addition, multiplication, or requantization. Most of these operations fall into categories of
408 // broadcast or elementwise, e.g ADD, FLOOR.
409 const AccuracyCriteria kMediumCriteria = {
410 .float32 = {.atol = 1e-5f, .rtol = 1e-5f, .bias = 1e-6f, .mse = 1e-8f},
411 .float16 = {.atol = 1e-2f, .rtol = 1e-2f, .bias = 1e-3f, .mse = 1e-6f},
412 .int32 = {.atol = 1},
413 .quant8Asymm = {.atol = 2, .bias = 0.5f, .mse = 0.5f},
414 .quant8Symm = {.atol = 2, .bias = 0.5f, .mse = 0.5f},
415 .quant16Asymm = {.atol = 2, .bias = 0.5f, .mse = 0.5f},
416 .quant16Symm = {.atol = 2, .bias = 0.5f, .mse = 0.5f}};
417
418 // This is for operations that involve sophisticated computations on buffer values, either a single
419 // but complex transformation, e.g. LOGISTIC, or multiple transformations with accumulated errors,
420 // e.g. CONV_2D, REDUCE_*.
421 const AccuracyCriteria kRelaxedCriteria = {
422 .float32 = {.atol = 1e-3f, .rtol = 1e-3f, .bias = 2e-5f, .mse = 1e-7f},
423 .float16 = {.atol = 1.0f, .rtol = 1.0f, .bias = 5e-3f, .mse = 1e-4f},
424 .int32 = {.atol = 1},
425 .quant8Asymm = {.atol = 10, .bias = 1.5, .mse = 1.5},
426 .quant8Symm = {.atol = 10, .bias = 1.5, .mse = 1.5},
427 .quant16Asymm = {.atol = 10, .bias = 1.5, .mse = 1.5},
428 .quant16Symm = {.atol = 10, .bias = 1.5, .mse = 1.5}};
429
430 /*-- NNAPI 1.0 Operations ---------------------------------------------------*/
431
432 // TODO: The following 1.0 operation signatures are currently not defined:
433 // - ANEURALNETWORKS_LSH_PROJECTION
434 // - ANEURALNETWORKS_LSTM
435 // - ANEURALNETWORKS_RNN
436 // - ANEURALNETWORKS_SVDF
437
438 TEST_SINGLE_OPERATION(ADD, V1_0, kMediumCriteria);
439 TEST_SINGLE_OPERATION(MUL, V1_0, kMediumCriteria);
440 TEST_SINGLE_OPERATION(FLOOR, V1_0, kMediumCriteria);
441 TEST_SINGLE_OPERATION(LOGISTIC, V1_0, kRelaxedCriteria);
442 TEST_SINGLE_OPERATION(RELU, V1_0, kMediumCriteria);
443 TEST_SINGLE_OPERATION(RELU1, V1_0, kMediumCriteria);
444 TEST_SINGLE_OPERATION(RELU6, V1_0, kMediumCriteria);
445 TEST_SINGLE_OPERATION(TANH, V1_0, kRelaxedCriteria);
446 TEST_SINGLE_OPERATION(SOFTMAX, V1_0, kRelaxedCriteria);
447 TEST_SINGLE_OPERATION(L2_NORMALIZATION, V1_0, kRelaxedCriteria);
448 TEST_SINGLE_OPERATION(LOCAL_RESPONSE_NORMALIZATION, V1_0, kRelaxedCriteria);
449 TEST_SINGLE_OPERATION(AVERAGE_POOL_2D, V1_0, kRelaxedCriteria);
450 TEST_SINGLE_OPERATION(L2_POOL_2D, V1_0, kRelaxedCriteria);
451 TEST_SINGLE_OPERATION(MAX_POOL_2D, V1_0, kRelaxedCriteria);
452 TEST_SINGLE_OPERATION(CONV_2D, V1_0, kRelaxedCriteria);
453 TEST_SINGLE_OPERATION(DEPTHWISE_CONV_2D, V1_0, kRelaxedCriteria);
454 TEST_SINGLE_OPERATION(CONCATENATION, V1_0, kMediumCriteria);
455 TEST_SINGLE_OPERATION(RESIZE_BILINEAR, V1_0, kRelaxedCriteria);
456 TEST_SINGLE_OPERATION(DEPTH_TO_SPACE, V1_0, kStrictCriteria);
457 TEST_SINGLE_OPERATION(SPACE_TO_DEPTH, V1_0, kStrictCriteria);
458 TEST_SINGLE_OPERATION(EMBEDDING_LOOKUP, V1_0, kStrictCriteria);
459 TEST_SINGLE_OPERATION(HASHTABLE_LOOKUP, V1_0, kStrictCriteria);
460 TEST_SINGLE_OPERATION(FULLY_CONNECTED, V1_0, kRelaxedCriteria);
461 TEST_SINGLE_OPERATION(RESHAPE, V1_0, kStrictCriteria);
462 TEST_SINGLE_OPERATION(DEQUANTIZE, V1_0, kMediumCriteria);
463
464 /*-- NNAPI 1.1 Operations ---------------------------------------------------*/
465
466 TEST_SINGLE_OPERATION(SUB, V1_1, kMediumCriteria);
467 TEST_SINGLE_OPERATION(DIV, V1_1, kRelaxedCriteria);
468 TEST_SINGLE_OPERATION(BATCH_TO_SPACE_ND, V1_1, kStrictCriteria);
469 TEST_SINGLE_OPERATION(SPACE_TO_BATCH_ND, V1_1, kStrictCriteria);
470 TEST_SINGLE_OPERATION(MEAN, V1_1, kRelaxedCriteria);
471 TEST_SINGLE_OPERATION(PAD, V1_1, kStrictCriteria);
472 TEST_SINGLE_OPERATION(TRANSPOSE, V1_1, kStrictCriteria);
473 TEST_SINGLE_OPERATION(SQUEEZE, V1_1, kStrictCriteria);
474 TEST_SINGLE_OPERATION(STRIDED_SLICE, V1_1, kStrictCriteria);
475
476 /*-- NNAPI 1.0 and 1.1 Operations with Extended Behavior in 1.2 -------------*/
477
478 TEST_SINGLE_OPERATION(ADD, V1_2, kMediumCriteria);
479 TEST_SINGLE_OPERATION(MUL, V1_2, kMediumCriteria);
480 TEST_SINGLE_OPERATION(SUB, V1_2, kMediumCriteria);
481 TEST_SINGLE_OPERATION(DIV, V1_2, kRelaxedCriteria);
482 TEST_SINGLE_OPERATION(FLOOR, V1_2, kMediumCriteria);
483 TEST_SINGLE_OPERATION(LOGISTIC, V1_2, kRelaxedCriteria);
484 TEST_SINGLE_OPERATION(RELU, V1_2, kMediumCriteria);
485 TEST_SINGLE_OPERATION(RELU1, V1_2, kMediumCriteria);
486 TEST_SINGLE_OPERATION(RELU6, V1_2, kMediumCriteria);
487 TEST_SINGLE_OPERATION(TANH, V1_2, kRelaxedCriteria);
488 TEST_SINGLE_OPERATION(CONCATENATION, V1_2, kMediumCriteria);
489 TEST_SINGLE_OPERATION(DEPTH_TO_SPACE, V1_2, kStrictCriteria);
490 TEST_SINGLE_OPERATION(SPACE_TO_DEPTH, V1_2, kStrictCriteria);
491 TEST_SINGLE_OPERATION(BATCH_TO_SPACE_ND, V1_2, kStrictCriteria);
492 TEST_SINGLE_OPERATION(SPACE_TO_BATCH_ND, V1_2, kStrictCriteria);
493 TEST_SINGLE_OPERATION(FULLY_CONNECTED, V1_2, kRelaxedCriteria);
494 TEST_SINGLE_OPERATION(RESHAPE, V1_2, kStrictCriteria);
495 TEST_SINGLE_OPERATION(MEAN, V1_2, kRelaxedCriteria);
496 TEST_SINGLE_OPERATION(PAD, V1_2, kStrictCriteria);
497 TEST_SINGLE_OPERATION(TRANSPOSE, V1_2, kStrictCriteria);
498 TEST_SINGLE_OPERATION(CONV_2D, V1_2, kRelaxedCriteria);
499 TEST_SINGLE_OPERATION(DEPTHWISE_CONV_2D, V1_2, kRelaxedCriteria);
500 TEST_SINGLE_OPERATION(AVERAGE_POOL_2D, V1_2, kRelaxedCriteria);
501 TEST_SINGLE_OPERATION(L2_POOL_2D, V1_2, kRelaxedCriteria);
502 TEST_SINGLE_OPERATION(MAX_POOL_2D, V1_2, kRelaxedCriteria);
503 TEST_SINGLE_OPERATION(RESIZE_BILINEAR, V1_2, kRelaxedCriteria);
504 TEST_SINGLE_OPERATION(SOFTMAX, V1_2, kRelaxedCriteria);
505 TEST_SINGLE_OPERATION(L2_NORMALIZATION, V1_2, kRelaxedCriteria);
506 TEST_SINGLE_OPERATION(LOCAL_RESPONSE_NORMALIZATION, V1_2, kRelaxedCriteria);
507 TEST_SINGLE_OPERATION(DEQUANTIZE, V1_2, kMediumCriteria);
508 TEST_SINGLE_OPERATION(SQUEEZE, V1_2, kStrictCriteria);
509 TEST_SINGLE_OPERATION(STRIDED_SLICE, V1_2, kStrictCriteria);
510
511 /*-- NNAPI 1.2 Operations ---------------------------------------------------*/
512
513 // TODO: The following 1.2 operation signatures are currently not defined:
514 // - ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM
515 // - ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM
516 // - ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN
517 // - ANEURALNETWORKS_BOX_WITH_NMS_LIMIT
518 // - ANEURALNETWORKS_DETECTION_POSTPROCESSING
519 // - ANEURALNETWORKS_GENERATE_PROPOSALS
520 // - ANEURALNETWORKS_QUANTIZED_16BIT_LSTM
521 // - ANEURALNETWORKS_RANDOM_MULTINOMIAL
522 // - ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM
523 // - ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN
524
525 TEST_SINGLE_OPERATION(ABS, V1_2, kMediumCriteria);
526 TEST_SINGLE_OPERATION(EXP, V1_2, kRelaxedCriteria);
527 TEST_SINGLE_OPERATION(LOG, V1_2, kRelaxedCriteria);
528 TEST_SINGLE_OPERATION(NEG, V1_2, kMediumCriteria);
529 TEST_SINGLE_OPERATION(RSQRT, V1_2, kRelaxedCriteria);
530 TEST_SINGLE_OPERATION(SIN, V1_2, kRelaxedCriteria);
531 TEST_SINGLE_OPERATION(SQRT, V1_2, kRelaxedCriteria);
532 TEST_SINGLE_OPERATION(ARGMAX, V1_2, kStrictCriteria);
533 TEST_SINGLE_OPERATION(ARGMIN, V1_2, kStrictCriteria);
534 TEST_SINGLE_OPERATION(EQUAL, V1_2, kStrictCriteria);
535 TEST_SINGLE_OPERATION(GREATER, V1_2, kStrictCriteria);
536 TEST_SINGLE_OPERATION(GREATER_EQUAL, V1_2, kStrictCriteria);
537 TEST_SINGLE_OPERATION(LESS, V1_2, kStrictCriteria);
538 TEST_SINGLE_OPERATION(LESS_EQUAL, V1_2, kStrictCriteria);
539 TEST_SINGLE_OPERATION(LOGICAL_AND, V1_2, kStrictCriteria);
540 TEST_SINGLE_OPERATION(LOGICAL_NOT, V1_2, kStrictCriteria);
541 TEST_SINGLE_OPERATION(LOGICAL_OR, V1_2, kStrictCriteria);
542 TEST_SINGLE_OPERATION(NOT_EQUAL, V1_2, kStrictCriteria);
543 TEST_SINGLE_OPERATION(MAXIMUM, V1_2, kMediumCriteria);
544 TEST_SINGLE_OPERATION(MINIMUM, V1_2, kMediumCriteria);
545 TEST_SINGLE_OPERATION(POW, V1_2, kRelaxedCriteria);
546 TEST_SINGLE_OPERATION(PRELU, V1_2, kMediumCriteria);
547 TEST_SINGLE_OPERATION(REDUCE_ALL, V1_2, kRelaxedCriteria);
548 TEST_SINGLE_OPERATION(REDUCE_ANY, V1_2, kRelaxedCriteria);
549 TEST_SINGLE_OPERATION(REDUCE_MAX, V1_2, kRelaxedCriteria);
550 TEST_SINGLE_OPERATION(REDUCE_MIN, V1_2, kRelaxedCriteria);
551 TEST_SINGLE_OPERATION(REDUCE_PROD, V1_2, kRelaxedCriteria);
552 TEST_SINGLE_OPERATION(REDUCE_SUM, V1_2, kRelaxedCriteria);
553 TEST_SINGLE_OPERATION(CHANNEL_SHUFFLE, V1_2, kStrictCriteria);
554 TEST_SINGLE_OPERATION(INSTANCE_NORMALIZATION, V1_2, kRelaxedCriteria);
555 TEST_SINGLE_OPERATION(LOG_SOFTMAX, V1_2, kRelaxedCriteria);
556 TEST_SINGLE_OPERATION(GROUPED_CONV_2D, V1_2, kRelaxedCriteria);
557 TEST_SINGLE_OPERATION(TRANSPOSE_CONV_2D, V1_2, kRelaxedCriteria);
558 TEST_SINGLE_OPERATION(RESIZE_NEAREST_NEIGHBOR, V1_2, kRelaxedCriteria);
559 TEST_SINGLE_OPERATION(PAD_V2, V1_2, kStrictCriteria);
560 TEST_SINGLE_OPERATION(QUANTIZE, V1_2, kMediumCriteria);
561 TEST_SINGLE_OPERATION(CAST, V1_2, kMediumCriteria);
562 TEST_SINGLE_OPERATION(EXPAND_DIMS, V1_2, kStrictCriteria);
563 TEST_SINGLE_OPERATION(TILE, V1_2, kStrictCriteria);
564 TEST_SINGLE_OPERATION(GATHER, V1_2, kStrictCriteria);
565 TEST_SINGLE_OPERATION(SELECT, V1_2, kStrictCriteria);
566 TEST_SINGLE_OPERATION(TOPK_V2, V1_2, kStrictCriteria);
567 TEST_SINGLE_OPERATION(SLICE, V1_2, kStrictCriteria);
568 TEST_SINGLE_OPERATION(SPLIT, V1_2, kMediumCriteria);
569 TEST_SINGLE_OPERATION(ROI_ALIGN, V1_2, kRelaxedCriteria);
570 TEST_SINGLE_OPERATION(ROI_POOLING, V1_2, kRelaxedCriteria);
571 TEST_SINGLE_OPERATION(HEATMAP_MAX_KEYPOINT, V1_2, kRelaxedCriteria);
572
573 const AccuracyCriteria kSmallGraphCriteria = {
574 .float32 = {.atol = 1e-2f, .rtol = 1e-2f, .bias = 2e-5f, .mse = 1e-7f},
575 .float16 = {.atol = 1.0f, .rtol = 1.0f, .bias = 5e-3f, .mse = 1e-4f},
576 .int32 = {.atol = 1},
577 .quant8Asymm = {.atol = 12, .bias = 2, .mse = 2},
578 .quant8Symm = {.atol = 12, .bias = 2, .mse = 2},
579 .quant16Asymm = {.atol = 12, .bias = 2, .mse = 2},
580 .quant16Symm = {.atol = 12, .bias = 2, .mse = 2}};
581
582 const AccuracyCriteria kLargeGraphCriteria = {
583 .float32 = {.atol = 1e-1f, .rtol = 1e-1f, .bias = 1e-2f, .mse = 1e-4f},
584 .float16 = {.atol = 1.0f, .rtol = 1.0f, .bias = 1e-1f, .mse = 5e-2f},
585 .int32 = {.atol = 1},
586 .quant8Asymm = {.atol = 12, .bias = 2, .mse = 2},
587 .quant8Symm = {.atol = 12, .bias = 2, .mse = 2},
588 .quant16Asymm = {.atol = 12, .bias = 2, .mse = 2},
589 .quant16Symm = {.atol = 12, .bias = 2, .mse = 2}};
590
591 // Due to the limitation of the random graph generator, graphs generated with mixed-type or
592 // mixed-rank operations are likely to result in a disconnected network. Thus, we filter the
593 // operation signatures by primary data type and rank first, then generate random graph tests for
594 // each combination.
595 //
596 // Two parameterized tests are created for each filter:
597 // * 5-op graph with dimensions in range [1, 1000].
598 // * 40-op graph with dimensions in range [1, 10].
599 //
600 #define TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(dataType, rank) \
601 TEST_P(RandomGraphTest, SmallGraph_##dataType##_Rank##rank) { \
602 OperationFilter filter = {.dataTypes = {Type::dataType}, .ranks = {rank}}; \
603 OperationManager::get()->applyFilter(filter); \
604 mCriteria = kSmallGraphCriteria; \
605 testRandomGraph(GraphSize::SMALL, DimensionRange::WIDE); \
606 } \
607 TEST_P(RandomGraphTest, LargeGraph_##dataType##_Rank##rank) { \
608 OperationFilter filter = {.dataTypes = {Type::dataType}, .ranks = {rank}}; \
609 OperationManager::get()->applyFilter(filter); \
610 mCriteria = kLargeGraphCriteria; \
611 testRandomGraph(GraphSize::LARGE, DimensionRange::NARROW); \
612 }
613
614 // Random graph test with TENSOR_QUANT8_ASYMM as the primary data type is currently not defined.
615 // The generated graph with TENSOR_QUANT8_ASYMM as the primary data type will likely to result in
616 // disconnected graphs due to the mismatch between quantized parameters.
617
618 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT32, 4);
619 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT32, 3);
620 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT32, 2);
621 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT32, 1);
622
623 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT16, 4);
624 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT16, 3);
625 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT16, 2);
626 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_FLOAT16, 1);
627
628 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_INT32, 4);
629 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_INT32, 3);
630 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_INT32, 2);
631 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_INT32, 1);
632
633 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_BOOL8, 4);
634 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_BOOL8, 3);
635 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_BOOL8, 2);
636 TEST_RANDOM_GRAPH_WITH_DATA_TYPE_AND_RANK(TENSOR_BOOL8, 1);
637
638 #ifdef NNTEST_CTS
639 INSTANTIATE_TEST_CASE_P(TestRandomGraph, SingleOperationTest, ::testing::Range(0u, 50u));
640 INSTANTIATE_TEST_CASE_P(TestRandomGraph, RandomGraphTest, ::testing::Range(0u, 50u));
641 #else
642 INSTANTIATE_TEST_CASE_P(TestRandomGraph, SingleOperationTest, ::testing::Range(0u, 100u));
643 INSTANTIATE_TEST_CASE_P(TestRandomGraph, RandomGraphTest, ::testing::Range(0u, 100u));
644 #endif
645
646 } // namespace fuzzing_test
647 } // namespace nn
648 } // namespace android
649