diff options
author | Xusong Wang <xusongw@google.com> | 2020-04-22 20:15:52 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-04-22 20:15:52 +0000 |
commit | 4771108bc09751db04c64971473dd4f4d5cebbf7 (patch) | |
tree | 904b85fe6da1ba9e50620d06101b667ba1adbcc2 /nn | |
parent | 4c9cf95a1684d43bdd7e7c07059f3d41743a6138 (diff) | |
parent | b822394e13b92f22422fad8c5a3a7dbca214b40d (diff) | |
download | ml-4771108bc09751db04c64971473dd4f4d5cebbf7.tar.gz |
Merge changes I85577481,I43ed11e9 into rvc-dev
* changes:
Add STRIDED_SLICE with shrinkMask in RGG tests.
Increase the fp precision in dumped spec.
Diffstat (limited to 'nn')
3 files changed, 89 insertions, 23 deletions
diff --git a/nn/runtime/test/fuzzing/operation_signatures/Selection.cpp b/nn/runtime/test/fuzzing/operation_signatures/Selection.cpp index 185644092..6d45d0433 100644 --- a/nn/runtime/test/fuzzing/operation_signatures/Selection.cpp +++ b/nn/runtime/test/fuzzing/operation_signatures/Selection.cpp @@ -280,8 +280,7 @@ static void stridedSliceConstructor(TestOperandType, uint32_t rank, RandomOperat setFreeDimensions(op->inputs[0], rank); std::vector<bool> shrinkMask(rank, false); for (uint32_t i = 0; i < rank; i++) { - // TODO: Currently shrinkMask is always set to false. - shrinkMask[i] = false; + shrinkMask[i] = getBernoulli(0.2f); int32_t stride = getUniform<int32_t>(1, 3); op->inputs[3]->value<int32_t>(i) = stride; if (!shrinkMask[i]) { @@ -303,7 +302,8 @@ static void stridedSliceFinalizer(RandomOperation* op) { for (uint32_t i = 0, o = 0; i < rank; i++) { int32_t inputSize = op->inputs[0]->dimensions[i].getValue(); int32_t stride = op->inputs[3]->value<int32_t>(i); - if ((shrinkMask & (1 << i)) == 0) { + bool shrink = shrinkMask & (1 << i); + if (!shrink) { int32_t outputSize = op->outputs[0]->dimensions[o++].getValue(); int32_t maxStart = inputSize - (outputSize - 1) * stride - 1; begin[i] = getUniform<int32_t>(0, maxStart); @@ -328,7 +328,8 @@ static void stridedSliceFinalizer(RandomOperation* op) { } // Switch to negative stride. - if (getBernoulli(0.2f)) { + // TODO(b/154639297): shrinkMask with negative stride will produce uninitialized output. + if (!shrink && getBernoulli(0.2f)) { op->inputs[3]->value<int32_t>(i) = -stride; std::swap(begin[i], end[i]); std::swap(beginMask[i], endMask[i]); diff --git a/nn/tools/test_generator/test_harness/TestHarness.cpp b/nn/tools/test_generator/test_harness/TestHarness.cpp index f37332789..56e1414fe 100644 --- a/nn/tools/test_generator/test_harness/TestHarness.cpp +++ b/nn/tools/test_generator/test_harness/TestHarness.cpp @@ -327,6 +327,21 @@ bool isQuantizedType(TestOperandType type) { return kQuantizedTypes.count(type) > 0; } +bool isFloatType(TestOperandType type) { + static const std::set<TestOperandType> kFloatTypes = { + TestOperandType::TENSOR_FLOAT32, + TestOperandType::TENSOR_FLOAT16, + TestOperandType::FLOAT32, + TestOperandType::FLOAT16, + }; + return kFloatTypes.count(type) > 0; +} + +bool isConstant(TestOperandLifeTime lifetime) { + return lifetime == TestOperandLifeTime::CONSTANT_COPY || + lifetime == TestOperandLifeTime::CONSTANT_REFERENCE; +} + namespace { const char* kOperationTypeNames[] = { @@ -492,11 +507,27 @@ std::string getOperandClassInSpecFile(TestOperandLifeTime lifetime) { } template <typename T> -const auto defaultToStringFunc = [](const T& value) { return std::to_string(value); }; +std::string defaultToStringFunc(const T& value) { + return std::to_string(value); +}; +template <> +std::string defaultToStringFunc<_Float16>(const _Float16& value) { + return defaultToStringFunc(static_cast<float>(value)); +}; +// Dump floating point values in hex representation. +template <typename T> +std::string toHexFloatString(const T& value); +template <> +std::string toHexFloatString<float>(const float& value) { + std::stringstream ss; + ss << "\"" << std::hexfloat << value << "\""; + return ss.str(); +}; template <> -const auto defaultToStringFunc<_Float16> = - [](const _Float16& value) { return std::to_string(static_cast<float>(value)); }; +std::string toHexFloatString<_Float16>(const _Float16& value) { + return toHexFloatString(static_cast<float>(value)); +}; template <typename Iterator, class ToStringFunc> std::string join(const std::string& joint, Iterator begin, Iterator end, ToStringFunc func) { @@ -513,9 +544,15 @@ std::string join(const std::string& joint, const std::vector<T>& range, ToString } template <typename T> -void dumpTestBufferToSpecFileHelper(const TestBuffer& buffer, std::ostream& os) { +void dumpTestBufferToSpecFileHelper(const TestBuffer& buffer, bool useHexFloat, std::ostream& os) { const T* data = buffer.get<T>(); const uint32_t length = buffer.size() / sizeof(T); + if constexpr (nnIsFloat<T>) { + if (useHexFloat) { + os << "from_hex([" << join(", ", data, data + length, toHexFloatString<T>) << "])"; + return; + } + } os << "[" << join(", ", data, data + length, defaultToStringFunc<T>) << "]"; } @@ -530,36 +567,36 @@ const char* toString(TestOperationType type) { } // Dump a test buffer. -void SpecDumper::dumpTestBuffer(TestOperandType type, const TestBuffer& buffer) { +void SpecDumper::dumpTestBuffer(TestOperandType type, const TestBuffer& buffer, bool useHexFloat) { switch (type) { case TestOperandType::FLOAT32: case TestOperandType::TENSOR_FLOAT32: - dumpTestBufferToSpecFileHelper<float>(buffer, mOs); + dumpTestBufferToSpecFileHelper<float>(buffer, useHexFloat, mOs); break; case TestOperandType::INT32: case TestOperandType::TENSOR_INT32: - dumpTestBufferToSpecFileHelper<int32_t>(buffer, mOs); + dumpTestBufferToSpecFileHelper<int32_t>(buffer, useHexFloat, mOs); break; case TestOperandType::TENSOR_QUANT8_ASYMM: - dumpTestBufferToSpecFileHelper<uint8_t>(buffer, mOs); + dumpTestBufferToSpecFileHelper<uint8_t>(buffer, useHexFloat, mOs); break; case TestOperandType::TENSOR_QUANT8_SYMM: case TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED: - dumpTestBufferToSpecFileHelper<int8_t>(buffer, mOs); + dumpTestBufferToSpecFileHelper<int8_t>(buffer, useHexFloat, mOs); break; case TestOperandType::TENSOR_QUANT16_ASYMM: - dumpTestBufferToSpecFileHelper<uint16_t>(buffer, mOs); + dumpTestBufferToSpecFileHelper<uint16_t>(buffer, useHexFloat, mOs); break; case TestOperandType::TENSOR_QUANT16_SYMM: - dumpTestBufferToSpecFileHelper<int16_t>(buffer, mOs); + dumpTestBufferToSpecFileHelper<int16_t>(buffer, useHexFloat, mOs); break; case TestOperandType::BOOL: case TestOperandType::TENSOR_BOOL8: - dumpTestBufferToSpecFileHelper<bool8>(buffer, mOs); + dumpTestBufferToSpecFileHelper<bool8>(buffer, useHexFloat, mOs); break; case TestOperandType::FLOAT16: case TestOperandType::TENSOR_FLOAT16: - dumpTestBufferToSpecFileHelper<_Float16>(buffer, mOs); + dumpTestBufferToSpecFileHelper<_Float16>(buffer, useHexFloat, mOs); break; default: CHECK(false) << "Unknown type when dumping the buffer"; @@ -571,17 +608,29 @@ void SpecDumper::dumpTestOperand(const TestOperand& operand, uint32_t index) { << "\", [\"" << toString(operand.type) << "\", [" << join(", ", operand.dimensions, defaultToStringFunc<uint32_t>) << "]"; if (operand.scale != 0.0f || operand.zeroPoint != 0) { - mOs << ", " << operand.scale << ", " << operand.zeroPoint; + mOs << ", float.fromhex(" << toHexFloatString(operand.scale) << "), " << operand.zeroPoint; } mOs << "]"; if (operand.lifetime == TestOperandLifeTime::CONSTANT_COPY || operand.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) { mOs << ", "; - dumpTestBuffer(operand.type, operand.data); + dumpTestBuffer(operand.type, operand.data, /*useHexFloat=*/true); } else if (operand.lifetime == TestOperandLifeTime::NO_VALUE) { mOs << ", value=None"; } - mOs << ")\n"; + mOs << ")"; + // For quantized data types, append a human-readable scale at the end. + if (operand.scale != 0.0f) { + mOs << " # scale = " << operand.scale; + } + // For float buffers, append human-readable values at the end. + if (isFloatType(operand.type) && + (operand.lifetime == TestOperandLifeTime::CONSTANT_COPY || + operand.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE)) { + mOs << " # "; + dumpTestBuffer(operand.type, operand.data, /*useHexFloat=*/false); + } + mOs << "\n"; } void SpecDumper::dumpTestOperation(const TestOperation& operation) { @@ -593,6 +642,7 @@ void SpecDumper::dumpTestOperation(const TestOperation& operation) { void SpecDumper::dumpTestModel() { CHECK_EQ(kTestModel.referenced.size(), 0u) << "Subgraphs not supported"; + mOs << "from_hex = lambda l: [float.fromhex(i) for i in l]\n\n"; // Dump model operands. mOs << "# Model operands\n"; @@ -614,8 +664,14 @@ void SpecDumper::dumpTestModel() { operand.lifetime != TestOperandLifeTime::SUBGRAPH_OUTPUT) { continue; } + // For float buffers, dump human-readable values as a comment. + if (isFloatType(operand.type)) { + mOs << " # op" << i << ": "; + dumpTestBuffer(operand.type, operand.data, /*useHexFloat=*/false); + mOs << "\n"; + } mOs << " op" << i << ": "; - dumpTestBuffer(operand.type, operand.data); + dumpTestBuffer(operand.type, operand.data, /*useHexFloat=*/true); mOs << ",\n"; } mOs << "}).DisableLifeTimeVariation()\n"; @@ -627,8 +683,14 @@ void SpecDumper::dumpResults(const std::string& name, const std::vector<TestBuff for (uint32_t i = 0; i < results.size(); i++) { const uint32_t outputIndex = kTestModel.main.outputIndexes[i]; const auto& operand = kTestModel.main.operands[outputIndex]; + // For float buffers, dump human-readable values as a comment. + if (isFloatType(operand.type)) { + mOs << " # op" << outputIndex << ": "; + dumpTestBuffer(operand.type, results[i], /*useHexFloat=*/false); + mOs << "\n"; + } mOs << " op" << outputIndex << ": "; - dumpTestBuffer(operand.type, results[i]); + dumpTestBuffer(operand.type, results[i], /*useHexFloat=*/true); mOs << ",\n"; } mOs << "}\n"; diff --git a/nn/tools/test_generator/test_harness/include/TestHarness.h b/nn/tools/test_generator/test_harness/include/TestHarness.h index c67200cd2..ef2dbc87c 100644 --- a/nn/tools/test_generator/test_harness/include/TestHarness.h +++ b/nn/tools/test_generator/test_harness/include/TestHarness.h @@ -531,7 +531,10 @@ class SpecDumper { // Dump a test buffer as a python 1D list. // e.g. [1, 2, 3, 4, 5] - void dumpTestBuffer(TestOperandType type, const TestBuffer& buffer); + // + // If useHexFloat is set to true and the operand type is float, the buffer values will be + // dumped in hex representation. + void dumpTestBuffer(TestOperandType type, const TestBuffer& buffer, bool useHexFloat); const TestModel& kTestModel; std::ostream& mOs; |