0

I've built a Keras model with two inputs that I'd like to predict on with SNPE on my phone. I've already converted it successfully, it's just the C++ code that I'm having trouble with right now. I'm able to predict on a model with one input with any shape 1D array, but I now have a model that takes two 1D arrays of size 1.

So in Keras, predicting looks like this: model.predict([np.array([.4]), np.array([.6])])

And the SNPE code I have to predict:

void init_model(){
  zdl::DlSystem::Runtime_t runt=checkRuntime();
  initializeSNPE(runt);
}

float run_model(float a, float b){
  std::vector<float> inputVec;
  std::vector<float> inputVec2;
  inputVec.push_back(a);
  inputVec2.push_back(b);
  std::unique_ptr<zdl::DlSystem::ITensor> inputTensor = loadInputTensor(snpe, inputVec);
  std::unique_ptr<zdl::DlSystem::ITensor> inputTensor2 = loadInputTensor(snpe, inputVec2);  // what do I do with this?
  zdl::DlSystem::ITensor* oTensor = executeNetwork(snpe, inputTensor);
  return returnOutput(oTensor);
}

The functions I'm using are modified from SNPE's website. It works well with my prior uses of predicting on a single array:

zdl::DlSystem::Runtime_t checkRuntime()
{
    static zdl::DlSystem::Version_t Version = zdl::SNPE::SNPEFactory::getLibraryVersion();
    static zdl::DlSystem::Runtime_t Runtime;
    std::cout << "SNPE Version: " << Version.asString().c_str() << std::endl; //Print Version number
    std::cout << "\ntest";
    if (zdl::SNPE::SNPEFactory::isRuntimeAvailable(zdl::DlSystem::Runtime_t::GPU)) {
        Runtime = zdl::DlSystem::Runtime_t::GPU;
    } else {
        Runtime = zdl::DlSystem::Runtime_t::CPU;
    }

    return Runtime;
}

void initializeSNPE(zdl::DlSystem::Runtime_t runtime) {
  std::unique_ptr<zdl::DlContainer::IDlContainer> container;
  container = zdl::DlContainer::IDlContainer::open("/path/to/model.dlc");
  //printf("loaded model\n");
  int counter = 0;
  zdl::SNPE::SNPEBuilder snpeBuilder(container.get());
  snpe = snpeBuilder.setOutputLayers({})
                      .setRuntimeProcessor(runtime)
                      .setUseUserSuppliedBuffers(false)
                      .setPerformanceProfile(zdl::DlSystem::PerformanceProfile_t::HIGH_PERFORMANCE)
                      .build();
}

std::unique_ptr<zdl::DlSystem::ITensor> loadInputTensor(std::unique_ptr<zdl::SNPE::SNPE> &snpe, std::vector<float> inputVec) {
  std::unique_ptr<zdl::DlSystem::ITensor> input;
  const auto &strList_opt = snpe->getInputTensorNames();
  if (!strList_opt) throw std::runtime_error("Error obtaining Input tensor names");
  const auto &strList = *strList_opt;

  const auto &inputDims_opt = snpe->getInputDimensions(strList.at(0));
  const auto &inputShape = *inputDims_opt;

  input = zdl::SNPE::SNPEFactory::getTensorFactory().createTensor(inputShape);
  std::copy(inputVec.begin(), inputVec.end(), input->begin());

  return input;
}

float returnOutput(const zdl::DlSystem::ITensor* tensor) {
  float op = *tensor->cbegin();
  return op;
}

zdl::DlSystem::ITensor* executeNetwork(std::unique_ptr<zdl::SNPE::SNPE>& snpe,
                    std::unique_ptr<zdl::DlSystem::ITensor>& input) {
  static zdl::DlSystem::TensorMap outputTensorMap;
  snpe->execute(input.get(), outputTensorMap);
  zdl::DlSystem::StringList tensorNames = outputTensorMap.getTensorNames();

  const char* name = tensorNames.at(0);  // only should the first
  auto tensorPtr = outputTensorMap.getTensor(name);
  return tensorPtr;
}

But I have no clue how to combine the two input tensors I've gotten to use with the executeNetwork function. Any help would be appreciated.

Shane Smiskol
  • 952
  • 1
  • 11
  • 38

1 Answers1

1

You can use zdl::DlSystem::TensorMap and set it to execute function.

zdl::DlSystem::TensorMap inputTensorMap;
zdl::DlSystem::TensorMap outputTensorMap;
zdl::DlSystem::ITensor *inputTensor1;
zdl::DlSystem::ITensor *inputTensor2;
inputTensorMap.add("input_1", inputTensor1);
inputTensorMap.add("input_2", inputTensor2);
model->execute(inputTensorMap, outputTensorMap);

Note that you have to iterate through inputTensorMap after and delete ITensor's by yourself with delete.

Vlad
  • 26
  • 3
  • Thanks! I'm not using this specific code anymore, but I'll definitely come back once I need a model with multi inputs working – Shane Smiskol Mar 07 '20 at 01:46