1 /* 2 * Copyright (C) 2017 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 #define LOG_TAG "android.hardware.neuralnetworks (at) 1.0-impl-hvx" 18 19 #include "HexagonModel.h" 20 #include "HexagonOperations.h" 21 #include "OperationsUtils.h" 22 23 namespace android { 24 namespace hardware { 25 namespace neuralnetworks { 26 namespace V1_0 { 27 namespace implementation { 28 namespace hexagon { 29 30 using android::nn::Shape; 31 32 namespace { 33 namespace float32 { 34 35 bool add(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, HexagonModel* model) { 36 HEXAGON_SOFT_ASSERT_EQ(3, ins.size(), "Need 3 inputs for float32::add"); 37 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::add"); 38 39 // get parameters 40 const hexagon_nn_input& in1 = model->getTensor(ins[0]); 41 const hexagon_nn_input& in2 = model->getTensor(ins[1]); 42 43 const op_type act = model->getFloatActivation(ins[2]); 44 45 // add node to graph 46 return model->addFusedFloatOperation(OP_Add_f, NN_PAD_NA, {}, act, {in1, in2}, outs); 47 } 48 49 bool average_pool_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 50 HexagonModel* model) { 51 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 52 "Need 7 or 10 inputs for float32::average_pool_2d"); 53 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::average_pool_2d"); 54 55 // get parameters 56 const hexagon_nn_input& input = model->getTensor(ins[0]); 57 58 // setup parameters 59 hexagon_nn_padding_type pad; 60 int32_t stride_width; 61 int32_t stride_height; 62 int32_t filter_width; 63 int32_t filter_height; 64 op_type act; 65 66 // get parameters 67 if (ins.size() == 10) { 68 const int32_t padding_left = model->getScalar<int32_t>(ins[1]); 69 const int32_t padding_right = model->getScalar<int32_t>(ins[2]); 70 const int32_t padding_top = model->getScalar<int32_t>(ins[3]); 71 const int32_t padding_bottom = model->getScalar<int32_t>(ins[4]); 72 stride_width = model->getScalar<int32_t>(ins[5]); 73 stride_height = model->getScalar<int32_t>(ins[6]); 74 filter_width = model->getScalar<int32_t>(ins[7]); 75 filter_height = model->getScalar<int32_t>(ins[8]); 76 act = model->getFloatActivation(ins[9]); 77 78 const Shape inputShape = model->getShape(ins[0]); 79 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 80 stride_height, filter_width, filter_height, padding_left, padding_right, 81 padding_top, padding_bottom); 82 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 83 } else { 84 pad = model->getPadding(ins[1]); 85 stride_width = model->getScalar<int32_t>(ins[2]); 86 stride_height = model->getScalar<int32_t>(ins[3]); 87 filter_width = model->getScalar<int32_t>(ins[4]); 88 filter_height = model->getScalar<int32_t>(ins[5]); 89 act = model->getFloatActivation(ins[6]); 90 } 91 92 const hexagon_nn_input window = model->createShape(1, filter_height, filter_width, 1); 93 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 94 95 // add node to graph 96 return model->addFloatOperationWithActivation(OP_AvgPool_f, pad, act, {input, window, stride}, 97 outs); 98 } 99 100 bool concatenation(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 101 HexagonModel* model) { 102 HEXAGON_SOFT_ASSERT_LE(3, ins.size(), "Need at least 3 inputs for float32::concatenation"); 103 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::concatenation"); 104 105 const size_t numInputTensors = ins.size() - 1; 106 107 // get parameters 108 std::vector<hexagon_nn_input> inputs(numInputTensors + 1); 109 for (size_t i = 0; i < numInputTensors; ++i) { 110 inputs[i + 1] = model->getTensor(ins[i]); 111 } 112 113 // axis being concatenated 114 const int32_t axis = model->getScalar<int32_t>(ins[numInputTensors]); 115 const int32_t dims = model->getShape(ins[0]).dimensions.size(); 116 inputs[0] = model->createScalar<int32_t>(axis + (4 - dims)); 117 118 // add node to graph 119 return model->addBasicOperation(OP_Concat_f, NN_PAD_NA, inputs, outs); 120 } 121 122 bool conv_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 123 HexagonModel* model) { 124 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 125 "Need 7 or 10 inputs for float32::conv_2d"); 126 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::conv_2d"); 127 128 // get parameters 129 const hexagon_nn_input& input = model->getTensor(ins[0]); 130 const hexagon_nn_input filter = model->createConvFilterTensor(ins[1]); 131 const hexagon_nn_input& bias = model->getTensor(ins[2]); 132 133 // setup parameters 134 hexagon_nn_padding_type pad; 135 int32_t stride_width; 136 int32_t stride_height; 137 op_type act; 138 139 // get parameters 140 if (ins.size() == 10) { 141 const int32_t padding_left = model->getScalar<int32_t>(ins[3]); 142 const int32_t padding_right = model->getScalar<int32_t>(ins[4]); 143 const int32_t padding_top = model->getScalar<int32_t>(ins[5]); 144 const int32_t padding_bottom = model->getScalar<int32_t>(ins[6]); 145 stride_width = model->getScalar<int32_t>(ins[7]); 146 stride_height = model->getScalar<int32_t>(ins[8]); 147 act = model->getFloatActivation(ins[9]); 148 149 const Shape inputShape = model->getShape(ins[0]); 150 const Shape filterShape = model->getShape(ins[1]); 151 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 152 stride_height, filterShape.dimensions[2], filterShape.dimensions[1], 153 padding_left, padding_right, padding_top, padding_bottom); 154 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 155 } else { 156 pad = model->getPadding(ins[3]); 157 stride_width = model->getScalar<int32_t>(ins[4]); 158 stride_height = model->getScalar<int32_t>(ins[5]); 159 act = model->getFloatActivation(ins[6]); 160 } 161 162 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 163 164 // add node to graph 165 return model->addFusedFloatOperation(OP_Conv2d_f, pad, bias, act, {input, filter, stride}, 166 outs); 167 } 168 169 bool depthwise_conv_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 170 HexagonModel* model) { 171 HEXAGON_SOFT_ASSERT(ins.size() == 11 || ins.size() == 8, 172 "Need 8 or 11 inputs for float32::depthwise_conv_2d"); 173 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::depthwise_conv_2d"); 174 175 // get parameters 176 const hexagon_nn_input& input = model->getTensor(ins[0]); 177 const hexagon_nn_input& bias = model->getTensor(ins[2]); 178 179 const Shape filterShape = model->getShape(ins[1]); 180 181 // setup parameters 182 hexagon_nn_padding_type pad; 183 int32_t stride_width; 184 int32_t stride_height; 185 int32_t depth_multiplier; 186 op_type act; 187 188 // get parameters 189 if (ins.size() == 11) { 190 const int32_t padding_left = model->getScalar<int32_t>(ins[3]); 191 const int32_t padding_right = model->getScalar<int32_t>(ins[4]); 192 const int32_t padding_top = model->getScalar<int32_t>(ins[5]); 193 const int32_t padding_bottom = model->getScalar<int32_t>(ins[6]); 194 stride_width = model->getScalar<int32_t>(ins[7]); 195 stride_height = model->getScalar<int32_t>(ins[8]); 196 depth_multiplier = model->getScalar<int32_t>(ins[9]); 197 act = model->getFloatActivation(ins[10]); 198 199 const Shape inputShape = model->getShape(ins[0]); 200 const Shape filterShape = model->getShape(ins[1]); 201 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 202 stride_height, filterShape.dimensions[2], filterShape.dimensions[1], 203 padding_left, padding_right, padding_top, padding_bottom); 204 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 205 } else { 206 pad = model->getPadding(ins[3]); 207 stride_width = model->getScalar<int32_t>(ins[4]); 208 stride_height = model->getScalar<int32_t>(ins[5]); 209 depth_multiplier = model->getScalar<int32_t>(ins[6]); 210 act = model->getFloatActivation(ins[7]); 211 } 212 213 const hexagon_nn_input filter = model->createDepthwiseFilterTensor(ins[1], depth_multiplier); 214 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 215 216 // add node to graph 217 return model->addFusedFloatOperation(OP_DepthwiseConv2d_f, pad, bias, act, 218 {input, filter, stride}, outs); 219 } 220 221 bool fully_connected(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 222 HexagonModel* model) { 223 HEXAGON_SOFT_ASSERT_EQ(4, ins.size(), "Need 4 inputs for float32::fully_connected"); 224 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::fully_connected"); 225 226 // get parameters 227 const hexagon_nn_input& input = model->getTensor(ins[0]); 228 const hexagon_nn_input& weights = model->createFullyConnectedWeightTensor(ins[1]); 229 const hexagon_nn_input& bias = model->getTensor(ins[2]); 230 231 const op_type act = model->getFloatActivation(ins[3]); 232 233 // add node to graph 234 return model->addFusedFloatOperation(OP_MatMul_f, NN_PAD_NA, bias, act, {input, weights}, outs); 235 } 236 237 bool l2_pool_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 238 HexagonModel* model) { 239 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 240 "Need 7 or 10 inputs for float32::l2_pool_2d"); 241 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::l2_pool_2d"); 242 243 // get parameters 244 const hexagon_nn_input& input = model->getTensor(ins[0]); 245 246 // setup parameters 247 hexagon_nn_padding_type pad; 248 int32_t stride_width; 249 int32_t stride_height; 250 int32_t filter_width; 251 int32_t filter_height; 252 op_type act; 253 254 // get parameters 255 if (ins.size() == 10) { 256 const int32_t padding_left = model->getScalar<int32_t>(ins[1]); 257 const int32_t padding_right = model->getScalar<int32_t>(ins[2]); 258 const int32_t padding_top = model->getScalar<int32_t>(ins[3]); 259 const int32_t padding_bottom = model->getScalar<int32_t>(ins[4]); 260 stride_width = model->getScalar<int32_t>(ins[5]); 261 stride_height = model->getScalar<int32_t>(ins[6]); 262 filter_width = model->getScalar<int32_t>(ins[7]); 263 filter_height = model->getScalar<int32_t>(ins[8]); 264 act = model->getFloatActivation(ins[9]); 265 266 const Shape inputShape = model->getShape(ins[0]); 267 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 268 stride_height, filter_width, filter_height, padding_left, padding_right, 269 padding_top, padding_bottom); 270 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 271 } else { 272 pad = model->getPadding(ins[1]); 273 stride_width = model->getScalar<int32_t>(ins[2]); 274 stride_height = model->getScalar<int32_t>(ins[3]); 275 filter_width = model->getScalar<int32_t>(ins[4]); 276 filter_height = model->getScalar<int32_t>(ins[5]); 277 act = model->getFloatActivation(ins[6]); 278 } 279 280 const hexagon_nn_input window = model->createShape(1, filter_height, filter_width, 1); 281 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 282 283 // add node to graph 284 return model->addFloatOperationWithActivation(OP_L2Pool_f, pad, act, {input, window, stride}, 285 outs); 286 } 287 288 bool local_response_normalization(const std::vector<uint32_t>& ins, 289 const std::vector<uint32_t>& outs, HexagonModel* model) { 290 HEXAGON_SOFT_ASSERT_EQ(5, ins.size(), 291 "Need 5 inputs for float32::local_response_normalization"); 292 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), 293 "Need 1 output for float32::local_response_normalization"); 294 295 // get parameters 296 const hexagon_nn_input& input = model->getTensor(ins[0]); 297 const hexagon_nn_input& bias = model->getTensor(ins[2]); 298 const hexagon_nn_input& alpha = model->getTensor(ins[3]); 299 const hexagon_nn_input& beta = model->getTensor(ins[4]); 300 301 // create value that's [1, 1, 1, radius] with value of 1.0f 302 const int32_t radius = model->getScalar<int32_t>(ins[1]); 303 const hexagon_nn_input window = model->createTensor<float>(1, 1, 1, radius * 2 + 1, {1.0f}); 304 305 // add node to graph 306 return model->addBasicOperation(OP_LRN_f, NN_PAD_NA, {input, window, bias, alpha, beta}, outs); 307 } 308 309 bool logistic(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 310 HexagonModel* model) { 311 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for float32::logistic"); 312 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::logistic"); 313 314 // get parameters 315 const hexagon_nn_input& input = model->getTensor(ins[0]); 316 317 // add node to graph 318 return model->addBasicOperation(OP_Sigmoid_f, NN_PAD_NA, {input}, outs); 319 } 320 321 bool max_pool_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 322 HexagonModel* model) { 323 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 324 "Need 7 or 10 inputs for float32::max_pool_2d"); 325 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::max_pool_2d"); 326 327 // get parameters 328 const hexagon_nn_input& input = model->getTensor(ins[0]); 329 330 // setup parameters 331 hexagon_nn_padding_type pad; 332 int32_t stride_width; 333 int32_t stride_height; 334 int32_t filter_width; 335 int32_t filter_height; 336 op_type act; 337 338 // get parameters 339 if (ins.size() == 10) { 340 const int32_t padding_left = model->getScalar<int32_t>(ins[1]); 341 const int32_t padding_right = model->getScalar<int32_t>(ins[2]); 342 const int32_t padding_top = model->getScalar<int32_t>(ins[3]); 343 const int32_t padding_bottom = model->getScalar<int32_t>(ins[4]); 344 stride_width = model->getScalar<int32_t>(ins[5]); 345 stride_height = model->getScalar<int32_t>(ins[6]); 346 filter_width = model->getScalar<int32_t>(ins[7]); 347 filter_height = model->getScalar<int32_t>(ins[8]); 348 act = model->getFloatActivation(ins[9]); 349 350 const Shape inputShape = model->getShape(ins[0]); 351 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 352 stride_height, filter_width, filter_height, padding_left, padding_right, 353 padding_top, padding_bottom); 354 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 355 } else { 356 pad = model->getPadding(ins[1]); 357 stride_width = model->getScalar<int32_t>(ins[2]); 358 stride_height = model->getScalar<int32_t>(ins[3]); 359 filter_width = model->getScalar<int32_t>(ins[4]); 360 filter_height = model->getScalar<int32_t>(ins[5]); 361 act = model->getFloatActivation(ins[6]); 362 } 363 364 const hexagon_nn_input window = model->createShape(1, filter_height, filter_width, 1); 365 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 366 367 // add node to graph 368 return model->addFloatOperationWithActivation(OP_MaxPool_f, pad, act, {input, window, stride}, 369 outs); 370 } 371 372 bool mul(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, HexagonModel* model) { 373 HEXAGON_SOFT_ASSERT_EQ(3, ins.size(), "Need 3 inputs for float32::mul"); 374 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::mul"); 375 376 // get parameters 377 const hexagon_nn_input& in1 = model->getTensor(ins[0]); 378 const hexagon_nn_input& in2 = model->getTensor(ins[1]); 379 380 const op_type act = model->getFloatActivation(ins[2]); 381 382 // add node to graph 383 return model->addFusedFloatOperation(OP_Mul_f, NN_PAD_NA, {}, act, {in1, in2}, outs); 384 } 385 386 bool relu(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 387 HexagonModel* model) { 388 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for float32::relu"); 389 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::relu"); 390 391 // get parameters 392 const hexagon_nn_input& input = model->getTensor(ins[0]); 393 394 // add node to graph 395 return model->addBasicOperation(OP_Relu_f, NN_PAD_NA, {input}, outs); 396 } 397 398 bool relu1(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 399 HexagonModel* model) { 400 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for float32::relu1"); 401 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::relu1"); 402 403 // get parameters 404 const hexagon_nn_input& input = model->getTensor(ins[0]); 405 const hexagon_nn_input min = model->createScalar(-1.0f); 406 const hexagon_nn_input max = model->createScalar(1.0f); 407 408 // add node to graph 409 return model->addBasicOperation(OP_Clamp_f, NN_PAD_NA, {input, min, max}, outs); 410 } 411 412 bool relu6(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 413 HexagonModel* model) { 414 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for float32::relu6"); 415 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::relu6"); 416 417 // get parameters 418 const hexagon_nn_input& input = model->getTensor(ins[0]); 419 const hexagon_nn_input max = model->createScalar(6.0f); 420 421 // add node to graph 422 return model->addBasicOperation(OP_ReluX_f, NN_PAD_NA, {input, max}, outs); 423 } 424 425 bool reshape(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 426 HexagonModel* model) { 427 HEXAGON_SOFT_ASSERT_EQ(2, ins.size(), "Need 2 inputs for float32::reshape"); 428 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::reshape"); 429 430 // get parameters 431 const hexagon_nn_input& input = model->getTensor(ins[0]); 432 const hexagon_nn_input& newdims = model->getTensor(ins[1]); 433 434 // add node to graph 435 return model->addBasicOperation(OP_Reshape, NN_PAD_NA, {input, newdims}, outs); 436 } 437 438 bool resize_bilinear(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 439 HexagonModel* model) { 440 HEXAGON_SOFT_ASSERT_EQ(3, ins.size(), "Need 3 inputs for float32::resize_bilinear"); 441 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::resize_bilinear"); 442 443 // get parameters 444 const hexagon_nn_input& input = model->getTensor(ins[0]); 445 446 const int32_t width = model->getScalar<int32_t>(ins[1]); 447 const int32_t height = model->getScalar<int32_t>(ins[2]); 448 449 const hexagon_nn_input newdim = model->createValues<int32_t>({height, width}); 450 451 // add node to graph 452 return model->addBasicOperation(OP_ResizeBilinear_f, NN_PAD_NA, {input, newdim}, outs); 453 } 454 455 bool softmax(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 456 HexagonModel* model) { 457 HEXAGON_SOFT_ASSERT_EQ(2, ins.size(), "Need 2 inputs for float32::softmax"); 458 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::softmax"); 459 460 // get parameters 461 const hexagon_nn_input& input = model->getTensor(ins[0]); 462 const hexagon_nn_input& beta = model->getTensor(ins[1]); 463 464 // add node to graph 465 return model->addBasicOperation(OP_Softmax_f, NN_PAD_NA, {input, beta}, outs); 466 } 467 468 bool tanh(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 469 HexagonModel* model) { 470 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for float32::tanh"); 471 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for float32::tanh"); 472 473 // get parameters 474 const hexagon_nn_input& input = model->getTensor(ins[0]); 475 476 // add node to graph 477 return model->addBasicOperation(OP_Tanh_f, NN_PAD_NA, {input}, outs); 478 } 479 480 } // namespace float32 481 482 namespace quant8_asym { 483 484 bool add(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, HexagonModel* model) { 485 HEXAGON_SOFT_ASSERT_EQ(3, ins.size(), "Need 3 inputs for quant8_asym::add"); 486 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::add"); 487 488 // get parameters 489 const hexagon_nn_input& in1 = model->getTensor(ins[0]); 490 const hexagon_nn_input& in2 = model->getTensor(ins[1]); 491 492 const op_type act = model->getQuantizedActivation(ins[2]); 493 494 const hexagon_nn_input& in1_min = model->getQuantizationMin(ins[0]); 495 const hexagon_nn_input& in1_max = model->getQuantizationMax(ins[0]); 496 const hexagon_nn_input& in2_min = model->getQuantizationMin(ins[1]); 497 const hexagon_nn_input& in2_max = model->getQuantizationMax(ins[1]); 498 499 // add node to graph 500 return model->addFusedQuant8Operation(OP_QuantizedAdd_8p8to32, NN_PAD_NA, {}, act, 501 {in1, in2, in1_min, in1_max, in2_min, in2_max}, outs); 502 } 503 504 bool average_pool_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 505 HexagonModel* model) { 506 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 507 "Need 7 or 10 inputs for quant8_asym::average_pool_2d"); 508 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::average_pool_2d"); 509 510 // get parameters 511 const hexagon_nn_input& input = model->getTensor(ins[0]); 512 513 // setup parameters 514 hexagon_nn_padding_type pad; 515 int32_t stride_width; 516 int32_t stride_height; 517 int32_t filter_width; 518 int32_t filter_height; 519 op_type act; 520 521 // get parameters 522 if (ins.size() == 10) { 523 const int32_t padding_left = model->getScalar<int32_t>(ins[1]); 524 const int32_t padding_right = model->getScalar<int32_t>(ins[2]); 525 const int32_t padding_top = model->getScalar<int32_t>(ins[3]); 526 const int32_t padding_bottom = model->getScalar<int32_t>(ins[4]); 527 stride_width = model->getScalar<int32_t>(ins[5]); 528 stride_height = model->getScalar<int32_t>(ins[6]); 529 filter_width = model->getScalar<int32_t>(ins[7]); 530 filter_height = model->getScalar<int32_t>(ins[8]); 531 act = model->getQuantizedActivation(ins[9]); 532 533 const Shape inputShape = model->getShape(ins[0]); 534 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 535 stride_height, filter_width, filter_height, padding_left, padding_right, 536 padding_top, padding_bottom); 537 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 538 } else { 539 pad = model->getPadding(ins[1]); 540 stride_width = model->getScalar<int32_t>(ins[2]); 541 stride_height = model->getScalar<int32_t>(ins[3]); 542 filter_width = model->getScalar<int32_t>(ins[4]); 543 filter_height = model->getScalar<int32_t>(ins[5]); 544 act = model->getQuantizedActivation(ins[6]); 545 } 546 547 const hexagon_nn_input& in_min = model->getQuantizationMin(ins[0]); 548 const hexagon_nn_input& in_max = model->getQuantizationMax(ins[0]); 549 const hexagon_nn_input window = model->createShape(1, filter_height, filter_width, 1); 550 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 551 552 // add node to graph 553 return model->addQuant8OperationWithActivation(OP_QuantizedAvgPool_8, pad, act, 554 {input, in_min, in_max, window, stride}, outs); 555 } 556 557 bool concatenation(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 558 HexagonModel* model) { 559 HEXAGON_SOFT_ASSERT_LE(3, ins.size(), "Need at least 3 inputs for quant8_asym::concatenation"); 560 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::concatenation"); 561 562 const size_t numInputTensors = ins.size() - 1; 563 564 // get parameters 565 std::vector<hexagon_nn_input> inputs(numInputTensors * 3 + 1); 566 for (size_t i = 0; i < numInputTensors; ++i) { 567 inputs[i + 1 + numInputTensors * 0] = model->getTensor(ins[i]); 568 inputs[i + 1 + numInputTensors * 1] = model->getQuantizationMin(ins[i]); 569 inputs[i + 1 + numInputTensors * 2] = model->getQuantizationMax(ins[i]); 570 } 571 572 // axis being concatenated 573 const int32_t axis = model->getScalar<int32_t>(ins[numInputTensors]); 574 const int32_t dims = model->getShape(ins[0]).dimensions.size(); 575 inputs[0] = model->createScalar<int32_t>(axis + (4 - dims)); 576 577 // add node to graph 578 return model->addBasicOperation(OP_QuantizedConcat_8, NN_PAD_NA, inputs, outs); 579 } 580 581 bool conv_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 582 HexagonModel* model) { 583 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 584 "Need 7 or 10 inputs for quant8_asym::conv_2d"); 585 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::conv_2d"); 586 587 // get parameters 588 const hexagon_nn_input& input = model->getTensor(ins[0]); 589 const hexagon_nn_input filter = model->createConvFilterTensor(ins[1]); 590 const hexagon_nn_input& bias = model->getTensor(ins[2]); 591 592 // setup parameters 593 hexagon_nn_padding_type pad; 594 int32_t stride_width; 595 int32_t stride_height; 596 op_type act; 597 598 // get parameters 599 if (ins.size() == 10) { 600 const int32_t padding_left = model->getScalar<int32_t>(ins[3]); 601 const int32_t padding_right = model->getScalar<int32_t>(ins[4]); 602 const int32_t padding_top = model->getScalar<int32_t>(ins[5]); 603 const int32_t padding_bottom = model->getScalar<int32_t>(ins[6]); 604 stride_width = model->getScalar<int32_t>(ins[7]); 605 stride_height = model->getScalar<int32_t>(ins[8]); 606 act = model->getQuantizedActivation(ins[9]); 607 608 const Shape inputShape = model->getShape(ins[0]); 609 const Shape filterShape = model->getShape(ins[1]); 610 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 611 stride_height, filterShape.dimensions[2], filterShape.dimensions[1], 612 padding_left, padding_right, padding_top, padding_bottom); 613 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 614 } else { 615 pad = model->getPadding(ins[3]); 616 stride_width = model->getScalar<int32_t>(ins[4]); 617 stride_height = model->getScalar<int32_t>(ins[5]); 618 act = model->getQuantizedActivation(ins[6]); 619 } 620 621 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 622 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 623 const hexagon_nn_input& filter_min = model->getQuantizationMin(ins[1]); 624 const hexagon_nn_input& filter_max = model->getQuantizationMax(ins[1]); 625 const hexagon_nn_input& bias_min = model->getQuantizationMin(ins[2]); 626 const hexagon_nn_input& bias_max = model->getQuantizationMax(ins[2]); 627 628 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 629 630 // add node to graph 631 return model->addFusedQuant8Operation( 632 OP_QuantizedConv2d_8x8to32, pad, {bias, bias_min, bias_max}, act, 633 {input, filter, input_min, input_max, filter_min, filter_max, stride}, outs); 634 } 635 636 bool depthwise_conv_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 637 HexagonModel* model) { 638 HEXAGON_SOFT_ASSERT(ins.size() == 11 || ins.size() == 8, 639 "Need 8 to 11 inputs for quant8_asym::depthwise_conv_2d"); 640 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::depthwise_conv_2d"); 641 642 // get parameters 643 const hexagon_nn_input& input = model->getTensor(ins[0]); 644 const hexagon_nn_input& bias = model->getTensor(ins[2]); 645 646 // setup parameters 647 hexagon_nn_padding_type pad; 648 int32_t stride_width; 649 int32_t stride_height; 650 int32_t depth_multiplier; 651 op_type act; 652 653 // get parameters 654 if (ins.size() == 11) { 655 const int32_t padding_left = model->getScalar<int32_t>(ins[3]); 656 const int32_t padding_right = model->getScalar<int32_t>(ins[4]); 657 const int32_t padding_top = model->getScalar<int32_t>(ins[5]); 658 const int32_t padding_bottom = model->getScalar<int32_t>(ins[6]); 659 stride_width = model->getScalar<int32_t>(ins[7]); 660 stride_height = model->getScalar<int32_t>(ins[8]); 661 depth_multiplier = model->getScalar<int32_t>(ins[9]); 662 act = model->getQuantizedActivation(ins[10]); 663 664 const Shape inputShape = model->getShape(ins[0]); 665 const Shape filterShape = model->getShape(ins[1]); 666 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 667 stride_height, filterShape.dimensions[2], filterShape.dimensions[1], 668 padding_left, padding_right, padding_top, padding_bottom); 669 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 670 } else { 671 pad = model->getPadding(ins[3]); 672 stride_width = model->getScalar<int32_t>(ins[4]); 673 stride_height = model->getScalar<int32_t>(ins[5]); 674 depth_multiplier = model->getScalar<int32_t>(ins[6]); 675 act = model->getQuantizedActivation(ins[7]); 676 } 677 678 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 679 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 680 const hexagon_nn_input& filter_min = model->getQuantizationMin(ins[1]); 681 const hexagon_nn_input& filter_max = model->getQuantizationMax(ins[1]); 682 const hexagon_nn_input& bias_min = model->getQuantizationMin(ins[2]); 683 const hexagon_nn_input& bias_max = model->getQuantizationMax(ins[2]); 684 685 const hexagon_nn_input filter = model->createDepthwiseFilterTensor(ins[1], depth_multiplier); 686 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 687 688 // add node to graph 689 return model->addFusedQuant8Operation( 690 OP_QuantizedDepthwiseConv2d_8x8to32, pad, {bias, bias_min, bias_max}, act, 691 {input, filter, input_min, input_max, filter_min, filter_max, stride}, outs); 692 } 693 694 bool dequantize(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 695 HexagonModel* model) { 696 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for quant8_asym::dequantize"); 697 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::dequantize"); 698 699 // get parameters 700 const hexagon_nn_input& input = model->getTensor(ins[0]); 701 702 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 703 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 704 705 // add node to graph 706 return model->addBasicOperation(OP_Dequantize, NN_PAD_NA, {input, input_min, input_max}, outs); 707 } 708 709 bool fully_connected(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 710 HexagonModel* model) { 711 HEXAGON_SOFT_ASSERT_EQ(4, ins.size(), "Need 4 inputs for quant8::fully_connected"); 712 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8::fully_connected"); 713 714 // get parameters 715 const hexagon_nn_input& input = model->getTensor(ins[0]); 716 const hexagon_nn_input& weights = model->createFullyConnectedWeightTensor(ins[1]); 717 const hexagon_nn_input& bias = model->getTensor(ins[2]); 718 719 const op_type act = model->getQuantizedActivation(ins[3]); 720 721 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 722 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 723 const hexagon_nn_input& weights_min = model->getQuantizationMin(ins[1]); 724 const hexagon_nn_input& weights_max = model->getQuantizationMax(ins[1]); 725 const hexagon_nn_input& bias_min = model->getQuantizationMin(ins[2]); 726 const hexagon_nn_input& bias_max = model->getQuantizationMax(ins[2]); 727 728 // add node to graph 729 return model->addFusedQuant8Operation( 730 OP_QuantizedMatMul_8x8to32, NN_PAD_NA, {bias, bias_min, bias_max}, act, 731 {input, weights, input_min, input_max, weights_min, weights_max}, outs); 732 } 733 734 bool logistic(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 735 HexagonModel* model) { 736 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for quant8_asym::logistic"); 737 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::logistic"); 738 739 // get parameters 740 const hexagon_nn_input& input = model->getTensor(ins[0]); 741 742 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 743 744 // TFLite uses different max value 745 const hexagon_nn_input input_max = model->createQuantizationValue(ins[0], 256); 746 747 // add node to graph 748 return model->addBasicOperation(OP_QuantizedSigmoid_8, NN_PAD_NA, {input, input_min, input_max}, 749 outs); 750 } 751 752 bool max_pool_2d(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 753 HexagonModel* model) { 754 HEXAGON_SOFT_ASSERT(ins.size() == 10 || ins.size() == 7, 755 "Need 7 or 10 inputs for quant8_asym::max_pool_2d"); 756 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::max_pool_2d"); 757 758 // get parameters 759 const hexagon_nn_input& input = model->getTensor(ins[0]); 760 761 // setup parameters 762 hexagon_nn_padding_type pad; 763 int32_t stride_width; 764 int32_t stride_height; 765 int32_t filter_width; 766 int32_t filter_height; 767 op_type act; 768 769 // get parameters 770 if (ins.size() == 10) { 771 const int32_t padding_left = model->getScalar<int32_t>(ins[1]); 772 const int32_t padding_right = model->getScalar<int32_t>(ins[2]); 773 const int32_t padding_top = model->getScalar<int32_t>(ins[3]); 774 const int32_t padding_bottom = model->getScalar<int32_t>(ins[4]); 775 stride_width = model->getScalar<int32_t>(ins[5]); 776 stride_height = model->getScalar<int32_t>(ins[6]); 777 filter_width = model->getScalar<int32_t>(ins[7]); 778 filter_height = model->getScalar<int32_t>(ins[8]); 779 act = model->getQuantizedActivation(ins[9]); 780 781 const Shape inputShape = model->getShape(ins[0]); 782 pad = getPadding(inputShape.dimensions[2], inputShape.dimensions[1], stride_width, 783 stride_height, filter_width, filter_height, padding_left, padding_right, 784 padding_top, padding_bottom); 785 HEXAGON_SOFT_ASSERT_NE(pad, NN_PAD_NA, "Unknown padding"); 786 } else { 787 pad = model->getPadding(ins[1]); 788 stride_width = model->getScalar<int32_t>(ins[2]); 789 stride_height = model->getScalar<int32_t>(ins[3]); 790 filter_width = model->getScalar<int32_t>(ins[4]); 791 filter_height = model->getScalar<int32_t>(ins[5]); 792 act = model->getQuantizedActivation(ins[6]); 793 } 794 795 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 796 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 797 const hexagon_nn_input window = model->createShape(1, filter_height, filter_width, 1); 798 const hexagon_nn_input stride = model->createShape(1, stride_height, stride_width, 1); 799 800 // add node to graph 801 return model->addQuant8OperationWithActivation( 802 OP_QuantizedMaxPool_8, pad, act, {input, input_min, input_max, window, stride}, outs); 803 } 804 805 bool mul(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, HexagonModel* model) { 806 HEXAGON_SOFT_ASSERT_EQ(3, ins.size(), "Need 3 inputs for quant8_asym::mul"); 807 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::mul"); 808 809 // get parameters 810 const hexagon_nn_input& in1 = model->getTensor(ins[0]); 811 const hexagon_nn_input& in2 = model->getTensor(ins[1]); 812 813 const op_type act = model->getQuantizedActivation(ins[2]); 814 815 const hexagon_nn_input& in1_min = model->getQuantizationMin(ins[0]); 816 const hexagon_nn_input& in1_max = model->getQuantizationMax(ins[0]); 817 const hexagon_nn_input& in2_min = model->getQuantizationMin(ins[1]); 818 const hexagon_nn_input& in2_max = model->getQuantizationMax(ins[1]); 819 820 // add node to graph 821 return model->addFusedQuant8Operation(OP_QuantizedMul_8x8to32, NN_PAD_NA, {}, act, 822 {in1, in2, in1_min, in1_max, in2_min, in2_max}, outs); 823 } 824 825 bool relu(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 826 HexagonModel* model) { 827 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for quant8_asym::relu"); 828 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::relu"); 829 830 // get parameters 831 const hexagon_nn_input& input = model->getTensor(ins[0]); 832 833 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 834 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 835 836 // add node to graph 837 return model->addBasicOperation(OP_QuantizedRelu_8, NN_PAD_NA, {input, input_min, input_max}, 838 outs); 839 } 840 841 bool relu1(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 842 HexagonModel* model) { 843 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for quant8_asym::relu1"); 844 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::relu1"); 845 846 // get parameters 847 const hexagon_nn_input& input = model->getTensor(ins[0]); 848 const hexagon_nn_input min = model->createScalar(-1.0f); 849 const hexagon_nn_input max = model->createScalar(1.0f); 850 851 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 852 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 853 854 // add node to graph 855 return model->addBasicOperation(OP_QuantizedClamp_8, NN_PAD_NA, 856 {input, input_min, input_max, min, max}, outs); 857 } 858 859 bool relu6(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 860 HexagonModel* model) { 861 HEXAGON_SOFT_ASSERT_EQ(1, ins.size(), "Need 1 input for quant8_asym::relu6"); 862 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::relu6"); 863 864 // get parameters 865 const hexagon_nn_input& input = model->getTensor(ins[0]); 866 const hexagon_nn_input max = model->createScalar(6.0f); 867 868 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 869 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 870 871 // add node to graph 872 return model->addBasicOperation(OP_QuantizedReluX_8, NN_PAD_NA, 873 {input, input_min, input_max, max}, outs); 874 } 875 876 bool reshape(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 877 HexagonModel* model) { 878 HEXAGON_SOFT_ASSERT_EQ(2, ins.size(), "Need 2 inputs for quant8_asym::reshape"); 879 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::reshape"); 880 881 // get parameters 882 const hexagon_nn_input& input = model->getTensor(ins[0]); 883 const hexagon_nn_input& newdims = model->getTensor(ins[1]); 884 885 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 886 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 887 888 // add node to graph 889 return model->addBasicOperation(OP_QuantizedReshape, NN_PAD_NA, 890 {input, newdims, input_min, input_max}, outs); 891 } 892 893 bool softmax(const std::vector<uint32_t>& ins, const std::vector<uint32_t>& outs, 894 HexagonModel* model) { 895 HEXAGON_SOFT_ASSERT_EQ(2, ins.size(), "Need 2 inputs for quant8_asym::softmax"); 896 HEXAGON_SOFT_ASSERT_EQ(1, outs.size(), "Need 1 output for quant8_asym::softmax"); 897 898 // get parameters 899 const hexagon_nn_input& input = model->getTensor(ins[0]); 900 const hexagon_nn_input& beta = model->getTensor(ins[1]); 901 902 const hexagon_nn_input& input_min = model->getQuantizationMin(ins[0]); 903 const hexagon_nn_input& input_max = model->getQuantizationMax(ins[0]); 904 905 // add node to graph 906 return model->addBasicOperation(OP_QuantizedSoftmax_8, NN_PAD_NA, 907 {input, input_min, input_max, beta}, outs); 908 } 909 910 } // namespace quant8_asym 911 912 } // namespace 913 914 OperationTable& getOperationPrepareTable() { 915 static OperationTable table = { 916 // NOTE: the operations that are commented out via inline represent 917 // operations that are valid for the Android O NNAPI release, but are 918 // currently not implemented in HVX. 919 920 // -------------------------- 32-BIT FLOAT ---------------------------- 921 // HVX is only performant when running on quantized values. Further, as 922 // an optimization, the current HVX driver will convert some floating 923 // point tensors into quantized values, perform the operation, and then 924 // convert them back to floating point. This results in a loss in 925 // precision causing some tests to fail. For these reasons, the FLOAT32 926 // operations are being temporarily disabled. 927 /* 928 {{OperationType::ADD, OperandType::TENSOR_FLOAT32}, float32::add}, 929 {{OperationType::AVERAGE_POOL_2D, OperandType::TENSOR_FLOAT32}, float32::average_pool_2d}, 930 {{OperationType::CONCATENATION, OperandType::TENSOR_FLOAT32}, float32::concatenation}, 931 {{OperationType::CONV_2D, OperandType::TENSOR_FLOAT32}, float32::conv_2d}, 932 {{OperationType::DEPTHWISE_CONV_2D, OperandType::TENSOR_FLOAT32}, 933 float32::depthwise_conv_2d}, 934 //{{OperationType::DEPTH_TO_SPACE, OperandType::TENSOR_FLOAT32}, float32::depth_to_space}, 935 //{{OperationType::EMBEDDING_LOOKUP, OperandType::TENSOR_FLOAT32}, 936 // float32::embedding_lookup}, 937 //{{OperationType::FLOOR, OperandType::TENSOR_FLOAT32}, float32::floor}, 938 {{OperationType::FULLY_CONNECTED, OperandType::TENSOR_FLOAT32}, float32::fully_connected}, 939 //{{OperationType::HASHTABLE_LOOKUP, OperandType::TENSOR_FLOAT32}, 940 // float32::hashtable_lookup}, 941 //{{OperationType::L2_NORMALIZATION, OperandType::TENSOR_FLOAT32}, 942 // float32::l2_normalization}, 943 {{OperationType::L2_POOL_2D, OperandType::TENSOR_FLOAT32}, float32::l2_pool_2d}, 944 {{OperationType::LOCAL_RESPONSE_NORMALIZATION, OperandType::TENSOR_FLOAT32}, 945 float32::local_response_normalization}, 946 {{OperationType::LOGISTIC, OperandType::TENSOR_FLOAT32}, float32::logistic}, 947 //{{OperationType::LSH_PROJECTION, OperandType::TENSOR_FLOAT32}, float32::lsh_projection}, 948 //{{OperationType::LSTM, OperandType::TENSOR_FLOAT32}, float32::lstm }, 949 {{OperationType::MAX_POOL_2D, OperandType::TENSOR_FLOAT32}, float32::max_pool_2d}, 950 {{OperationType::MUL, OperandType::TENSOR_FLOAT32}, float32::mul}, 951 {{OperationType::RELU, OperandType::TENSOR_FLOAT32}, float32::relu}, 952 {{OperationType::RELU1, OperandType::TENSOR_FLOAT32}, float32::relu1}, 953 {{OperationType::RELU6, OperandType::TENSOR_FLOAT32}, float32::relu6}, 954 {{OperationType::RESHAPE, OperandType::TENSOR_FLOAT32}, float32::reshape}, 955 {{OperationType::RESIZE_BILINEAR, OperandType::TENSOR_FLOAT32}, float32::resize_bilinear}, 956 //{{OperationType::RNN, OperandType::TENSOR_FLOAT32}, float32::rnn}, 957 {{OperationType::SOFTMAX, OperandType::TENSOR_FLOAT32}, float32::softmax}, 958 //{{OperationType::SPACE_TO_DEPTH, OperandType::TENSOR_FLOAT32}, float32::space_to_depth}, 959 //{{OperationType::SVDF, OperandType::TENSOR_FLOAT32}, float32::svdf }, 960 {{OperationType::TANH, OperandType::TENSOR_FLOAT32}, float32::tanh}, 961 */ 962 963 // -------------------- QUANTIZED 8-BIT ASYMMETRICAL ------------------ 964 {{OperationType::ADD, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::add}, 965 {{OperationType::AVERAGE_POOL_2D, OperandType::TENSOR_QUANT8_ASYMM}, 966 quant8_asym::average_pool_2d}, 967 {{OperationType::CONCATENATION, OperandType::TENSOR_QUANT8_ASYMM}, 968 quant8_asym::concatenation}, 969 {{OperationType::CONV_2D, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::conv_2d}, 970 {{OperationType::DEPTHWISE_CONV_2D, OperandType::TENSOR_QUANT8_ASYMM}, 971 quant8_asym::depthwise_conv_2d}, 972 //{{OperationType::DEPTH_TO_SPACE, OperandType::TENSOR_QUANT8_ASYMM}, 973 // quant8_asym::depth_to_space}, 974 {{OperationType::DEQUANTIZE, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::dequantize}, 975 //{{OperationType::EMBEDDING_LOOKUP, OperandType::TENSOR_QUANT8_ASYMM}, 976 // quant8_asym::embedding_lookup}, 977 {{OperationType::FULLY_CONNECTED, OperandType::TENSOR_QUANT8_ASYMM}, 978 quant8_asym::fully_connected}, 979 //{{OperationType::HASHTABLE_LOOKUP, OperandType::TENSOR_QUANT8_ASYMM}, 980 // quant8_asym::hashtable_lookup}, 981 {{OperationType::LOGISTIC, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::logistic}, 982 //{{OperationType::LSH_PROJECTION, OperandType::TENSOR_QUANT8_ASYMM}, 983 // quant8_asym::lsh_projection}, 984 {{OperationType::MAX_POOL_2D, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::max_pool_2d}, 985 {{OperationType::MUL, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::mul}, 986 {{OperationType::RELU, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::relu}, 987 {{OperationType::RELU1, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::relu1}, 988 {{OperationType::RELU6, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::relu6}, 989 {{OperationType::RESHAPE, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::reshape}, 990 {{OperationType::SOFTMAX, OperandType::TENSOR_QUANT8_ASYMM}, quant8_asym::softmax}, 991 //{{OperationType::SPACE_TO_DEPTH, OperandType::TENSOR_QUANT8_ASYMM}, 992 // quant8_asym::space_to_depth}, 993 }; 994 995 // The following functions are normally used by float32, but those 996 // operations have been temporarily disabled. Void explicitly marks them as 997 // unused, and prevents the compiler from throwing an error. 998 (void)float32::add; 999 (void)float32::average_pool_2d; 1000 (void)float32::concatenation; 1001 (void)float32::conv_2d; 1002 (void)float32::depthwise_conv_2d; 1003 (void)float32::fully_connected; 1004 (void)float32::l2_pool_2d; 1005 (void)float32::local_response_normalization; 1006 (void)float32::logistic; 1007 (void)float32::max_pool_2d; 1008 (void)float32::mul; 1009 (void)float32::relu; 1010 (void)float32::relu1; 1011 (void)float32::relu6; 1012 (void)float32::reshape; 1013 (void)float32::resize_bilinear; 1014 (void)float32::softmax; 1015 (void)float32::tanh; 1016 1017 return table; 1018 } 1019 1020 } // namespace hexagon 1021 } // namespace implementation 1022 } // namespace V1_0 1023 } // namespace neuralnetworks 1024 } // namespace hardware 1025 } // namespace android 1026