prior_box_op.h 7.7 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
W
wanghaox 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15

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. */

#pragma once
16 17
#include <algorithm>
#include <vector>
Y
Yi Wang 已提交
18 19 20
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/operators/math/math_function.h"
#include "paddle/fluid/platform/transform.h"
W
wanghaox 已提交
21 22 23 24

namespace paddle {
namespace operators {

W
wanghaox 已提交
25 26
inline void ExpandAspectRatios(const std::vector<float>& input_aspect_ratior,
                               bool flip,
27
                               std::vector<float>* output_aspect_ratior) {
28
  constexpr float epsilon = 1e-6;
29 30
  output_aspect_ratior->clear();
  output_aspect_ratior->push_back(1.0f);
W
wanghaox 已提交
31 32 33
  for (size_t i = 0; i < input_aspect_ratior.size(); ++i) {
    float ar = input_aspect_ratior[i];
    bool already_exist = false;
34 35
    for (size_t j = 0; j < output_aspect_ratior->size(); ++j) {
      if (fabs(ar - output_aspect_ratior->at(j)) < epsilon) {
W
wanghaox 已提交
36 37 38 39 40
        already_exist = true;
        break;
      }
    }
    if (!already_exist) {
41
      output_aspect_ratior->push_back(ar);
W
wanghaox 已提交
42
      if (flip) {
43
        output_aspect_ratior->push_back(1.0f / ar);
W
wanghaox 已提交
44 45 46 47 48
      }
    }
  }
}

W
wanghaox 已提交
49 50
template <typename T>
struct ClipFunctor {
51
  HOSTDEVICE inline T operator()(T in) const {
W
wanghaox 已提交
52 53 54 55
    return std::min<T>(std::max<T>(in, 0.), 1.);
  }
};

56
template <typename T>
W
wanghaox 已提交
57 58 59 60 61
class PriorBoxOpKernel : public framework::OpKernel<T> {
 public:
  void Compute(const framework::ExecutionContext& ctx) const override {
    auto* input = ctx.Input<paddle::framework::Tensor>("Input");
    auto* image = ctx.Input<paddle::framework::Tensor>("Image");
W
wanghaox 已提交
62 63
    auto* boxes = ctx.Output<paddle::framework::Tensor>("Boxes");
    auto* vars = ctx.Output<paddle::framework::Tensor>("Variances");
W
wanghaox 已提交
64

C
chengduoZH 已提交
65 66
    auto min_sizes = ctx.Attr<std::vector<float>>("min_sizes");
    auto max_sizes = ctx.Attr<std::vector<float>>("max_sizes");
W
wanghaox 已提交
67 68 69 70
    auto input_aspect_ratio = ctx.Attr<std::vector<float>>("aspect_ratios");
    auto variances = ctx.Attr<std::vector<float>>("variances");
    auto flip = ctx.Attr<bool>("flip");
    auto clip = ctx.Attr<bool>("clip");
71 72
    auto min_max_aspect_ratios_order =
        ctx.Attr<bool>("min_max_aspect_ratios_order");
W
wanghaox 已提交
73 74

    std::vector<float> aspect_ratios;
75
    ExpandAspectRatios(input_aspect_ratio, flip, &aspect_ratios);
W
wanghaox 已提交
76

W
wanghaox 已提交
77 78 79
    T step_w = static_cast<T>(ctx.Attr<float>("step_w"));
    T step_h = static_cast<T>(ctx.Attr<float>("step_h"));
    T offset = static_cast<T>(ctx.Attr<float>("offset"));
W
wanghaox 已提交
80

W
wanghaox 已提交
81 82
    auto img_width = image->dims()[3];
    auto img_height = image->dims()[2];
W
wanghaox 已提交
83

W
wanghaox 已提交
84 85
    auto feature_width = input->dims()[3];
    auto feature_height = input->dims()[2];
W
wanghaox 已提交
86

W
wanghaox 已提交
87
    T step_width, step_height;
W
wanghaox 已提交
88
    if (step_w == 0 || step_h == 0) {
W
wanghaox 已提交
89 90
      step_width = static_cast<T>(img_width) / feature_width;
      step_height = static_cast<T>(img_height) / feature_height;
W
wanghaox 已提交
91 92 93 94 95 96 97 98 99 100
    } else {
      step_width = step_w;
      step_height = step_h;
    }

    int num_priors = aspect_ratios.size() * min_sizes.size();
    if (max_sizes.size() > 0) {
      num_priors += max_sizes.size();
    }

W
wanghaox 已提交
101 102
    boxes->mutable_data<T>(ctx.GetPlace());
    vars->mutable_data<T>(ctx.GetPlace());
W
wanghaox 已提交
103

W
wanghaox 已提交
104
    auto e_boxes = framework::EigenTensor<T, 4>::From(*boxes);
W
wanghaox 已提交
105 106
    for (int h = 0; h < feature_height; ++h) {
      for (int w = 0; w < feature_width; ++w) {
W
wanghaox 已提交
107 108 109
        T center_x = (w + offset) * step_width;
        T center_y = (h + offset) * step_height;
        T box_width, box_height;
110
        int idx = 0;
W
wanghaox 已提交
111
        for (size_t s = 0; s < min_sizes.size(); ++s) {
C
chengduoZH 已提交
112
          auto min_size = min_sizes[s];
113 114
          if (min_max_aspect_ratios_order) {
            box_width = box_height = min_size / 2.;
115 116 117 118
            e_boxes(h, w, idx, 0) = (center_x - box_width) / img_width;
            e_boxes(h, w, idx, 1) = (center_y - box_height) / img_height;
            e_boxes(h, w, idx, 2) = (center_x + box_width) / img_width;
            e_boxes(h, w, idx, 3) = (center_y + box_height) / img_height;
119
            idx++;
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
            if (max_sizes.size() > 0) {
              auto max_size = max_sizes[s];
              // square prior with size sqrt(minSize * maxSize)
              box_width = box_height = sqrt(min_size * max_size) / 2.;
              e_boxes(h, w, idx, 0) = (center_x - box_width) / img_width;
              e_boxes(h, w, idx, 1) = (center_y - box_height) / img_height;
              e_boxes(h, w, idx, 2) = (center_x + box_width) / img_width;
              e_boxes(h, w, idx, 3) = (center_y + box_height) / img_height;
              idx++;
            }
            // priors with different aspect ratios
            for (size_t r = 0; r < aspect_ratios.size(); ++r) {
              float ar = aspect_ratios[r];
              if (fabs(ar - 1.) < 1e-6) {
                continue;
              }
              box_width = min_size * sqrt(ar) / 2.;
              box_height = min_size / sqrt(ar) / 2.;
              e_boxes(h, w, idx, 0) = (center_x - box_width) / img_width;
              e_boxes(h, w, idx, 1) = (center_y - box_height) / img_height;
              e_boxes(h, w, idx, 2) = (center_x + box_width) / img_width;
              e_boxes(h, w, idx, 3) = (center_y + box_height) / img_height;
              idx++;
            }
          } else {
            // priors with different aspect ratios
            for (size_t r = 0; r < aspect_ratios.size(); ++r) {
              float ar = aspect_ratios[r];
              box_width = min_size * sqrt(ar) / 2.;
              box_height = min_size / sqrt(ar) / 2.;
              e_boxes(h, w, idx, 0) = (center_x - box_width) / img_width;
              e_boxes(h, w, idx, 1) = (center_y - box_height) / img_height;
              e_boxes(h, w, idx, 2) = (center_x + box_width) / img_width;
              e_boxes(h, w, idx, 3) = (center_y + box_height) / img_height;
              idx++;
            }
            if (max_sizes.size() > 0) {
              auto max_size = max_sizes[s];
              // square prior with size sqrt(minSize * maxSize)
              box_width = box_height = sqrt(min_size * max_size) / 2.;
              e_boxes(h, w, idx, 0) = (center_x - box_width) / img_width;
              e_boxes(h, w, idx, 1) = (center_y - box_height) / img_height;
              e_boxes(h, w, idx, 2) = (center_x + box_width) / img_width;
              e_boxes(h, w, idx, 3) = (center_y + box_height) / img_height;
              idx++;
            }
W
wanghaox 已提交
166 167 168 169 170 171
          }
        }
      }
    }

    if (clip) {
W
wanghaox 已提交
172 173 174 175 176
      platform::Transform<platform::CPUDeviceContext> trans;
      ClipFunctor<T> clip_func;
      trans(ctx.template device_context<platform::CPUDeviceContext>(),
            boxes->data<T>(), boxes->data<T>() + boxes->numel(),
            boxes->data<T>(), clip_func);
W
wanghaox 已提交
177
    }
W
wanghaox 已提交
178

W
wanghaox 已提交
179 180 181 182 183
    framework::Tensor var_t;
    var_t.mutable_data<T>(
        framework::make_ddim({1, static_cast<int>(variances.size())}),
        ctx.GetPlace());
    auto var_et = framework::EigenTensor<T, 2>::From(var_t);
W
wanghaox 已提交
184
    for (size_t i = 0; i < variances.size(); ++i) {
W
wanghaox 已提交
185
      var_et(0, i) = variances[i];
W
wanghaox 已提交
186
    }
W
wanghaox 已提交
187

W
wanghaox 已提交
188
    int box_num = feature_height * feature_width * num_priors;
W
wanghaox 已提交
189 190 191 192 193 194 195
    auto var_dim = vars->dims();
    vars->Resize({box_num, static_cast<int>(variances.size())});

    auto e_vars = framework::EigenMatrix<T, Eigen::RowMajor>::From(*vars);
    e_vars = var_et.broadcast(Eigen::DSizes<int, 2>(box_num, 1));

    vars->Resize(var_dim);
W
wanghaox 已提交
196
  }
W
wanghaox 已提交
197
};  // namespace operators
W
wanghaox 已提交
198 199 200

}  // namespace operators
}  // namespace paddle