{
namespace tflite
{
+namespace op
+{
+
+struct NodeVisitor;
+
+struct Node
+{
+ virtual ~Node() = default;
+
+ virtual void accept(NodeVisitor &&) const = 0;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Conv2D
+{
+namespace implicit
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+ int32_t ker_index;
+ int32_t bias_index;
+
+ int32_t hstride;
+ int32_t vstride;
+
+ int32_t padding;
+ int32_t activation;
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param ¶m) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param ¶m(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace implicit
+} // namespace Conv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+
+struct NodeVisitor
+{
+ virtual ~NodeVisitor() = default;
+
+ virtual void visit(const Conv2D::implicit::Node &) = 0;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+
+class Sequence
+{
+public:
+ Sequence() = default;
+
+public:
+ uint32_t size(void) const { return _ops.size(); }
+
+public:
+ op::Node &at(uint32_t nth) { return *(_ops.at(nth)); }
+ const op::Node &at(uint32_t nth) const { return *(_ops.at(nth)); }
+
+private:
+ Sequence &emplace_back(std::unique_ptr<op::Node> &&node)
+ {
+ _ops.emplace_back(std::move(node));
+ return (*this);
+ }
+public:
+ template <typename T, typename... Args> Sequence &emplace_back(Args&&... args)
+ {
+ emplace_back(std::unique_ptr<T>(new T{std::forward<Args>(args)...}));
+ }
+
+private:
+ std::vector<std::unique_ptr<op::Node>> _ops;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
class Model
{
operand::Set &operands(void) { return _operands; }
const operand::Set &operands(void) const { return _operands; }
+public:
+ op::Sequence &operations(void) { return _operations; }
+ const op::Sequence &operations(void) const { return _operations; }
+
private:
operand::Set _operands;
+ op::Sequence _operations;
};
} // namespace tflite
#include <nnapi.h>
#include <cassert>
+#include <stdexcept>
#include "model.h"
#include "memory.h"
uint32_t inputCount, const uint32_t* inputs,
uint32_t outputCount, const uint32_t* outputs)
{
+ switch (type)
+ {
+ case ANEURALNETWORKS_CONV_2D:
+ {
+ // inputCount is either 7 or 9 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 7
+ // - Padding is explicit when inputCount is 9
+ assert(inputCount == 7 || inputCount == 9);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ internal::tflite::op::Conv2D::implicit::Param param;
+
+ param.ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID)
+ // 4 -> Stride (width)
+ // 5 -> Stride (height)
+ // 6 -> Activation
+ param.ifm_index = inputs[0];
+ param.ker_index = inputs[1];
+ param.bias_index = inputs[2];
+ // TODO Set hstride/vstride/padding/activation
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<internal::tflite::op::Conv2D::implicit::Node>(param);
+ }
+ else
+ {
+ throw std::runtime_error{"Explicit padding in Conv2D is not supported, yet"};
+ }
+
+ break;
+ }
+ default:
+ throw std::runtime_error{"Not supported operation"};
+ };
+
return ANEURALNETWORKS_NO_ERROR;
}