Add implementation of Gather operation to interpreter backend.
Signed-off-by: Sergei Barannikov <s.barannikov@samsung.com>
}
}
-char *TensorVariant::at(const Index &idx) const
-{
+char* TensorVariant::at(const Index& idx) const {
return _data.get() + getOffset(idx) * _elementSize;
}
+char* TensorVariant::atOffset(int32_t offset) const {
+ assert(offset >= 0 && offset < getShape().numElements());
+ return _data.get() + offset * _elementSize;
+}
+
size_t TensorVariant::getOffset(const Index &idx) const {
assert(idx.rank() == getShape().rank());
std::size_t offset = 0;
explicit Tensor(const TensorVariant &t) : _proxy(t), _shape(t.getShape()) {
}
- T at(const Index &id) const {
- return *reinterpret_cast<T *>(this->_proxy.at(id));
+ T at(const Index& id) const {
+ return *reinterpret_cast<T*>(this->_proxy.at(id));
}
- T &at(const Index &id) {
- return *reinterpret_cast<T *>(this->_proxy.at(id));
+ T& at(const Index& id) {
+ return *reinterpret_cast<T*>(this->_proxy.at(id));
+ }
+
+ T atOffset(int32_t offset) const {
+ return *reinterpret_cast<T*>(this->_proxy.atOffset(offset));
+ }
+
+ T& atOffset(int32_t offset) {
+ return *reinterpret_cast<T*>(this->_proxy.atOffset(offset));
}
ExternalRegion<T> getRegion(const Index& idx) {
}
virtual ~TensorVariant() = default;
- char *at(const Index &idx) const;
+ char* at(const Index& idx) const;
+ char* atOffset(int32_t offset) const;
size_t getOffset(const Index &idx) const;
virtual const Shape &getShape() const { return _shape; }
const std::vector<mir::IODescriptor>& inputs) {
const auto& params = layer.embed_param();
auto data = createOp<ops::ConstantOp>(layer.name() + ".weights", *convertBlob(layer.blobs(0)));
- // FIXME Indices in Caffe have floating type, while in ModelIR they are integral.
auto result = createOp<ops::GatherOp>(layer.name(), data->getOutput(0), inputs[0], 0);
// Add the bias, if any.
#include "passes/interpreter/Interpreter.h"
-#include "core/modelIR/operations/FullyConnectedOp.h"
-#include "core/modelIR/operations/GemmOp.h"
-#include "core/modelIR/operations/SoftmaxOp.h"
+#include "core/modelIR/operations/BatchNormOp.h"
+#include "core/modelIR/operations/BiasAddOp.h"
#include "core/modelIR/operations/CappedReluOp.h"
-#include "core/modelIR/operations/DepthwiseConv2DOp.h"
+#include "core/modelIR/operations/ConcatOp.h"
#include "core/modelIR/operations/ConstantOp.h"
#include "core/modelIR/operations/Conv2DOp.h"
#include "core/modelIR/operations/Deconv2DOp.h"
+#include "core/modelIR/operations/DepthwiseConv2DOp.h"
+#include "core/modelIR/operations/DropoutOp.h"
+#include "core/modelIR/operations/ElementwiseOp.h"
+#include "core/modelIR/operations/EluOp.h"
+#include "core/modelIR/operations/FullyConnectedOp.h"
+#include "core/modelIR/operations/GatherOp.h"
+#include "core/modelIR/operations/GemmOp.h"
+#include "core/modelIR/operations/PadOp.h"
#include "core/modelIR/operations/PoolOp.h"
-#include "core/modelIR/operations/VariableOp.h"
-#include "core/modelIR/operations/ReluOp.h"
#include "core/modelIR/operations/ReduceFOp.h"
+#include "core/modelIR/operations/ReluOp.h"
#include "core/modelIR/operations/ResizeOp.h"
-#include "core/modelIR/operations/EluOp.h"
-#include "core/modelIR/operations/ConcatOp.h"
-#include "core/modelIR/operations/BiasAddOp.h"
-#include "core/modelIR/operations/BatchNormOp.h"
#include "core/modelIR/operations/ScaleOp.h"
-#include "core/modelIR/operations/DropoutOp.h"
-#include "core/modelIR/operations/TanhOp.h"
-#include "core/modelIR/operations/ElementwiseOp.h"
+#include "core/modelIR/operations/SoftmaxOp.h"
#include "core/modelIR/operations/SqueezeOp.h"
-#include "core/modelIR/operations/PadOp.h"
+#include "core/modelIR/operations/TanhOp.h"
#include "core/modelIR/operations/TransposeOp.h"
+#include "core/modelIR/operations/VariableOp.h"
+#include "ops/BatchNorm.h"
#include "ops/Bias.h"
#include "ops/Concat.h"
#include "ops/conv_2D.h"
#include "ops/DeConv2D.h"
#include "ops/Depthwise_conv_2D.h"
+#include "ops/Dropout.h"
#include "ops/FullyConnected.h"
+#include "ops/Gather.h"
#include "ops/Gemm.h"
+#include "ops/Pad.h"
#include "ops/Pool.h"
#include "ops/Reshape.h"
-#include "ops/Softmax.h"
#include "ops/Scale.h"
+#include "ops/Softmax.h"
#include "ops/Transpose.h"
-#include "ops/Dropout.h"
-#include "ops/BatchNorm.h"
-#include "ops/Pad.h"
namespace nnc {
}
void NNInterpreter::visit(ops::GatherOp& op) {
- assert(false && "Not yet imlemented");
+ mapByName(&op);
+ auto data_descr = op.getPrevNodes()[0];
+ auto indices_descr = op.getPrevNodes()[1];
+ const auto& data = var(data_descr.op->getId())[data_descr.index];
+ const auto& indices = var(indices_descr.op->getId())[indices_descr.index];
+ var(op.getId()) = Gather(data, indices, op)();
}
} // namespace nnc
std::vector<mir::TensorVariant> operator()() override
{
return Fill<float>(_outputShape, [this](const mir::Index &idx) {
- return _input.at(idx) + _weights.at({idx.at(idx.rank() - 1)});
+ return _input.at(idx) + _weights.atOffset({idx.at(idx.rank() - 1)});
})();
}
--- /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.
+ */
+
+#include "Gather.h"
+
+namespace nnc {
+
+using namespace mir;
+
+Gather::Gather(const TensorVariant& data,
+ const TensorVariant& indices,
+ const ops::GatherOp& op)
+ : _data(data), _indices(indices), _op(op) {}
+
+std::vector<TensorVariant> Gather::operator()() {
+ const auto& data_shape = _data.getShape();
+ const auto& indices_shape = _indices.getShape();
+ const auto& output_shape = _op.getOutputShape(0);
+ auto res = allocate_tensor(_op.getOutputShape(0));
+ Tensor<float> data(_data);
+ Tensor<float> indices(_indices);
+ Tensor<float> output(res);
+
+ int32_t axis = _op.getAxis();
+ if (axis < 0)
+ axis += data_shape.rank();
+ assert(axis >= 0 && axis < data_shape.rank());
+ int32_t axis_size = data_shape.dim(axis);
+ int32_t num_indices = indices_shape.numElements();
+
+ int32_t outer_size = 1;
+ for (int32_t i = 0; i < axis; ++i)
+ outer_size *= data_shape.dim(i);
+
+ int32_t inner_size = 1;
+ for (int32_t i = axis + 1; i < data_shape.rank(); ++i)
+ inner_size *= data_shape.dim(i);
+
+ for (int32_t outer = 0; outer < outer_size; ++outer) {
+ for (int32_t i = 0; i < num_indices; ++i) {
+ auto index = static_cast<int32_t>(indices.atOffset(i));
+ assert(index >= 0 && index < axis_size);
+ for (int32_t inner = 0; inner < inner_size; inner++) {
+ output.atOffset((outer * num_indices + i) * inner_size + inner) =
+ data.atOffset((outer * axis_size + index) * inner_size + inner);
+ }
+ }
+ }
+
+ return {res};
+}
+
+} // namespace nnc
--- /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 _NNC_CORE_BACKEND_INTERPRETER_GATHER_
+#define _NNC_CORE_BACKEND_INTERPRETER_GATHER_
+
+#include "OperationImpl.h"
+#include "core/modelIR/operations/GatherOp.h"
+
+namespace nnc {
+
+class Gather : public OperationImpl<float> {
+public:
+ Gather(const mir::TensorVariant& data,
+ const mir::TensorVariant& indices,
+ const mir::ops::GatherOp& op);
+
+ std::vector<mir::TensorVariant> operator()() override;
+
+private:
+ const mir::Tensor<float> _data;
+ const mir::Tensor<float> _indices;
+ const mir::ops::GatherOp& _op;
+};
+
+}
+
+#endif //_NNC_CORE_BACKEND_INTERPRETER_GATHER_
//For now handles only most common case with scale applied by last dimension
mir::Tensor<float> weightsAccessor(_op.getWeights());
return Fill<float>(_input.getShape(), [this, weightsAccessor](const mir::Index &idx) {
- return _input.at(idx) * weightsAccessor.at({idx.at(idx.rank() - 1)});
+ return _input.at(idx) * weightsAccessor.atOffset({idx.at(idx.rank() - 1)});
})();
}
for (int outer = 0; outer < outer_size; ++outer) {
for (int i = 0; i < coords_count; ++i) {
- TFLITE_DCHECK_GE(coords_data[i], 0);
- TFLITE_DCHECK_LT(coords_data[i], axis_size);
+ int coord = static_cast<int>(coords_data[i]);
+ TFLITE_DCHECK_GE(coord, 0);
+ TFLITE_DCHECK_LT(coord, axis_size);
std::memcpy(
output_data + (outer * coords_count + i) * inner_size,
- input_data + (outer * axis_size + coords_data[i]) * inner_size,
+ input_data + (outer * axis_size + coord) * inner_size,
sizeof(T) * inner_size);
}
}
// pointer to float.
Gather(gather_params,
shapeToRuntimeShape(data.getShape()), data.getData(),
- shapeToRuntimeShape(indices.getShape()), reinterpret_cast<const int32*>(indices.getData()),
+ shapeToRuntimeShape(indices.getShape()), indices.getData(),
shapeToRuntimeShape(out.getShape()), out.getData());
}