#include <arm_compute/runtime/CL/CLScheduler.h>
#include <arm_compute/runtime/CL/CLSubTensor.h>
#include <arm_compute/runtime/CL/functions/CLArithmeticAddition.h>
+#include <arm_compute/runtime/CL/functions/CLPixelWiseDivision.h>
#include <arm_compute/runtime/CL/functions/CLPoolingLayer.h>
#include <arm_compute/runtime/CL/functions/CLActivationLayer.h>
#include <arm_compute/runtime/CL/functions/CLScale.h>
public:
void visit(const ::internal::tflite::op::Add::Node &node) override;
+ void visit(const ::internal::tflite::op::Div::Node &node) override;
void visit(const ::internal::tflite::op::Conv2D::implicit::Node &node) override;
void visit(const ::internal::tflite::op::MaxPool2D::implicit::Node &node) override;
void visit(const ::internal::tflite::op::AvgPool2D::implicit::Node &node) override;
_builder.addStage(stage);
}
+void Planner::visit(const ::internal::tflite::op::Div::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ // TODO Support general broadcasting. Currently, broadcast works only when one operand is scalar
+ // or the operand's dimension size is one.
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+ const auto ofm_shape_rank = ofm_shape.rank();
+ if (ofm_shape_rank == 4)
+ {
+ _builder.addShapeConstr(ofm_index, asTensorInfo(ofm_shape.asFeature()));
+ }
+ else if (ofm_shape_rank == 1)
+ {
+ _builder.addShapeConstr(ofm_index, asTensorInfo(ofm_shape.asVector()));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ const auto lhs_shape = _ctx.at(lhs_index).shape();
+ const auto lhs_shape_rank = lhs_shape.rank();
+ if (lhs_shape_rank == 4)
+ {
+ _builder.addShapeConstr(lhs_index, asTensorInfo(lhs_shape.asFeature()));
+ }
+ else if (lhs_shape_rank == 1)
+ {
+ _builder.addShapeConstr(lhs_index, asTensorInfo(lhs_shape.asVector()));
+ }
+ else if (lhs_shape_rank == 0)
+ {
+ // scalar
+ _builder.addShapeConstr(lhs_index, asTensorInfo(1));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ const auto rhs_shape = _ctx.at(rhs_index).shape();
+ const auto rhs_shape_rank = rhs_shape.rank();
+ if (rhs_shape_rank == 4)
+ {
+ _builder.addShapeConstr(rhs_index, asTensorInfo(rhs_shape.asFeature()));
+ }
+ else if (rhs_shape_rank == 1)
+ {
+ _builder.addShapeConstr(rhs_index, asTensorInfo(rhs_shape.asVector()));
+ }
+ else if (rhs_shape_rank == 0)
+ {
+ // scalar
+ _builder.addShapeConstr(rhs_index, asTensorInfo(1));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScala<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ auto fn = make_layer<::arm_compute::CLPixelWiseDivision>();
+
+ // TODO Decide scale, overflow_policy, and rounding_policy.
+ // Currently, the default values are used.
+ fn->configure(lhs_alloc, rhs_alloc, ofm_alloc);
+
+ builder.append(std::move(fn));
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
void Planner::visit(const ::internal::tflite::op::Conv2D::implicit::Node &node)
{
const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
#include <stack>
+using namespace std::placeholders;
+
static void initFeatureTensor(::arm_compute::ITensor &tensor,
const nnfw::util::feature::Shape &feature_shape,
const uint8_t *feature_base, const size_t feature_size)
{
const auto rank = operands.at(operand_idx).shape().rank();
auto base = operands.at(operand_idx).data().base();
- ::arm_compute::ICLTensor &tensor = *(_plan.operands().at(operand_idx).ptr());
switch (rank)
{
case 0: // scalar
{
- initVectorTensor(tensor, base, 1);
+ auto initializer = std::bind(initVectorTensor, _1, base, 1);
+ _plan.operands().at(operand_idx).access(initializer);
break;
}
case 1: // vector
{
auto size = operands.at(operand_idx).shape().asVector();
- initVectorTensor(tensor, base, size);
+ auto initializer = std::bind(initVectorTensor, _1, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
break;
}
case 4: // feature
{
const auto feature_shape = operands.at(operand_idx).shape().asFeature();
auto size = operands.at(operand_idx).data().size();
- initFeatureTensor(tensor, feature_shape, base, size);
+ auto initializer = std::bind(initFeatureTensor, _1, feature_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
break;
}
default: