in nn-samples/basic/src/main/cpp/simple_model.cpp [107:369]
bool SimpleModel::CreateCompiledModel() {
int32_t status;
// Create the ANeuralNetworksModel handle.
status = ANeuralNetworksModel_create(&model_);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_create failed");
return false;
}
uint32_t dimensions[] = {dimLength_};
ANeuralNetworksOperandType float32TensorType{
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
.dimensionCount = sizeof(dimensions) / sizeof(dimensions[0]),
.dimensions = dimensions,
.scale = 0.0f,
.zeroPoint = 0,
};
ANeuralNetworksOperandType scalarInt32Type{
.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0,
};
/**
* Add operands and operations to construct the model.
*
* Operands are implicitly identified by the order in which they are added to the model,
* starting from 0.
*
* These indexes are not returned by the model_addOperand call. The application must
* manage these values. Here, we use opIdx to do the bookkeeping.
*/
uint32_t opIdx = 0;
// We first add the operand for the NONE activation function, and set its
// value to ANEURALNETWORKS_FUSED_NONE.
// This constant scalar operand will be used for all 3 operations.
status = ANeuralNetworksModel_addOperand(model_, &scalarInt32Type);
uint32_t fusedActivationFuncNone = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
fusedActivationFuncNone);
return false;
}
FuseCode fusedActivationCodeValue = ANEURALNETWORKS_FUSED_NONE;
status = ANeuralNetworksModel_setOperandValue(
model_, fusedActivationFuncNone, &fusedActivationCodeValue,
sizeof(fusedActivationCodeValue));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_setOperandValue failed for operand (%d)",
fusedActivationFuncNone);
return false;
}
// Add operands for the tensors.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t tensor0 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
tensor0);
return false;
}
// tensor0 is a constant tensor that was established during training.
// We read these values from the corresponding ANeuralNetworksMemory object.
status = ANeuralNetworksModel_setOperandValueFromMemory(model_,
tensor0,
memoryModel_,
offset_,
tensorSize_ * sizeof(float));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_setOperandValueFromMemory failed for operand (%d)",
tensor0);
return false;
}
// tensor1 is one of the user provided input tensors to the trained model.
// Its value is determined pre-execution.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t tensor1 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
tensor1);
return false;
}
// tensor2 is a constant tensor that was established during training.
// We read these values from the corresponding ANeuralNetworksMemory object.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t tensor2 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
tensor2);
return false;
}
status = ANeuralNetworksModel_setOperandValueFromMemory(
model_, tensor2, memoryModel_, offset_ + tensorSize_ * sizeof(float),
tensorSize_ * sizeof(float));
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_setOperandValueFromMemory failed for operand (%d)",
tensor2);
return false;
}
// tensor3 is one of the user provided input tensors to the trained model.
// Its value is determined pre-execution.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t tensor3 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
tensor3);
return false;
}
// intermediateOutput0 is the output of the first ADD operation.
// Its value is computed during execution.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t intermediateOutput0 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
intermediateOutput0);
return false;
}
// intermediateOutput1 is the output of the second ADD operation.
// Its value is computed during execution.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t intermediateOutput1 = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
intermediateOutput1);
return false;
}
// multiplierOutput is the output of the MUL operation.
// Its value will be computed during execution.
status = ANeuralNetworksModel_addOperand(model_, &float32TensorType);
uint32_t multiplierOutput = opIdx++;
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperand failed for operand (%d)",
multiplierOutput);
return false;
}
// Add the first ADD operation.
std::vector<uint32_t> add1InputOperands = {
tensor0,
tensor1,
fusedActivationFuncNone,
};
status = ANeuralNetworksModel_addOperation(model_, ANEURALNETWORKS_ADD,
add1InputOperands.size(), add1InputOperands.data(),
1, &intermediateOutput0);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperation failed for ADD_1");
return false;
}
// Add the second ADD operation.
// Note the fusedActivationFuncNone is used again.
std::vector<uint32_t> add2InputOperands = {
tensor2,
tensor3,
fusedActivationFuncNone,
};
status = ANeuralNetworksModel_addOperation(model_, ANEURALNETWORKS_ADD,
add2InputOperands.size(),add2InputOperands.data(),
1, &intermediateOutput1);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperation failed for ADD_2");
return false;
}
// Add the MUL operation.
// Note that intermediateOutput0 and intermediateOutput1 are specified
// as inputs to the operation.
std::vector<uint32_t> mulInputOperands = {
intermediateOutput0,
intermediateOutput1,
fusedActivationFuncNone};
status = ANeuralNetworksModel_addOperation(model_, ANEURALNETWORKS_MUL,
mulInputOperands.size(),mulInputOperands.data(),
1, &multiplierOutput);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_addOperation failed for MUL");
return false;
}
// Identify the input and output tensors to the model.
// Inputs: {tensor1, tensor3}
// Outputs: {multiplierOutput}
std::vector<uint32_t> modelInputOperands = {
tensor1, tensor3,
};
status = ANeuralNetworksModel_identifyInputsAndOutputs(model_,
modelInputOperands.size(),
modelInputOperands.data(),
1,
&multiplierOutput);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_identifyInputsAndOutputs failed");
return false;
}
// Finish constructing the model.
// The values of constant and intermediate operands cannot be altered after
// the finish function is called.
status = ANeuralNetworksModel_finish(model_);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksModel_finish failed");
return false;
}
// Create the ANeuralNetworksCompilation object for the constructed model.
status = ANeuralNetworksCompilation_create(model_, &compilation_);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksCompilation_create failed");
return false;
}
// Set the preference for the compilation, so that the runtime and drivers
// can make better decisions.
// Here we prefer to get the answer quickly, so we choose
// ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER.
status = ANeuralNetworksCompilation_setPreference(compilation_,
ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksCompilation_setPreference failed");
return false;
}
// Finish the compilation.
status = ANeuralNetworksCompilation_finish(compilation_);
if (status != ANEURALNETWORKS_NO_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"ANeuralNetworksCompilation_finish failed");
return false;
}
return true;
}