2021-11-19 09:53:33 +08:00
|
|
|
//
|
2021-11-04 11:09:08 +08:00
|
|
|
// CPUROIAlign.cpp
|
|
|
|
// MNN
|
|
|
|
//
|
|
|
|
// Created by MNN on 2021/11/02.
|
|
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "backend/cpu/CPUROIAlign.hpp"
|
2021-11-04 15:26:18 +08:00
|
|
|
#include <float.h>
|
2021-11-04 11:49:58 +08:00
|
|
|
#include <math.h>
|
2021-11-04 11:09:08 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include "CPUTensorConvert.hpp"
|
|
|
|
#include "backend/cpu/CPUBackend.hpp"
|
|
|
|
#include "core/TensorUtils.hpp"
|
|
|
|
#ifdef MNN_USE_NEON
|
|
|
|
#include <arm_neon.h>
|
|
|
|
#endif
|
2021-11-15 14:53:12 +08:00
|
|
|
#ifdef MNN_USE_SSE
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#include <intrin.h>
|
|
|
|
#else
|
|
|
|
#include <x86intrin.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
2021-11-04 11:09:08 +08:00
|
|
|
|
|
|
|
namespace MNN {
|
|
|
|
|
|
|
|
CPUROIAlign::CPUROIAlign(Backend* backend, int pooledWidth, int pooledHeight, int samplingRatio, float spatialScale,
|
2021-11-09 11:11:27 +08:00
|
|
|
bool aligned, PoolType poolType)
|
2021-11-04 11:09:08 +08:00
|
|
|
: Execution(backend),
|
|
|
|
mPooledWidth(pooledWidth),
|
|
|
|
mPooledHeight(pooledHeight),
|
|
|
|
mSamplingRatio(samplingRatio),
|
|
|
|
mSpatialScale(spatialScale),
|
|
|
|
mAligned(aligned),
|
2021-11-09 11:11:27 +08:00
|
|
|
mPoolType(poolType) {
|
2021-11-04 11:09:08 +08:00
|
|
|
// nothing to do
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode CPUROIAlign::onResize(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs) {
|
|
|
|
//
|
|
|
|
auto& roi = inputs[1]->buffer();
|
|
|
|
|
|
|
|
mROI.buffer().dimensions = roi.dimensions;
|
|
|
|
memcpy(mROI.buffer().dim, roi.dim, sizeof(halide_dimension_t) * roi.dimensions);
|
|
|
|
TensorUtils::getDescribe(&mROI)->dimensionFormat = MNN_DATA_FORMAT_NCHW;
|
|
|
|
TensorUtils::setLinearLayout(&mROI);
|
|
|
|
|
|
|
|
backend()->onAcquireBuffer(&mROI, Backend::DYNAMIC);
|
|
|
|
backend()->onReleaseBuffer(&mROI, Backend::DYNAMIC);
|
|
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode CPUROIAlign::onExecute(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs) {
|
|
|
|
auto& input = inputs[0];
|
|
|
|
auto& output = outputs[0];
|
2022-01-29 18:03:25 +08:00
|
|
|
auto core = static_cast<CPUBackend*>(backend())->functions();
|
2021-11-04 11:09:08 +08:00
|
|
|
|
2022-01-29 18:03:25 +08:00
|
|
|
CPUTensorConverter::convert(inputs[1], &mROI, core);
|
|
|
|
|
|
|
|
// dataType of ROI must be float32.
|
|
|
|
Tensor *roiTensor = &mROI;
|
|
|
|
if (core->bytes != 4) {
|
2022-08-12 10:30:48 +08:00
|
|
|
core->MNNLowpToFp32(mROI.host<int16_t>(), mROI.host<float>(), mROI.elementSize());
|
2021-11-04 11:09:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// get params
|
2022-01-29 18:03:25 +08:00
|
|
|
auto iw = input->width(), ih = input->height(), is = iw * ih * core->pack; // C4
|
|
|
|
auto ow = output->width(), oh = output->height(), os = ow * oh * core->pack; // C4
|
|
|
|
auto rs = roiTensor->stride(0);
|
|
|
|
auto numROI = roiTensor->batch();
|
|
|
|
auto numSlice = UP_DIV(input->channel(), core->pack);
|
2021-11-05 16:47:27 +08:00
|
|
|
float alignOffset = mAligned ? -0.5f : 0.f;
|
2021-11-04 11:09:08 +08:00
|
|
|
|
|
|
|
for (int n = 0; n < numROI; ++n) {
|
2022-01-29 18:03:25 +08:00
|
|
|
auto batchOutput = output->host<uint8_t>() + os * n * core->bytes;
|
|
|
|
auto roiPtr = roiTensor->host<float>() + rs * n;
|
2022-01-04 10:50:40 +08:00
|
|
|
int batchIdx = (int)roiPtr[0], idxRoi = 1;
|
|
|
|
if (inputs.size() == 3) {
|
|
|
|
batchIdx = inputs[2]->host<int>()[n];
|
|
|
|
idxRoi = 0;
|
|
|
|
}
|
|
|
|
float x1 = roiPtr[idxRoi++] * mSpatialScale + alignOffset;
|
|
|
|
float y1 = roiPtr[idxRoi++] * mSpatialScale + alignOffset;
|
|
|
|
float x2 = roiPtr[idxRoi++] * mSpatialScale + alignOffset;
|
|
|
|
float y2 = roiPtr[idxRoi++] * mSpatialScale + alignOffset;
|
2021-11-04 11:09:08 +08:00
|
|
|
MNN_ASSERT(batchIdx < input->batch());
|
|
|
|
|
2021-11-05 16:47:27 +08:00
|
|
|
float roiW = x2 - x1;
|
|
|
|
float roiH = y2 - y1;
|
|
|
|
if (!mAligned) {
|
|
|
|
roiW = std::max(roiW, 1.f);
|
|
|
|
roiH = std::max(roiH, 1.f);
|
|
|
|
}
|
2021-11-04 11:09:08 +08:00
|
|
|
|
|
|
|
float binSizeW = roiW / mPooledWidth;
|
|
|
|
float binSizeH = roiH / mPooledHeight;
|
|
|
|
|
2021-11-09 11:20:22 +08:00
|
|
|
int samplingRatioW = mSamplingRatio > 0 ? mSamplingRatio : static_cast<int>(ceilf(roiW / mPooledWidth));
|
|
|
|
int samplingRatioH = mSamplingRatio > 0 ? mSamplingRatio : static_cast<int>(ceilf(roiH / mPooledHeight));
|
|
|
|
MNN_ASSERT(samplingRatioH > 0 && samplingRatioW > 0);
|
|
|
|
|
2021-11-05 16:47:27 +08:00
|
|
|
std::vector<std::vector<int>> vecPos;
|
|
|
|
std::vector<std::vector<float>> vecArea;
|
|
|
|
preCalcBilinearInterpolate(ih, iw, mPooledHeight, mPooledWidth, y1, x1, binSizeH, binSizeW, samplingRatioH,
|
|
|
|
samplingRatioW, vecPos, vecArea);
|
2021-11-04 11:09:08 +08:00
|
|
|
|
2022-01-29 18:03:25 +08:00
|
|
|
auto batchInput = input->host<uint8_t>() + is * batchIdx * core->bytes;
|
2021-11-09 11:11:27 +08:00
|
|
|
if (mPoolType == PoolType_AVEPOOL) {
|
2021-11-04 11:09:08 +08:00
|
|
|
for (int s = 0; s < numSlice; ++s) {
|
2022-01-29 18:03:25 +08:00
|
|
|
auto sliceInput = batchInput + is * input->batch() * s * core->bytes;
|
|
|
|
auto rowOutput = batchOutput + os * output->batch() * s * core->bytes;
|
|
|
|
core->MNNRoiAlignAvg((float *)rowOutput, (float *)sliceInput, vecPos, vecArea, samplingRatioH * samplingRatioW, mPooledHeight, mPooledWidth);
|
2021-11-04 11:09:08 +08:00
|
|
|
}
|
2021-11-09 11:11:27 +08:00
|
|
|
} else if (mPoolType == PoolType_MAXPOOL) {
|
2021-11-04 11:09:08 +08:00
|
|
|
for (int s = 0; s < numSlice; ++s) {
|
2022-01-29 18:03:25 +08:00
|
|
|
auto sliceInput = batchInput + is * input->batch() * s * core->bytes;
|
|
|
|
auto rowOutput = batchOutput + os * output->batch() * s * core->bytes;
|
|
|
|
core->MNNRoiAlignMax((float *)rowOutput, (float *)sliceInput, vecPos, vecArea, samplingRatioH * samplingRatioW, mPooledHeight, mPooledWidth);
|
2021-11-04 11:09:08 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-11-09 11:11:27 +08:00
|
|
|
MNN_ERROR("pooling mode: %d not supported now!", mPoolType);
|
2021-11-04 11:09:08 +08:00
|
|
|
return NOT_SUPPORT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-11-05 16:47:27 +08:00
|
|
|
ErrorCode CPUROIAlign::preCalcBilinearInterpolate(int height, int width, int pooledHeight, int pooledWidth,
|
|
|
|
float roiStartH, float roiStartW, float binSizeH, float binSizeW,
|
|
|
|
int samplingRatioH, int samplingRatioW,
|
|
|
|
std::vector<std::vector<int>>& vecPos,
|
|
|
|
std::vector<std::vector<float>>& vecArea) {
|
|
|
|
float samplingBinH = binSizeH / samplingRatioH;
|
|
|
|
float samplingBinW = binSizeW / samplingRatioW;
|
|
|
|
|
|
|
|
for (int h = 0; h < pooledHeight; ++h) {
|
|
|
|
float samplingStartH = roiStartH + h * binSizeH;
|
|
|
|
for (int w = 0; w < pooledWidth; ++w) {
|
|
|
|
float samplingStartW = roiStartW + w * binSizeW;
|
|
|
|
for (int i = 0; i < samplingRatioH; ++i) {
|
|
|
|
float py = samplingStartH + (0.5 + i) * samplingBinH;
|
|
|
|
for (int j = 0; j < samplingRatioW; ++j) {
|
|
|
|
float px = samplingStartW + (0.5 + j) * samplingBinW;
|
|
|
|
if (py < -1.f || py > height || px < -1.f || px > width) {
|
|
|
|
std::vector<int> pos({0, 0, 0, 0});
|
|
|
|
std::vector<float> area({0.f, 0.f, 0.f, 0.f});
|
|
|
|
vecPos.emplace_back(std::move(pos));
|
|
|
|
vecArea.emplace_back(std::move(area));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
py = py < 0 ? 0 : py;
|
|
|
|
px = px < 0 ? 0 : px;
|
|
|
|
|
|
|
|
int py0 = static_cast<int>(py), px0 = static_cast<int>(px), py1, px1;
|
|
|
|
if (py0 >= height - 1) {
|
|
|
|
py1 = py0 = height - 1;
|
|
|
|
py = static_cast<float>(py0);
|
|
|
|
} else {
|
|
|
|
py1 = py0 + 1;
|
|
|
|
}
|
2022-01-04 10:50:40 +08:00
|
|
|
if (px0 >= width - 1) {
|
2021-11-05 16:47:27 +08:00
|
|
|
px1 = px0 = width - 1;
|
|
|
|
px = static_cast<float>(px0);
|
|
|
|
} else {
|
|
|
|
px1 = px0 + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
float dy0 = py - py0, dx0 = px - px0;
|
|
|
|
float dy1 = 1.f - dy0, dx1 = 1.f - dx0;
|
|
|
|
float area0 = dx0 * dy0, area1 = dx1 * dy0, area2 = dx0 * dy1, area3 = dx1 * dy1;
|
2022-01-29 18:03:25 +08:00
|
|
|
int pos0 = py0 * width + px0, pos1 = py0 * width + px1, pos2 = py1 * width + px0,
|
|
|
|
pos3 = py1 * width + px1;
|
2021-11-05 16:47:27 +08:00
|
|
|
std::vector<int> pos({pos0, pos1, pos2, pos3});
|
|
|
|
std::vector<float> area({area3, area2, area1, area0});
|
|
|
|
vecPos.emplace_back(std::move(pos));
|
|
|
|
vecArea.emplace_back(std::move(area));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-11-04 11:09:08 +08:00
|
|
|
class CPUROIAlignCreator : public CPUBackend::Creator {
|
|
|
|
public:
|
|
|
|
virtual Execution* onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs,
|
|
|
|
const MNN::Op* op, Backend* backend) const override {
|
2021-11-09 11:11:27 +08:00
|
|
|
auto roiAlign = op->main_as_RoiParameters();
|
2022-01-29 18:03:25 +08:00
|
|
|
auto core = static_cast<CPUBackend*>(backend)->functions();
|
|
|
|
if (core->MNNRoiAlignMax == nullptr || core->MNNRoiAlignAvg == nullptr) {
|
|
|
|
MNN_ERROR("Don't have function for CPUROIAlign\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-11-04 11:09:08 +08:00
|
|
|
return new CPUROIAlign(backend, roiAlign->pooledWidth(), roiAlign->pooledHeight(), roiAlign->samplingRatio(),
|
2021-11-09 11:11:27 +08:00
|
|
|
roiAlign->spatialScale(), roiAlign->aligned(), roiAlign->poolType());
|
2021-11-04 11:09:08 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
REGISTER_CPU_OP_CREATOR(CPUROIAlignCreator, OpType_ROIAlign);
|
2021-11-19 09:53:33 +08:00
|
|
|
} // namespace MNN
|