Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 187c5971 authored by Xusong Wang's avatar Xusong Wang
Browse files

Add 1.2 NN HAL interface for dynamic output shape.

Let notify_1_2() notify output shapes.

Document unspecified dimensions and rank.

Bug: 73506513
Bug: 77234888
Test: NeuralNetworksTest_static
Test: VtsHalNeuralnetworksV1_xTargetTest with 1.2 sample driver
Change-Id: I01108913212d9f4aa47daf2f293ea19259925865
parent a885b5d9
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
@@ -139,8 +139,10 @@ Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
    return Void();
    return Void();
}
}


Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus) {
Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
                                           const hidl_vec<OutputShape>& outputShapes) {
    mErrorStatus = errorStatus;
    mErrorStatus = errorStatus;
    mOutputShapes = outputShapes;
    CallbackBase::notify();
    CallbackBase::notify();
    return Void();
    return Void();
}
}
@@ -150,6 +152,11 @@ ErrorStatus ExecutionCallback::getStatus() {
    return mErrorStatus;
    return mErrorStatus;
}
}


const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() {
    wait();
    return mOutputShapes;
}

}  // namespace implementation
}  // namespace implementation
}  // namespace V1_2
}  // namespace V1_2
}  // namespace neuralnetworks
}  // namespace neuralnetworks
+58 −11
Original line number Original line Diff line number Diff line
@@ -275,8 +275,9 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback {
     * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
     * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
     * be called exactly once on a given ExecutionCallback object.
     * be called exactly once on a given ExecutionCallback object.
     *
     *
     * @param status Error status returned from asynchronously preparing the
     * @param status Error status returned from launching the asynchronous task
     *               model; will be:
     *               (if the launch fails) or from the asynchronous task itself
     *               (if the launch succeeds). Must be:
     *               - NONE if the asynchronous execution was successful
     *               - NONE if the asynchronous execution was successful
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - GENERAL_FAILURE if there is an unspecified error
     *               - GENERAL_FAILURE if there is an unspecified error
@@ -285,27 +286,73 @@ class ExecutionCallback : public CallbackBase, public IExecutionCallback {
     *               - INVALID_ARGUMENT if the input request is invalid
     *               - INVALID_ARGUMENT if the input request is invalid
     */
     */
    Return<void> notify(ErrorStatus status) override;
    Return<void> notify(ErrorStatus status) override;
    Return<void> notify_1_2(ErrorStatus status) override;

    /**
     * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to
     * also notify output shapes along with error status.
     *
     * @param status Error status returned from launching the asynchronous task
     *               (if the launch fails) or from the asynchronous task itself
     *               (if the launch succeeds). Must be:
     *               - NONE if the asynchronous execution was successful
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - GENERAL_FAILURE if the asynchronous task resulted in an
     *                 unspecified error
     *               - OUTPUT_INSUFFICIENT_SIZE if at least one output
     *                 operand buffer is not large enough to store the
     *                 corresponding output
     *               - INVALID_ARGUMENT if one of the input arguments to
     *                 prepareModel is invalid
     * @param outputShapes A list of shape information of model output operands.
     *                     The index into "outputShapes" corresponds to the index
     *                     of the output operand in the Request outputs vector.
     *                     outputShapes must be empty unless the status is either
     *                     NONE or OUTPUT_INSUFFICIENT_SIZE.
     */
    Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes) override;


    /**
    /**
     * Retrieves the error status returned from the asynchronous task launched
     * Retrieves the error status returned from the asynchronous task launched
     * by IPreparedModel::execute. If IPreparedModel::execute has not finished
     * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
     * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
     * asynchronously executing, this call will block until the asynchronous task
     * asynchronously executing, this call will block until the asynchronous task
     * notifies the object.
     * notifies the object.
     *
     *
     * @return status Error status returned from asynchronously preparing the
     * @return status Error status returned from launching the asynchronous task
     *                model; will be:
     *                (if the launch fails) or from the asynchronous task itself
     *                (if the launch succeeds). Must be:
     *                - NONE if the asynchronous execution was successful
     *                - NONE if the asynchronous execution was successful
     *                - DEVICE_UNAVAILABLE if driver is offline or busy
     *                - DEVICE_UNAVAILABLE if driver is offline or busy
     *                - GENERAL_FAILURE if there is an unspecified error
     *                - GENERAL_FAILURE if the asynchronous task resulted in an
     *                - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
     *                  unspecified error
     *                  not large enough to store the resultant values
     *                - OUTPUT_INSUFFICIENT_SIZE if at least one output
     *                - INVALID_ARGUMENT if the input request is invalid
     *                  operand buffer is not large enough to store the
     *                  corresponding output
     *                - INVALID_ARGUMENT if one of the input arguments to
     *                  prepareModel is invalid
     */
     */
    ErrorStatus getStatus();
    ErrorStatus getStatus();


    /**
     * Retrieves the output shapes returned from the asynchronous task launched
     * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
     * asynchronously executing, this call will block until the asynchronous task
     * notifies the object.
     *
     * If the asynchronous task was launched by IPreparedModel::execute, an empty vector
     * will be returned.
     *
     * @return outputShapes A list of shape information of model output operands.
     *                      The index into "outputShapes" corresponds to the index
     *                      of the output operand in the Request outputs vector.
     *                      outputShapes must be empty unless the status is either
     *                      NONE or OUTPUT_INSUFFICIENT_SIZE.
     */
    const std::vector<OutputShape>& getOutputShapes();

   private:
   private:
    ErrorStatus mErrorStatus;
    ErrorStatus mErrorStatus;
    std::vector<OutputShape> mOutputShapes;
};
};




+28 −9
Original line number Original line Diff line number Diff line
@@ -89,13 +89,24 @@ static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& prepar
                                                sp<ExecutionCallback>& callback) {
                                                sp<ExecutionCallback>& callback) {
    return preparedModel->execute_1_2(request, callback);
    return preparedModel->execute_1_2(request, callback);
}
}
static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&) {
static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&,
                                                hidl_vec<OutputShape>*) {
    ADD_FAILURE() << "asking for synchronous execution at V1_0";
    ADD_FAILURE() << "asking for synchronous execution at V1_0";
    return ErrorStatus::GENERAL_FAILURE;
    return ErrorStatus::GENERAL_FAILURE;
}
}
static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
                                                const Request& request) {
                                                const Request& request,
    return preparedModel->executeSynchronously(request);
                                                hidl_vec<OutputShape>* outputShapes) {
    ErrorStatus result;
    Return<void> ret = preparedModel->executeSynchronously(
        request, [&result, &outputShapes](ErrorStatus error, const hidl_vec<OutputShape>& shapes) {
            result = error;
            *outputShapes = shapes;
        });
    if (!ret.isOk()) {
        return ErrorStatus::GENERAL_FAILURE;
    }
    return result;
}
}
enum class Synchronously { NO, YES };
enum class Synchronously { NO, YES };
const float kDefaultAtol = 1e-5f;
const float kDefaultAtol = 1e-5f;
@@ -197,6 +208,8 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo
        inputMemory->commit();
        inputMemory->commit();
        outputMemory->commit();
        outputMemory->commit();


        ErrorStatus executionStatus;
        hidl_vec<OutputShape> outputShapes;
        if (sync == Synchronously::NO) {
        if (sync == Synchronously::NO) {
            SCOPED_TRACE("asynchronous");
            SCOPED_TRACE("asynchronous");


@@ -211,18 +224,24 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo


            // retrieve execution status
            // retrieve execution status
            executionCallback->wait();
            executionCallback->wait();
            ErrorStatus executionReturnStatus = executionCallback->getStatus();
            executionStatus = executionCallback->getStatus();
            EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
            outputShapes = executionCallback->getOutputShapes();
        } else {
        } else {
            SCOPED_TRACE("synchronous");
            SCOPED_TRACE("synchronous");


            // execute
            // execute
            Return<ErrorStatus> executionStatus = ExecutePreparedModel(
            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
                preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
                preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools},
            ASSERT_TRUE(executionStatus.isOk());
                &outputShapes);
            EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionStatus));
            ASSERT_TRUE(executionReturnStatus.isOk());
            executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
        }
        }


        ASSERT_EQ(ErrorStatus::NONE, executionStatus);
        // TODO(xusongw): Check if the returned output shapes match with expectation once the
        //                sample driver implementation of dynamic output shape is finished.
        ASSERT_EQ(outputShapes.size(), 0);

        // validate results
        // validate results
        outputMemory->read();
        outputMemory->read();
        copy_back(&test, outputs_info, outputPtr);
        copy_back(&test, outputs_info, outputPtr);
+1 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ hidl_interface {
        "Operation",
        "Operation",
        "OperationType",
        "OperationType",
        "OperationTypeRange",
        "OperationTypeRange",
        "OutputShape",
    ],
    ],
    gen_java: false,
    gen_java: false,
}
}
+10 −3
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package android.hardware.neuralnetworks@1.2;


import @1.0::ErrorStatus;
import @1.0::ErrorStatus;
import @1.0::IExecutionCallback;
import @1.0::IExecutionCallback;
import OutputShape;


/**
/**
 * IExecutionCallback must be used to return the error status result from an
 * IExecutionCallback must be used to return the error status result from an
@@ -39,10 +40,16 @@ interface IExecutionCallback extends @1.0::IExecutionCallback {
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - GENERAL_FAILURE if the asynchronous task resulted in an
     *               - GENERAL_FAILURE if the asynchronous task resulted in an
     *                 unspecified error
     *                 unspecified error
     *               - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
     *               - OUTPUT_INSUFFICIENT_SIZE if at least one output
     *                 not large enough to store the resultant values
     *                 operand buffer is not large enough to store the
     *                 corresponding output
     *               - INVALID_ARGUMENT if one of the input arguments to
     *               - INVALID_ARGUMENT if one of the input arguments to
     *                 prepareModel is invalid
     *                 prepareModel is invalid
     * @param outputShapes A list of shape information of model output operands.
     *                     The index into "outputShapes" corresponds with to index
     *                     of the output operand in the Request outputs vector.
     *                     outputShapes must be empty unless the status is either
     *                     NONE or OUTPUT_INSUFFICIENT_SIZE.
     */
     */
    oneway notify_1_2(ErrorStatus status);
    oneway notify_1_2(ErrorStatus status, vec<OutputShape> outputShapes);
};
};
Loading