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 "RandomGraphGeneratorUtils.h" 18 19 #include <algorithm> 20 #include <iomanip> 21 #include <memory> 22 #include <sstream> 23 #include <string> 24 25 #include "RandomGraphGenerator.h" 26 #include "RandomVariable.h" 27 28 namespace android { 29 namespace nn { 30 namespace fuzzing_test { 31 32 std::mt19937 RandomNumberGenerator::generator; 33 34 std::string Logger::getElapsedTime() { 35 auto end = std::chrono::high_resolution_clock::now(); 36 int ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - mStart).count(); 37 int hour = ms / 3600000; 38 int minutes = (ms % 3600000) / 60000; 39 int seconds = (ms % 60000) / 1000; 40 int milli = ms % 1000; 41 std::ostringstream oss; 42 oss << std::setfill('0') << std::setw(2) << hour << ":" << std::setw(2) << minutes << ":" 43 << std::setw(2) << seconds << "." << std::setw(3) << milli << " "; 44 return oss.str(); 45 } 46 47 SpecWriter::SpecWriter(std::string filename, std::string testname) : os(filename) { 48 if (os.is_open() && testname != "") { 49 os << "# Generated from " << testname << ". Do not edit.\n\n"; 50 } 51 } 52 53 // Main entrance of dumping the spec file. 54 // Check nn/tools/test_generator/README.md for guide on spec file syntax. 55 void SpecWriter::dump(const std::vector<RandomOperation>& operations, 56 const std::vector<std::shared_ptr<RandomOperand>>& operands) { 57 // RandomGraphGenerator does not support dynamic output shape. 58 os << "Configuration.test_dynamic_output_shape = False\n\n"; 59 60 // Dump model operands. 61 os << "# Model operands\n"; 62 for (auto& operand : operands) dump(operand); 63 64 // Dump model operations. 65 os << "\n# Model operations\nmodel = Model()\n"; 66 for (const auto& operation : operations) dump(operation); 67 68 // Dump input/output buffers. 69 os << "\n# Example\n"; 70 os << "Example({\n"; 71 for (auto& operand : operands) { 72 if (operand->type == RandomOperandType::CONST || 73 operand->type == RandomOperandType::INTERNAL) { 74 continue; 75 } 76 os << " op" << operand->opIndex << ": ["; 77 dump(operand->dataType, reinterpret_cast<uint8_t*>(operand->buffer.data()), 78 operand->getNumberOfElements()); 79 os << "],\n"; 80 } 81 os << "})\n"; 82 } 83 84 // Dump an operand buffer. 85 void SpecWriter::dump(test_wrapper::Type type, const uint8_t* buffer, uint32_t length) { 86 if (buffer == nullptr) return; 87 switch (type) { 88 case test_wrapper::Type::FLOAT32: 89 case test_wrapper::Type::TENSOR_FLOAT32: 90 dump(reinterpret_cast<const float*>(buffer), length); 91 break; 92 case test_wrapper::Type::INT32: 93 case test_wrapper::Type::TENSOR_INT32: 94 dump(reinterpret_cast<const int32_t*>(buffer), length); 95 break; 96 case test_wrapper::Type::TENSOR_QUANT8_ASYMM: 97 dump(reinterpret_cast<const uint8_t*>(buffer), length); 98 break; 99 case test_wrapper::Type::TENSOR_QUANT8_SYMM: 100 dump(reinterpret_cast<const int8_t*>(buffer), length); 101 break; 102 case test_wrapper::Type::TENSOR_QUANT16_ASYMM: 103 dump(reinterpret_cast<const uint16_t*>(buffer), length); 104 break; 105 case test_wrapper::Type::TENSOR_QUANT16_SYMM: 106 dump(reinterpret_cast<const int16_t*>(buffer), length); 107 break; 108 case test_wrapper::Type::BOOL: 109 case test_wrapper::Type::TENSOR_BOOL8: 110 dump(reinterpret_cast<const bool8*>(buffer), length); 111 break; 112 case test_wrapper::Type::FLOAT16: 113 case test_wrapper::Type::TENSOR_FLOAT16: 114 dump(reinterpret_cast<const _Float16*>(buffer), length); 115 break; 116 default: 117 NN_FUZZER_CHECK(false) << "Unknown type when dumping the buffer"; 118 } 119 } 120 121 // Dump dimensions with curly braces. 122 void SpecWriter::dump(const std::vector<RandomVariable>& dimensions) { 123 os << "{" << joinStr(", ", dimensions, [](const RandomVariable& var) { 124 return std::to_string(var.getValue()); 125 }) << "}"; 126 } 127 128 // Dump a model operand. 129 // e.g. op0 = Input("op0", "TENSOR_FLOAT32", "{1, 2, 6, 1}") 130 // e.g. op1 = Parameter("op1", "INT32", "{}", [2]) 131 void SpecWriter::dump(const std::shared_ptr<RandomOperand>& op) { 132 os << "op" << op->opIndex << " = " << toString(op->type) << "(\"op" << op->opIndex << "\", \"" 133 << toString(op->dataType) << "\", \""; 134 dump(op->dimensions); 135 if (op->scale != 0.0f || op->zeroPoint != 0) { 136 os << ", " << op->scale << "f, " << op->zeroPoint; 137 } 138 os << "\""; 139 if (op->type == RandomOperandType::CONST) { 140 os << ", ["; 141 dump(op->dataType, reinterpret_cast<uint8_t*>(op->buffer.data()), 142 op->getNumberOfElements()); 143 os << "]"; 144 } 145 os << ")\n"; 146 } 147 148 // Dump a model operation. 149 // e.g. model = model.Operation("CONV_2D", op0, op1, op2, op3, op4, op5, op6).To(op7) 150 void SpecWriter::dump(const RandomOperation& op) { 151 auto getOperandStr = [](std::shared_ptr<RandomOperand> op) { 152 return "op" + std::to_string(op->opIndex); 153 }; 154 os << "model = model.Operation(\"" << kOperationNames[op.opType] << "\", " 155 << joinStr(", ", op.inputs, getOperandStr) << ").To(" 156 << joinStr(", ", op.outputs, getOperandStr) << ")\n"; 157 } 158 159 } // namespace fuzzing_test 160 } // namespace nn 161 } // namespace android 162