| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | //  CPUPriorbox.cpp
 | 
					
						
							|  |  |  | //  MNN
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //  Created by MNN on 2018/07/18.
 | 
					
						
							|  |  |  | //  Copyright © 2018, Alibaba Group Holding Limited
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | #include "backend/cpu/CPUPriorbox.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | #include <math.h>
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | #include "core/AutoStorage.h"
 | 
					
						
							|  |  |  | #include "backend/cpu/CPUBackend.hpp"
 | 
					
						
							|  |  |  | #include "backend/cpu/compute/CommonOptFunction.h"
 | 
					
						
							|  |  |  | #include "core/TensorUtils.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace MNN { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CPUPriorBox::CPUPriorBox(Backend *b, const MNN::Op *op) : MNN::Execution(b) { | 
					
						
							|  |  |  |     mParameter = op->main_as_PriorBox(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorCode CPUPriorBox::onExecute(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) { | 
					
						
							|  |  |  |     return NO_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ErrorCode CPUPriorBox::onResize(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) { | 
					
						
							|  |  |  |     AutoStorage<float> mOutputData; | 
					
						
							|  |  |  |     mOutputData.reset(outputs[0]->height() * outputs[0]->channel()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto layer  = mParameter; | 
					
						
							|  |  |  |     auto input0 = inputs[0]; | 
					
						
							|  |  |  |     const int w = input0->width(); | 
					
						
							|  |  |  |     const int h = input0->height(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // image width, height
 | 
					
						
							|  |  |  |     int imageW = layer->imageWidth(); | 
					
						
							|  |  |  |     if (imageW <= 0) { | 
					
						
							|  |  |  |         imageW = inputs[1]->width(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int imageH = layer->imageHeight(); | 
					
						
							|  |  |  |     if (imageH <= 0) { | 
					
						
							|  |  |  |         imageH = inputs[1]->height(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // step width, height
 | 
					
						
							|  |  |  |     float stepW = layer->stepWidth(); | 
					
						
							|  |  |  |     if (stepW <= 0) { | 
					
						
							|  |  |  |         stepW = (float)imageW / w; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     float stepH = layer->stepHeight(); | 
					
						
							|  |  |  |     if (stepH <= 0) { | 
					
						
							|  |  |  |         stepH = (float)imageH / h; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // sizes
 | 
					
						
							| 
									
										
											  
											
												- build:
	- unify schema building in core and converter;
	- add more build script for android;
	- add linux build script for python;
- ops impl:
	- add floor mod support in binary;
	- use eltwise impl in add/max/sub/mul binary for optimization;
	- remove fake double support in cast;
	- fix 5d support for concat;
	- add adjX and adjY support for batch matmul;
	- optimize conv2d back prop filter;
	- add pad mode support for conv3d;
	- fix bug in conv2d & conv depthwise with very small feature map;
	- optimize binary without broacast;
	- add data types support for gather;
	- add gather ND support;
	- use uint8 data type in gather v2;
	- add transpose support for matmul;
	- add matrix band part;
	- add dim != 4 support for padding, reshape & tensor convert;
	- add pad type support for pool3d;
	- make ops based on TensorFlow Lite quantization optional;
	- add all & any support for reduction;
	- use type in parameter as output type in reduction;
	- add int support for unary;
	- add variable weight support for conv2d;
	- fix conv2d depthwise weights initialization;
	- fix type support for transpose;
	- fix grad outputs count for  reduce grad and reshape grad;
	- fix priorbox & detection output;
	- fix metal softmax error;
- python:
	- add runSessionWithCallBackInfo interface;
	- add max nodes limit (1400) for visualization tool;
	- fix save error in python3;
	- align default dim;
- convert:
	- add extra design for optimization;
	- add more post converting optimizers;
	- add caffe v1 weights blob support;
	- add cast, unary, conv transpose support for onnx model;
	- optimize batchnorm, conv with variable weights, prelu, reshape, slice, upsample for onnx model;
	- add cos/sin/atan/tan support for unary for tensorflow model;
	- add any/all support for reduction for tensorflow model;
	- add elu, conv3d, pool3d support for tensorflow model;
	- optimize argmax, batchnorm, concat, batch to space, conv with variable weights, prelu, slice for tensorflow model;
- others:
	- fix size computer lock;
	- fix thread pool deadlock;
	- add express & parameters in express;
	- rewrite blitter chooser without static map;
	- add tests for expr;
											
										 
											2019-10-29 13:37:26 +08:00
										 |  |  |     auto minSizes     = layer->minSizes(); | 
					
						
							|  |  |  |     auto minSizeCount = minSizes ? minSizes->size() : 0; | 
					
						
							|  |  |  |     auto maxSizes     = layer->maxSizes(); | 
					
						
							|  |  |  |     auto maxSizeCount = maxSizes ? maxSizes->size() : 0; | 
					
						
							|  |  |  |     auto aspectRatios = layer->aspectRatios(); | 
					
						
							|  |  |  |     bool flip         = layer->flip(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::vector<float> aspectRatiosValue{1.0f}; | 
					
						
							|  |  |  |     if (aspectRatios != nullptr) { | 
					
						
							|  |  |  |         for (int i = 0; i < aspectRatios->size(); ++i) { | 
					
						
							|  |  |  |             auto ratio = aspectRatios->data()[i]; | 
					
						
							|  |  |  |             bool exist = false; | 
					
						
							|  |  |  |             for (auto v : aspectRatiosValue) { | 
					
						
							|  |  |  |                 auto diff = v - ratio; | 
					
						
							|  |  |  |                 if (diff < 0) { | 
					
						
							|  |  |  |                     diff = -diff; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (diff < 1e-6) { | 
					
						
							|  |  |  |                     exist = true; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!exist) { | 
					
						
							|  |  |  |                 aspectRatiosValue.emplace_back(ratio); | 
					
						
							|  |  |  |                 if (flip) { | 
					
						
							|  |  |  |                     aspectRatiosValue.emplace_back(1.0f / ratio); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
											  
											
												- build:
	- unify schema building in core and converter;
	- add more build script for android;
	- add linux build script for python;
- ops impl:
	- add floor mod support in binary;
	- use eltwise impl in add/max/sub/mul binary for optimization;
	- remove fake double support in cast;
	- fix 5d support for concat;
	- add adjX and adjY support for batch matmul;
	- optimize conv2d back prop filter;
	- add pad mode support for conv3d;
	- fix bug in conv2d & conv depthwise with very small feature map;
	- optimize binary without broacast;
	- add data types support for gather;
	- add gather ND support;
	- use uint8 data type in gather v2;
	- add transpose support for matmul;
	- add matrix band part;
	- add dim != 4 support for padding, reshape & tensor convert;
	- add pad type support for pool3d;
	- make ops based on TensorFlow Lite quantization optional;
	- add all & any support for reduction;
	- use type in parameter as output type in reduction;
	- add int support for unary;
	- add variable weight support for conv2d;
	- fix conv2d depthwise weights initialization;
	- fix type support for transpose;
	- fix grad outputs count for  reduce grad and reshape grad;
	- fix priorbox & detection output;
	- fix metal softmax error;
- python:
	- add runSessionWithCallBackInfo interface;
	- add max nodes limit (1400) for visualization tool;
	- fix save error in python3;
	- align default dim;
- convert:
	- add extra design for optimization;
	- add more post converting optimizers;
	- add caffe v1 weights blob support;
	- add cast, unary, conv transpose support for onnx model;
	- optimize batchnorm, conv with variable weights, prelu, reshape, slice, upsample for onnx model;
	- add cos/sin/atan/tan support for unary for tensorflow model;
	- add any/all support for reduction for tensorflow model;
	- add elu, conv3d, pool3d support for tensorflow model;
	- optimize argmax, batchnorm, concat, batch to space, conv with variable weights, prelu, slice for tensorflow model;
- others:
	- fix size computer lock;
	- fix thread pool deadlock;
	- add express & parameters in express;
	- rewrite blitter chooser without static map;
	- add tests for expr;
											
										 
											2019-10-29 13:37:26 +08:00
										 |  |  |     int priorCount = minSizeCount * aspectRatiosValue.size() + maxSizeCount; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // boxes
 | 
					
						
							|  |  |  |     float offset  = layer->offset(); | 
					
						
							|  |  |  |     auto boxesPtr = mOutputData.get(); | 
					
						
							|  |  |  |     for (int i = 0; i < h; i++) { | 
					
						
							|  |  |  |         float *box    = boxesPtr + i * w * priorCount * 4; | 
					
						
							|  |  |  |         float centerX = offset * stepW; | 
					
						
							|  |  |  |         float centerY = offset * stepH + i * stepH; | 
					
						
							|  |  |  |         for (int j = 0; j < w; j++, centerX += stepW) { | 
					
						
							|  |  |  |             for (int k = 0; k < minSizeCount; k++) { | 
					
						
							|  |  |  |                 // min size box
 | 
					
						
							|  |  |  |                 float minSize = minSizes->data()[k]; | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     box[0] = (centerX - minSize * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[1] = (centerY - minSize * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box[2] = (centerX + minSize * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[3] = (centerY + minSize * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box += 4; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // max size box
 | 
					
						
							|  |  |  |                 if (maxSizeCount > 0) { | 
					
						
							|  |  |  |                     float maxSize = maxSizes->data()[k]; | 
					
						
							|  |  |  |                     float ssqrt   = sqrt(minSize * maxSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     box[0] = (centerX - ssqrt * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[1] = (centerY - ssqrt * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box[2] = (centerX + ssqrt * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[3] = (centerY + ssqrt * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box += 4; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // aspect ratios
 | 
					
						
							| 
									
										
											  
											
												- build:
	- unify schema building in core and converter;
	- add more build script for android;
	- add linux build script for python;
- ops impl:
	- add floor mod support in binary;
	- use eltwise impl in add/max/sub/mul binary for optimization;
	- remove fake double support in cast;
	- fix 5d support for concat;
	- add adjX and adjY support for batch matmul;
	- optimize conv2d back prop filter;
	- add pad mode support for conv3d;
	- fix bug in conv2d & conv depthwise with very small feature map;
	- optimize binary without broacast;
	- add data types support for gather;
	- add gather ND support;
	- use uint8 data type in gather v2;
	- add transpose support for matmul;
	- add matrix band part;
	- add dim != 4 support for padding, reshape & tensor convert;
	- add pad type support for pool3d;
	- make ops based on TensorFlow Lite quantization optional;
	- add all & any support for reduction;
	- use type in parameter as output type in reduction;
	- add int support for unary;
	- add variable weight support for conv2d;
	- fix conv2d depthwise weights initialization;
	- fix type support for transpose;
	- fix grad outputs count for  reduce grad and reshape grad;
	- fix priorbox & detection output;
	- fix metal softmax error;
- python:
	- add runSessionWithCallBackInfo interface;
	- add max nodes limit (1400) for visualization tool;
	- fix save error in python3;
	- align default dim;
- convert:
	- add extra design for optimization;
	- add more post converting optimizers;
	- add caffe v1 weights blob support;
	- add cast, unary, conv transpose support for onnx model;
	- optimize batchnorm, conv with variable weights, prelu, reshape, slice, upsample for onnx model;
	- add cos/sin/atan/tan support for unary for tensorflow model;
	- add any/all support for reduction for tensorflow model;
	- add elu, conv3d, pool3d support for tensorflow model;
	- optimize argmax, batchnorm, concat, batch to space, conv with variable weights, prelu, slice for tensorflow model;
- others:
	- fix size computer lock;
	- fix thread pool deadlock;
	- add express & parameters in express;
	- rewrite blitter chooser without static map;
	- add tests for expr;
											
										 
											2019-10-29 13:37:26 +08:00
										 |  |  |                 for (int p = 0; p < aspectRatiosValue.size(); p++) { | 
					
						
							|  |  |  |                     float arsqrt = sqrt(aspectRatiosValue[p]); | 
					
						
							|  |  |  |                     if (fabsf(arsqrt - 1.0f) < 1e-6) { | 
					
						
							|  |  |  |                         continue; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     float boxW = minSize * arsqrt; | 
					
						
							|  |  |  |                     float boxH = minSize / arsqrt; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     box[0] = (centerX - boxW * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[1] = (centerY - boxH * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box[2] = (centerX + boxW * 0.5f) / imageW; | 
					
						
							|  |  |  |                     box[3] = (centerY + boxH * 0.5f) / imageH; | 
					
						
							|  |  |  |                     box += 4; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // clip
 | 
					
						
							|  |  |  |     int oh = outputs[0]->height(); | 
					
						
							|  |  |  |     if (layer->clip()) { | 
					
						
							|  |  |  |         float *box = boxesPtr; | 
					
						
							|  |  |  |         for (int i = 0; i < oh; i++) { | 
					
						
							|  |  |  |             box[i] = std::min(std::max(box[i], 0.f), 1.f); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // set variance
 | 
					
						
							|  |  |  |     auto variances = layer->variances()->data(); | 
					
						
							|  |  |  |     auto var       = boxesPtr + oh; | 
					
						
							|  |  |  |     for (int i = 0; i < oh / 4; i++) { | 
					
						
							|  |  |  |         var[0] = variances[0]; | 
					
						
							|  |  |  |         var[1] = variances[1]; | 
					
						
							|  |  |  |         var[2] = variances[2]; | 
					
						
							|  |  |  |         var[3] = variances[3]; | 
					
						
							|  |  |  |         var += 4; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // transform to output
 | 
					
						
							|  |  |  |     auto output = outputs[0]; | 
					
						
							|  |  |  |     MNNPackC4(output->host<float>(), mOutputData.get(), output->height(), output->channel()); | 
					
						
							|  |  |  |     return NO_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CPUPriorBoxCreator : 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 { | 
					
						
							|  |  |  |         return new CPUPriorBox(backend, op); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | REGISTER_CPU_OP_CREATOR(CPUPriorBoxCreator, OpType_PriorBox); | 
					
						
							|  |  |  | } // namespace MNN
 |