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