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 #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H 18 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H 19 20 #include <functional> 21 #include <memory> 22 #include <string> 23 #include <vector> 24 25 #include "TestHarness.h" 26 #include "TestNeuralNetworksWrapper.h" 27 #include "fuzzing/RandomVariable.h" 28 29 namespace android { 30 namespace nn { 31 namespace fuzzing_test { 32 33 using OperandBuffer = std::vector<int32_t>; 34 35 struct OperandSignature; 36 struct OperationSignature; 37 class OperationManager; 38 39 enum class RandomOperandType { INPUT = 0, OUTPUT = 1, INTERNAL = 2, CONST = 3, NO_VALUE = 4 }; 40 41 struct RandomOperand { 42 // Describes the properties of the values of an operand. For operation inputs, this specifies 43 // what is required; for outputs, this specifies what is guaranteed. 44 // The graph generation algorithm will use this information to decide whether to wire an output 45 // to an input or not. 46 enum ValueProperty : int { 47 NON_ZERO = 1 << 0, 48 NON_NEGATIVE = 1 << 1, 49 }; 50 51 RandomOperandType type; 52 int valueProperties = 0; 53 test_helper::TestOperandType dataType; 54 float scale = 0.0f; 55 int32_t zeroPoint = 0; 56 std::vector<RandomVariable> dimensions; 57 OperandBuffer buffer; 58 std::vector<RandomVariable> randomBuffer; 59 60 // The finalizer will be invoked after RandomVariableNetwork::freeze(). 61 // Operand buffer will be set during this step (if not set before). 62 std::function<void(RandomOperand*)> finalizer = nullptr; 63 64 // The index of the operand in the model as returned from model->addOperand(...). 65 int32_t opIndex = -1; 66 // The index of the input/output as specified in model->identifyInputsAndOutputs(...). 67 int32_t ioIndex = -1; 68 69 // If set true, this operand will be ignored during the accuracy checking step. 70 bool doNotCheckAccuracy = false; 71 72 // If set true, this operand will not be connected to another operation, e.g. if this operand is 73 // an operation output, then it will not be used as an input to another operation, and will 74 // eventually end up being a model output. 75 bool doNotConnect = false; 76 77 RandomOperand(const OperandSignature& op, test_helper::TestOperandType dataType, uint32_t rank); 78 79 // Resize the underlying operand buffer. 80 template <typename T> resizeBufferRandomOperand81 void resizeBuffer(uint32_t len) { 82 constexpr size_t valueSize = sizeof(OperandBuffer::value_type); 83 uint32_t bufferSize = (sizeof(T) * len + valueSize - 1) / valueSize; 84 buffer.resize(bufferSize); 85 } 86 87 // Get the operand value as the specified type. The caller is reponsible for making sure that 88 // the index is not out of range. 89 template <typename T> 90 T& value(uint32_t index = 0) { 91 return reinterpret_cast<T*>(buffer.data())[index]; 92 } 93 template <> 94 RandomVariable& value<RandomVariable>(uint32_t index) { 95 return randomBuffer[index]; 96 } 97 98 // The caller is reponsible for making sure that the operand is indeed a scalar. 99 template <typename T> setScalarValueRandomOperand100 void setScalarValue(const T& val) { 101 resizeBuffer<T>(/*len=*/1); 102 value<T>() = val; 103 } 104 105 // Check if a directed edge between [other -> this] is valid. If yes, add the edge. 106 // Where "this" must be of type INPUT and "other" must be of type OUTPUT. 107 bool createEdgeIfValid(const RandomOperand& other) const; 108 109 // The followings are only intended to be used after RandomVariableNetwork::freeze(). 110 std::vector<uint32_t> getDimensions() const; 111 uint32_t getNumberOfElements() const; 112 size_t getBufferSize() const; 113 }; 114 115 struct RandomOperation { 116 test_helper::TestOperationType opType; 117 std::vector<std::shared_ptr<RandomOperand>> inputs; 118 std::vector<std::shared_ptr<RandomOperand>> outputs; 119 std::function<void(RandomOperation*)> finalizer = nullptr; 120 RandomOperation(const OperationSignature& operation); 121 }; 122 123 // The main interface of the random graph generator. 124 class RandomGraph { 125 public: 126 RandomGraph() = default; 127 128 // Generate a random graph with numOperations and dimensionRange from a seed. 129 bool generate(uint32_t seed, uint32_t numOperations, uint32_t dimensionRange); 130 131 // Create a test model of the generated graph. The operands will always have fully-specified 132 // dimensions. The output buffers are only allocated but not initialized. 133 test_helper::TestModel createTestModel(); 134 getOperations()135 const std::vector<RandomOperation>& getOperations() const { return mOperations; } 136 137 private: 138 // Generate the graph structure. 139 bool generateGraph(uint32_t numOperations); 140 141 // Fill in random values for dimensions, constants, and inputs. 142 bool generateValue(); 143 144 std::vector<RandomOperation> mOperations; 145 std::vector<std::shared_ptr<RandomOperand>> mOperands; 146 }; 147 148 } // namespace fuzzing_test 149 } // namespace nn 150 } // namespace android 151 152 #endif // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H 153