target_assign_op.cc 8.6 KB
Newer Older
D
dangqingqing 已提交
1
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

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 "paddle/operators/target_assign_op.h"

namespace paddle {
namespace operators {

class TargetAssignOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    // checkout inputs
    PADDLE_ENFORCE(ctx->HasInput("EncodedGTBBox"),
                   "Input(EncodedGTBBox) of TargetAssignOp should not be null");
    PADDLE_ENFORCE(ctx->HasInput("GTScoreLabel"),
                   "Input(GTScoreLabel) of TargetAssignOp should not be null");
    PADDLE_ENFORCE(ctx->HasInput("MatchIndices"),
                   "Input(MatchIndices) of TargetAssignOp should not be null");
    PADDLE_ENFORCE(ctx->HasInput("NegIndices"),
                   "Input(NegIndices) of TargetAssignOp should not be null");

    // checkout outputs
    PADDLE_ENFORCE(
        ctx->HasOutput("PredBBoxLabel"),
        "Output(PredBBoxLabel) of TargetAssignOp should not be null.");
    PADDLE_ENFORCE(
        ctx->HasOutput("PredBBoxWeight"),
        "Output(PredBBoxWeight) of TargetAssignOp should not be null.");
    PADDLE_ENFORCE(
        ctx->HasOutput("PredScoreLabel"),
        "Output(PredScoreLabel) of TargetAssignOp should not be null.");
    PADDLE_ENFORCE(
        ctx->HasOutput("PredScoreWeight"),
        "Output(PredScoreWeight) of TargetAssignOp should not be null.");

    auto blabel_dims = ctx->GetInputDim("EncodedGTBBox");
    auto slabel_dims = ctx->GetInputDim("GTScoreLabel");
    auto mi_dims = ctx->GetInputDim("MatchIndices");
    auto neg_dims = ctx->GetInputDim("NegIndices");

    PADDLE_ENFORCE_EQ(blabel_dims.size(), 3UL,
                      "The rank of Input(EncodedGTBBox) must be 3.");
    PADDLE_ENFORCE_EQ(slabel_dims.size(), 2UL,
                      "The rank of Input(GTScoreLabel) must be 2.");
    PADDLE_ENFORCE_EQ(mi_dims.size(), 2UL,
                      "The rank of Input(MatchIndices) must be 2.");
    PADDLE_ENFORCE_EQ(neg_dims.size(), 2UL,
                      "The rank of Input(NegIndices) must be 2.");

    PADDLE_ENFORCE_EQ(blabel_dims[0], slabel_dims[0],
D
dangqingqing 已提交
64 65 66
                      "The 1st dimension (means the total number of "
                      "ground-truth bounding boxes) of Input(EncodedGTBBox) "
                      "and Input(GTScoreLabel) must be the same.");
67
    PADDLE_ENFORCE_EQ(blabel_dims[1], mi_dims[1],
D
dangqingqing 已提交
68 69
                      "The 2nd dimension (means the number of priod boxes) "
                      "of Input(EncodedGTBBox) and "
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
                      "Input(MatchIndices) must be the same.");
    PADDLE_ENFORCE_EQ(blabel_dims[2], 4,
                      "The 3rd dimension of Input(EncodedGTBBox) must be 4.");

    auto n = mi_dims[0];
    auto np = mi_dims[1];
    ctx->SetOutputDim("PredBBoxLabel", {n, np, 4});
    ctx->SetOutputDim("PredBBoxWeight", {n, np, 1});
    ctx->SetOutputDim("PredScoreLabel", {n, np, 1});
    ctx->SetOutputDim("PredScoreWeight", {n, np, 1});
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(
        framework::ToDataType(
            ctx.Input<framework::LoDTensor>("EncodedGTBBox")->type()),
        ctx.device_context());
  }
};

class TargetAssignOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  TargetAssignOpMaker(OpProto* proto, OpAttrChecker* op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput("EncodedGTBBox",
             "(LoDTensor), The encoded ground-truth bounding boxes with shape "
             "[Ng, Np, 4], where Ng is the total number of ground-truth boxes "
             "in this mini-batch, Np the number of predictions, 4 is the "
             "number of coordinate in [xmin, ymin, xmax, ymax] layout.");
    AddInput("GTScoreLabel",
             "(LoDTensor, default LoDTensor<int>),  The input ground-truth "
             "labels with shape [Ng, 1], where the Ng is the same as it in "
             "the input of EncodedGTBBox.");
    AddInput("MatchIndices",
D
dangqingqing 已提交
106
             "(Tensor, default Tensor<int>), The input matched indices "
107 108 109 110 111 112
             "with shape [N, Np], where N is the batch size, Np is the same "
             "as it in the input of EncodedGTBBox. If MatchIndices[i][j] "
             "is -1, the j-th prior box is not matched to any ground-truh "
             "box in i-th instance.");
    AddInput("NegIndices",
             "(LoDTensor, default LoDTensor<int>), The input negative example "
D
dangqingqing 已提交
113
             "indices with shape [Neg, 1], where is the total number of "
114 115
             "negative example indices.");
    AddAttr<int>("background_label",
D
dangqingqing 已提交
116
                 "(int, default 0), Label index of background class.")
117 118 119 120 121 122
        .SetDefault(0);
    AddOutput("PredBBoxLabel",
              "(Tensor), The output encoded ground-truth labels "
              "with shape [N, Np, 4], N is the batch size and Np, 4 is the "
              "same as they in input of EncodedGTBBox. If MatchIndices[i][j] "
              "is -1, the PredBBoxLabel[i][j][:] is the encoded ground-truth "
D
dangqingqing 已提交
123
              "box for background_label in i-th instance.");
124 125 126 127 128 129
    AddOutput("PredBBoxWeight",
              "(Tensor), The weight for PredBBoxLabel with the shape "
              "of [N, Np, 1]");
    AddOutput("PredScoreLabel",
              "(Tensor, default Tensor<int>), The output score labels for "
              "each predictions with shape [N, Np, 1]. If MatchIndices[i][j] "
D
dangqingqing 已提交
130
              "is -1, PredScoreLabel[i][j] = background_label.");
131 132 133 134 135 136 137 138 139 140
    AddOutput("PredScoreWeight",
              "(Tensor), The weight for PredScoreLabel with the shape "
              "of [N, Np, 1]");
    AddComment(R"DOC(
This operator is, for given the encoded boxes between prior boxes and
ground-truth boxes and ground-truth class labels, to assign classification
and regression targets to each prior box as well as weights to each
prior box. The weights is used to specify which prior box would not contribute
to training loss.

D
dangqingqing 已提交
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 166 167 168 169
For each instance, the output `PredBBoxLabel`, `PredBBoxWeight`,
`PredScoreLabel` and `PredScoreWeight` are assigned based on `MatchIndices`.
Assumed that the row offset for each instance in `EncodedGTBBox` is called lod,
this operato assigns classification/regression targets by performing the
following steps:

1. Assigning all outpts based on `MatchIndices`:

If id = MatchIndices[i][j] > 0,

    PredBBoxLabel[i][j] = EncodedGTBBox[lod[i] + id][j]
    PredBBoxWeight[i][j] = 1.
    PredScoreLabel[i][j] = GTScoreLabel[lod[i] + id]
    PredScoreWeight[i][j] = 1.

Otherwise, 

    PredBBoxLabel[j][j] = [0., 0., 0., 0.]
    PredBBoxWeight[i][j] = 0.
    PredScoreLabel[i][j] = background_label
    PredScoreWeight[i][j] = 0.

2. Assigning PredScoreWeight based on `NegIndices`:

Assumed that the row offset for each instance in `NegIndices` is caleed neg_lod,
for i-th instance and all ids of NegIndices in this instance:

    PredScoreLabel[i][id] = background_label
    PredScoreWeight[i][id] = 1.0
170 171 172 173 174 175

    )DOC");
  }
};

template <typename T>
D
dangqingqing 已提交
176
struct NegTargetAssignFunctor<platform::CPUDeviceContext, T> {
177 178 179 180
  void operator()(const platform::CPUDeviceContext& ctx, const int* neg_indices,
                  const size_t* lod, const int num, const int num_prior_box,
                  const int background_label, int* out_label, T* out_label_wt) {
    for (int i = 0; i < num; ++i) {
D
dangqingqing 已提交
181
      for (size_t j = lod[i]; j < lod[i + 1]; ++j) {
182 183 184 185 186 187 188 189
        int id = neg_indices[j];
        out_label[i * num_prior_box + id] = background_label;
        out_label_wt[i * num_prior_box + id] = static_cast<T>(1.0);
      }
    }
  }
};

D
dangqingqing 已提交
190 191
template struct NegTargetAssignFunctor<platform::CPUDeviceContext, float>;
template struct NegTargetAssignFunctor<platform::CPUDeviceContext, double>;
192 193 194 195 196 197 198 199 200 201 202

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OP_WITHOUT_GRADIENT(target_assign, ops::TargetAssignOp,
                             ops::TargetAssignOpMaker);
REGISTER_OP_CPU_KERNEL(
    target_assign,
    ops::TargetAssignKernel<paddle::platform::CPUDeviceContext, float>,
    ops::TargetAssignKernel<paddle::platform::CPUDeviceContext, double>);