1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
6 #include "ext_list.hpp"
7 #include "ext_base.hpp"
9 #include "matrixmult.h"
17 namespace InferenceEngine {
18 namespace Extensions {
21 class SpatialTransformerImpl: public ExtLayerBase {
23 explicit SpatialTransformerImpl(const CNNLayer* layer) {
25 if (layer->insData.size() != 2 || layer->outData.empty())
26 THROW_IE_EXCEPTION << "Incorrect number of input/output edges!";
28 addConfig(layer, {DataConfigurator(ConfLayout::PLN), DataConfigurator(ConfLayout::PLN)}, {DataConfigurator(ConfLayout::PLN)});
29 } catch (InferenceEngine::details::InferenceEngineException &ex) {
34 StatusCode execute(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs,
35 ResponseDesc *resp) noexcept override {
36 std::vector<size_t> real_dims = inputs[0]->getTensorDesc().getDims();
37 size_t data_size = inputs[0]->size();
39 const auto *src_data = inputs[0]->cbuffer().as<const float *>();
40 auto *theta = inputs[1]->buffer().as<float *>();
41 auto *dst_data = outputs[0]->buffer().as<float *>();
43 auto N = real_dims[0];
44 auto C = real_dims[1];
45 auto output_H_ = real_dims[2];
46 auto output_W_ = real_dims[3];
48 // Prepare input and output grid
49 std::vector<float> input_grid_data(N * output_H_ * output_W_ * 2);
50 std::vector<float> output_grid_data(3 * output_H_ * output_W_);
51 for (int i = 0; i < output_H_ * output_W_; ++i) {
52 output_grid_data[3 * i] = (i / output_W_) * 1.0 / output_H_ * 2 - 1;
53 output_grid_data[3 * i + 1] = (i % output_W_) * 1.0 / output_W_ * 2 - 1;
54 output_grid_data[3 * i + 2] = 1;
58 for (int i = 0; i < N; ++i) {
59 auto coordinates = input_grid_data.begin() + (output_H_ * output_W_ * 2) * i;
61 auto M_size = output_H_ * output_W_;
65 matrixMult(&output_grid_data[0], theta + 6 * i, &(*coordinates), M_size, N_size, K_size, true);
70 for (int j = 0; j < C; ++j) {
71 for (int s = 0; s < output_H_; ++s) {
72 for (int t = 0; t < output_W_; ++t) {
73 row_idx = output_W_ * s + t;
75 px = coordinates[row_idx * 2];
76 py = coordinates[row_idx * 2 + 1];
78 size_t dst_offset = ((i * C + j) * output_H_ + s) * output_W_ + t;
79 size_t src_offset = ((i * C + j) * output_H_ + 0) * output_W_ + 0;
80 dst_data[dst_offset] = transform_forward_cpu(src_data + src_offset, px, py);
89 float transform_forward_cpu(const float *pic, float px, float py) {
94 float x = (px + 1) / 2 * H;
95 float y = (py + 1) / 2 * W;
103 if (m >= 0 && m < H && n >= 0 && n < W) {
104 w = std::max<float>(0.0f, 1 - std::abs(x - m)) * std::max<float>(0.0f, 1 - std::abs(y - n));
105 res += w * pic[m * W + n];
108 m = std::floor(x) + 1;
111 if (m >= 0 && m < H && n >= 0 && n < W) {
112 w = std::max<float>(0.0f, 1 - std::abs(x - m)) * std::max<float>(0.0f, 1 - std::abs(y - n));
113 res += w * pic[m * W + n];
117 n = std::floor(y) + 1;
119 if (m >= 0 && m < H && n >= 0 && n < W) {
120 w = std::max<float>(0.0f, 1 - std::abs(x - m)) * std::max<float>(0.0f, 1 - std::abs(y - n));
121 res += w * pic[m * W + n];
124 m = std::floor(x) + 1;
125 n = std::floor(y) + 1;
127 if (m >= 0 && m < H && n >= 0 && n < W) {
128 w = std::max<float>(0.0f, 1 - std::abs(x - m)) * std::max<float>(0.0f, 1 - std::abs(y - n));
129 res += w * pic[m * W + n];
136 class SpatialTransformerShapeInfer : public IShapeInferImpl {
138 StatusCode inferShapes(const std::vector<SizeVector>& inShapes,
139 const std::map<std::string, std::string>& params,
140 const std::map<std::string, Blob::Ptr>& blobs,
141 std::vector<SizeVector>& outShapes,
142 ResponseDesc* resp) noexcept override {
143 outShapes.push_back(inShapes[0]);
144 return InferenceEngine::OK;
148 REG_FACTORY_FOR(ImplFactory<SpatialTransformerImpl>, SpatialTransformer);
149 REG_SHAPE_INFER_FOR_TYPE(SpatialTransformerShapeInfer, SpatialTransformer);
152 } // namespace Extensions
153 } // namespace InferenceEngine