in nn-samples/basic/src/main/cpp/simple_model.cpp [378:492]
bool SimpleModel::Compute(float inputValue1, float inputValue2,
float *result) {
if (!result) {
return false;
}
// Create an ANeuralNetworksExecution object from the compiled model.
// Note:
// 1. All the input and output data are tied to the ANeuralNetworksExecution object.
// 2. Multiple concurrent execution instances could be created from the same compiled model.
// This sample only uses one execution of the compiled model.
ANeuralNetworksExecution *execution;
int32_t status = ANeuralNetworksExecution_create(compilation_, &execution);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksExecution_create failed");
return false;
}
// Set all the elements of the first input tensor (tensor1) to the same value as inputValue1.
// It's not a realistic example but it shows how to pass a small tensor
// to an execution.
std::fill(inputTensor1_.data(), inputTensor1_.data() + tensorSize_,
inputValue1);
// Tell the execution to associate inputTensor1 to the first of the two model inputs.
// Note that the index "0" here means the first operand of the modelInput list
// {tensor1, tensor3}, which means tensor1.
status = ANeuralNetworksExecution_setInput(execution, 0, nullptr,
inputTensor1_.data(),
tensorSize_ * sizeof(float));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksExecution_setInput failed for input1");
return false;
}
// Set the values of the second input operand (tensor3) to be inputValue2.
// In reality, the values in the shared memory region will be manipulated by
// other modules or processes.
float *inputTensor2Ptr = reinterpret_cast<float *>(mmap(nullptr, tensorSize_ * sizeof(float),
PROT_READ | PROT_WRITE, MAP_SHARED,
inputTensor2Fd_, 0));
for (int i = 0; i < tensorSize_; i++) {
*inputTensor2Ptr = inputValue2;
inputTensor2Ptr++;
}
munmap(inputTensor2Ptr, tensorSize_ * sizeof(float));
// ANeuralNetworksExecution_setInputFromMemory associates the operand with a shared memory
// region to minimize the number of copies of raw data.
// Note that the index "1" here means the second operand of the modelInput list
// {tensor1, tensor3}, which means tensor3.
status = ANeuralNetworksExecution_setInputFromMemory(execution, 1, nullptr,
memoryInput2_, 0,
tensorSize_ * sizeof(float));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksExecution_setInputFromMemory failed for input2");
return false;
}
// Set the output tensor that will be filled by executing the model.
// We use shared memory here to minimize the copies needed for getting the output data.
status = ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr,
memoryOutput_, 0,
tensorSize_ * sizeof(float));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksExecution_setOutputFromMemory failed for output");
return false;
}
// Start the execution of the model.
// Note that the execution here is asynchronous, and an ANeuralNetworksEvent object will be
// created to monitor the status of the execution.
ANeuralNetworksEvent *event = nullptr;
status = ANeuralNetworksExecution_startCompute(execution, &event);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksExecution_startCompute failed");
return false;
}
// Wait until the completion of the execution. This could be done on a different
// thread. By waiting immediately, we effectively make this a synchronous call.
status = ANeuralNetworksEvent_wait(event);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksEvent_wait failed");
return false;
}
ANeuralNetworksEvent_free(event);
ANeuralNetworksExecution_free(execution);
// Validate the results.
const float goldenRef = (inputValue1 + 0.5f) * (inputValue2 + 0.5f);
float *outputTensorPtr = reinterpret_cast<float *>(mmap(nullptr,
tensorSize_ * sizeof(float),
PROT_READ, MAP_SHARED,
outputTensorFd_, 0));
for (int32_t idx = 0; idx < tensorSize_; idx++) {
float delta = outputTensorPtr[idx] - goldenRef;
delta = (delta < 0.0f) ? (-delta) : delta;
if (delta > FLOAT_EPISILON) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"Output computation Error: output0(%f), delta(%f) @ idx(%d)",
outputTensorPtr[0], delta, idx);
}
}
*result = outputTensorPtr[0];
munmap(outputTensorPtr, tensorSize_ * sizeof(float));
return result;
}