const auto ker_index = node.getInputs().at(1);
const auto bias_index = node.getInputs().at(2);
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
- const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
// Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
- _builder.addShapeConstr(ker_index, ::internal::asTensorInfo(ker_shape));
- _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size));
+ _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(_ctx.at(ofm_index).shape(),
+ _ctx.at(ofm_index).typeInfo()));
+ _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(_ctx.at(ifm_index).shape(),
+ _ctx.at(ifm_index).typeInfo()));
+ _builder.addShapeConstr(ker_index, ::internal::asTensorInfo(_ctx.at(ker_index).shape(),
+ _ctx.at(ker_index).typeInfo()));
+ _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(_ctx.at(bias_index).shape(),
+ _ctx.at(bias_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
-
// Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
+ _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(_ctx.at(ofm_index).shape(),
+ _ctx.at(ofm_index).typeInfo()));
+ _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(_ctx.at(ifm_index).shape(),
+ _ctx.at(ifm_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
-
// Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
+ _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(_ctx.at(ofm_index).shape(),
+ _ctx.at(ofm_index).typeInfo()));
+ _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(_ctx.at(ifm_index).shape(),
+ _ctx.at(ifm_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
{
const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- // NOTE This implementation assumes that input and output are a feature
- // TODO Remove this assumption
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
-
// NOTE This implementation assumes concat over feature depth
// TODO Remove this assumption
assert(_ctx.at(::neurun::graph::operand::Index{node.param().axis_index}).asScalar<int32_t>() ==
3);
// Set Shape Constraints (for output)
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
+ _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(_ctx.at(ofm_index).shape(),
+ _ctx.at(ofm_index).typeInfo()));
// Set Shape Constraints (for input)
for (const auto &index : node.getInputs())
{
const ::neurun::graph::operand::Index ifm_index{index};
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
+ _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(_ctx.at(ifm_index).shape(),
+ _ctx.at(ifm_index).typeInfo()));
}
// backend
const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
- assert(_ctx.at(output_index).shape().rank() == 2);
- const auto output_size = _ctx.at(output_index).shape().dim(1);
-
- // NOTE We assume that input is a feature map
- // TODO Remove this restriction!
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
-
- assert(_ctx.at(weight_index).shape().rank() == 2);
- const auto num_output = _ctx.at(weight_index).shape().dim(0);
- const auto input_size = _ctx.at(weight_index).shape().dim(1);
- assert(ifm_shape.C * ifm_shape.H * ifm_shape.W == input_size);
-
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
// Set Shape Constraints
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(output_size));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape));
- _builder.addShapeConstr(weight_index,
- ::internal::asTensorInfo(num_output /*H*/, input_size /*W*/));
- _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size));
+ _builder.addShapeConstr(output_index, ::internal::asTensorInfo(_ctx.at(output_index).shape(),
+ _ctx.at(output_index).typeInfo()));
+ _builder.addShapeConstr(input_index, ::internal::asTensorInfo(_ctx.at(input_index).shape(),
+ _ctx.at(input_index).typeInfo()));
+ _builder.addShapeConstr(weight_index, ::internal::asTensorInfo(_ctx.at(weight_index).shape(),
+ _ctx.at(weight_index).typeInfo()));
+ _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(_ctx.at(bias_index).shape(),
+ _ctx.at(bias_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
assert(_ctx.at(output_index).shape().rank() == 2);
assert(_ctx.at(output_index).shape().dim(0) == 1);
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
- const auto out_size = _ctx.at(output_index).shape().dim(1);
-
// NOTE Vector element ordering issue arises when H or W is not 1
- assert(ifm_shape.H == 1);
- assert(ifm_shape.W == 1);
- assert((ifm_shape.C * ifm_shape.H * ifm_shape.W) == out_size);
+ assert(_ctx.at(input_index).shape().dim(1) == 1); // H
+ assert(_ctx.at(input_index).shape().dim(2) == 1); // W
+ // input(4D)'s C * H * W == output(2D)'s W
+ assert((_ctx.at(input_index).shape().dim(3) * _ctx.at(input_index).shape().dim(1) *
+ _ctx.at(input_index).shape().dim(2)) == _ctx.at(output_index).shape().dim(1));
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(out_size));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape));
+ _builder.addShapeConstr(output_index, ::internal::asTensorInfo(_ctx.at(output_index).shape(),
+ _ctx.at(output_index).typeInfo()));
+ _builder.addShapeConstr(input_index, ::internal::asTensorInfo(_ctx.at(input_index).shape(),
+ _ctx.at(input_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
assert(_ctx.at(input_index).shape().dim(0) == _ctx.at(output_index).shape().dim(0));
assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(output_index).shape().dim(1));
- const uint32_t len = _ctx.at(output_index).shape().dim(1);
-
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(len));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(len));
+ _builder.addShapeConstr(output_index, ::internal::asTensorInfo(_ctx.at(output_index).shape(),
+ _ctx.at(output_index).typeInfo()));
+ _builder.addShapeConstr(input_index, ::internal::asTensorInfo(_ctx.at(input_index).shape(),
+ _ctx.at(input_index).typeInfo()));
// backend
auto backend = node.lower_info()->backend();
#include "Convert.h"
+#include "internal/Swizzle.h"
+#include "graph/operand/DataType.h"
+
namespace internal
{
-::arm_compute::TensorShape asTensorShape(int32_t h, int32_t w)
+::arm_compute::TensorShape asTensorShape(const ::neurun::graph::operand::Shape &shape,
+ bool apply_dim_correction = true)
{
- return ::arm_compute::TensorShape(w, h);
-}
+ const uint32_t rank = shape.rank();
-::arm_compute::TensorShape asTensorShape(const nnfw::util::feature::Shape &shape)
-{
- return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N);
-}
+ ::arm_compute::TensorShape res{};
-::arm_compute::TensorShape asTensorShape(const nnfw::util::kernel::Shape &shape)
-{
- return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N);
-}
+ res.set_num_dimensions(rank);
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::feature::Shape &shape)
-{
- return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32);
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ // NOTE In some cases, in incorrect dimensions is required.
+ // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of
+ // LSTM is used as the weight of the FullyConnected.
+ // The FullyConnected's weight must be greater or equal than 2-dimensions.
+ // However, if the dimension correction is applied to input_to_input_weights with input_size
+ // equal to 1, it will be changed to 1-D.
+ // So input_to_input_weights is not used by the weight of FullyConnected.
+ res.set(ToARMComputeAxis(rank, axis).value(), shape.dim(axis), apply_dim_correction);
+ }
+
+ return res;
}
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::kernel::Shape &shape)
+::arm_compute::DataType asDataType(const ::neurun::graph::operand::DataType &type)
{
- return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32);
+ switch (type)
+ {
+ case ::neurun::graph::operand::DataType::SCALAR_FLOAT32:
+ case ::neurun::graph::operand::DataType::TENSOR_FLOAT32:
+ return ::arm_compute::DataType::F32;
+ case ::neurun::graph::operand::DataType::SCALAR_INT32:
+ case ::neurun::graph::operand::DataType::TENSOR_INT32:
+ return ::arm_compute::DataType::S32;
+ case ::neurun::graph::operand::DataType::SCALAR_UINT32:
+ return ::arm_compute::DataType::U32;
+ case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM:
+ return ::arm_compute::DataType::QASYMM8;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
}
-::arm_compute::TensorInfo asTensorInfo(int32_t size)
+::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset)
{
- return ::arm_compute::TensorInfo(::arm_compute::TensorShape(size), 1,
- ::arm_compute::DataType::F32);
+ return ::arm_compute::QuantizationInfo(scale, offset);
}
-::arm_compute::TensorInfo asTensorInfo(int32_t h, int32_t w)
+::arm_compute::TensorInfo asTensorInfo(const ::neurun::graph::operand::Shape &shape,
+ const ::neurun::graph::operand::TypeInfo &typeInfo)
{
- return ::arm_compute::TensorInfo(::arm_compute::TensorShape(w, h), 1,
- ::arm_compute::DataType::F32);
+ return ::arm_compute::TensorInfo(asTensorShape(shape), 1, asDataType(typeInfo.type()),
+ asQuantizationInfo(typeInfo.scale(), typeInfo.offset()));
}
} // namespace internal
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __INTERNAL_SWIZZLE_H__
+#define __INTERNAL_SWIZZLE_H__
+
+#include <cassert>
+
+namespace internal
+{
+
+class ARMComputeAxis
+{
+public:
+ ARMComputeAxis() = default;
+
+public:
+ explicit ARMComputeAxis(uint32_t value) : _value{value}
+ {
+ // DO NOTHING
+ }
+
+public:
+ uint32_t value(void) const { return _value; }
+
+private:
+ uint32_t _value;
+};
+
+// Convert T/F Lite / NNAPI axis (based on ...NHWC) to ARMCompute axis (WHCN...)
+inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis)
+{
+ assert(rank > axis);
+ const ARMComputeAxis reversed{(rank - axis) - 1};
+
+ if (rank < 4)
+ {
+ return reversed;
+ }
+
+ // DEPTH
+ if (0 == reversed.value())
+ {
+ return ARMComputeAxis{2};
+ }
+ // WIDTH
+ if (1 == reversed.value())
+ {
+ return ARMComputeAxis{0};
+ }
+ // HEIGHT
+ if (2 == reversed.value())
+ {
+ return ARMComputeAxis{1};
+ }
+
+ // ELSE
+ return reversed;
+}
+
+template <typename T> inline T ReorderBits(T in, size_t numOfBits)
+{
+ assert(numOfBits > 0);
+ T out = 0;
+ for (int32_t i = numOfBits - 1; i >= 0; --i)
+ {
+ const uint32_t toShift = numOfBits - ToARMComputeAxis(numOfBits, i).value() - 1;
+ out += ((in & 1) << toShift);
+ in >>= 1;
+ }
+ return out;
+}
+
+} // namespace internal
+
+#endif // __INTERNAL_SWIZZLE_H__