| 115 | } |
| 116 | |
| 117 | void SingleOpModel::BuildInterpreter(std::vector<std::vector<int>> input_shapes, |
| 118 | int num_threads, |
| 119 | bool allow_fp32_relax_to_fp16, |
| 120 | bool apply_delegate) { |
| 121 | auto opcodes = builder_.CreateVector(opcodes_); |
| 122 | auto operators = builder_.CreateVector(operators_); |
| 123 | auto tensors = builder_.CreateVector(tensors_); |
| 124 | auto inputs = builder_.CreateVector<int32_t>(inputs_); |
| 125 | auto outputs = builder_.CreateVector<int32_t>(outputs_); |
| 126 | // Create a single subgraph |
| 127 | std::vector<flatbuffers::Offset<SubGraph>> subgraphs; |
| 128 | auto subgraph = CreateSubGraph(builder_, tensors, inputs, outputs, operators); |
| 129 | subgraphs.push_back(subgraph); |
| 130 | auto subgraphs_flatbuffer = builder_.CreateVector(subgraphs); |
| 131 | |
| 132 | auto buffers = builder_.CreateVector(buffers_); |
| 133 | auto description = builder_.CreateString("programmatic model"); |
| 134 | builder_.Finish(CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes, |
| 135 | subgraphs_flatbuffer, description, buffers)); |
| 136 | |
| 137 | auto* model = GetModel(builder_.GetBufferPointer()); |
| 138 | |
| 139 | if (!resolver_) { |
| 140 | auto resolver = new ops::builtin::BuiltinOpResolver(); |
| 141 | for (const auto& reg : custom_registrations_) { |
| 142 | resolver->AddCustom(reg.first.data(), reg.second()); |
| 143 | } |
| 144 | resolver_ = std::unique_ptr<OpResolver>(resolver); |
| 145 | } |
| 146 | CHECK(InterpreterBuilder(model, *resolver_)(&interpreter_, num_threads) == |
| 147 | kTfLiteOk); |
| 148 | |
| 149 | CHECK(interpreter_ != nullptr); |
| 150 | |
| 151 | for (size_t i = 0; i < input_shapes.size(); ++i) { |
| 152 | const int input_idx = interpreter_->inputs()[i]; |
| 153 | if (input_idx == kOptionalTensor) continue; |
| 154 | const auto& shape = input_shapes[i]; |
| 155 | if (shape.empty()) continue; |
| 156 | CHECK(interpreter_->ResizeInputTensor(input_idx, shape) == kTfLiteOk); |
| 157 | } |
| 158 | |
| 159 | interpreter_->SetAllowFp16PrecisionForFp32(allow_fp32_relax_to_fp16); |
| 160 | |
| 161 | CHECK(interpreter_->AllocateTensors() == kTfLiteOk) |
| 162 | << "Cannot allocate tensors"; |
| 163 | interpreter_->ResetVariableTensors(); |
| 164 | |
| 165 | // In some rare cases a test may need to postpone modifying the graph with |
| 166 | // a delegate, e.g. if tensors are not fully specified. In such cases the |
| 167 | // test has to explicitly call ApplyDelegate() when necessary. |
| 168 | if (apply_delegate) ApplyDelegate(); |
| 169 | } |
| 170 | |
| 171 | void SingleOpModel::ApplyDelegate() { |
| 172 | if (force_use_nnapi) { |
no test coverage detected