summaryrefslogtreecommitdiff
path: root/nn
diff options
context:
space:
mode:
authorXusong Wang <xusongw@google.com>2020-04-22 20:15:52 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-04-22 20:15:52 +0000
commit4771108bc09751db04c64971473dd4f4d5cebbf7 (patch)
tree904b85fe6da1ba9e50620d06101b667ba1adbcc2 /nn
parent4c9cf95a1684d43bdd7e7c07059f3d41743a6138 (diff)
parentb822394e13b92f22422fad8c5a3a7dbca214b40d (diff)
downloadml-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')
-rw-r--r--nn/runtime/test/fuzzing/operation_signatures/Selection.cpp9
-rw-r--r--nn/tools/test_generator/test_harness/TestHarness.cpp98
-rw-r--r--nn/tools/test_generator/test_harness/include/TestHarness.h5
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;