1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Alexander Alekhin e8357c0544 build: added DEBUG build guard
To prevent linkage of binary incompatible DEBUG/RELEASE binaries/runtimes
2017-07-19 18:38:08 +03:00
Alexander Alekhin 95a438d233 OpenCV version '-cvsdk' 2017-07-14 13:03:12 +03:00
Alexander Alekhin 4238add35b Merge pull request #9058 from alalek:dnn_minor_fixes 2017-07-14 09:53:09 +00:00
Alexander Alekhin 4784c7be5f dnn: cleanup dispatched code, fix SIMD128 types 2017-07-13 19:00:34 +03:00
Alexander Alekhin c3e6de293f dnn: code cleanup, refactor detection output layer 2017-07-13 19:00:34 +03:00
Alexander Alekhin 544908d06c dnn: some minor fixes in docs, indentation, unused code 2017-07-13 15:33:49 +03:00
Alexander Alekhin 520da7aaaf Merge pull request #9111 from vpisarev:dnn_optim_avx1 2017-07-13 12:27:05 +00:00
Alexander Alekhin ed4de20fd1 Merge pull request #9107 from alalek:static_analyze_python 2017-07-12 16:45:14 +00:00
Alexander Alekhin 9b9e685dbc Merge pull request #9142 from alalek:vzeroupper_guard_unused_warning 2017-07-12 16:44:00 +00:00
Alexander Alekhin 49bb0bf9c8 Merge pull request #9149 from alalek:ocl_fp16_test 2017-07-12 16:23:33 +00:00
Alexander Alekhin d6c5e18e24 core(test): fix input data for OCL FP16 test 2017-07-12 18:51:11 +03:00
Alexander Alekhin 617e6b4cc9 Merge pull request #9145 from alalek:ipp_minmaxidx_nan 2017-07-12 15:37:54 +00:00
Alexander Alekhin 5ebfb52a4a ipp(minmaxIdx): disable SSE4.2 optimizations for 32f datatype
NaN values handling issue
2017-07-12 16:06:18 +03:00
Alexander Alekhin e7cc2eea1d build: fix unused variable warning for vzeroupper guard 2017-07-11 16:46:35 +03:00
Vadim Pisarevsky ed9564106c reuse AVX2-optimized kernels for AVX1 CPUs (like IvyBridge) 2017-07-06 21:36:59 +03:00
Alexander Alekhin b32d914aab static analyze: python dynamic_cast checks 2017-07-06 17:11:51 +03:00
19 changed files with 559 additions and 548 deletions
@@ -108,7 +108,7 @@ struct VZeroUpperGuard {
#endif #endif
inline ~VZeroUpperGuard() { _mm256_zeroupper(); } inline ~VZeroUpperGuard() { _mm256_zeroupper(); }
}; };
#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; #define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; (void)__vzeroupper_guard;
#endif #endif
#endif // __OPENCV_BUILD #endif // __OPENCV_BUILD
+17
View File
@@ -48,6 +48,23 @@
//! @addtogroup core_utils //! @addtogroup core_utils
//! @{ //! @{
#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD
#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \
(defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC))
// Guard to prevent using of binary incompatible binaries / runtimes
// https://github.com/opencv/opencv/pull/9161
#define CV__DEBUG_NS_BEGIN namespace debug_build_guard {
#define CV__DEBUG_NS_END }
namespace cv { namespace debug_build_guard { } using namespace debug_build_guard; }
#endif
#endif
#ifndef CV__DEBUG_NS_BEGIN
#define CV__DEBUG_NS_BEGIN
#define CV__DEBUG_NS_END
#endif
#ifdef __OPENCV_BUILD #ifdef __OPENCV_BUILD
#include "cvconfig.h" #include "cvconfig.h"
#endif #endif
@@ -62,6 +62,8 @@ namespace cv
enum { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25, enum { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25,
ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 }; ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 };
CV__DEBUG_NS_BEGIN
class CV_EXPORTS _OutputArray; class CV_EXPORTS _OutputArray;
//////////////////////// Input/Output Array Arguments ///////////////////////////////// //////////////////////// Input/Output Array Arguments /////////////////////////////////
@@ -400,6 +402,8 @@ public:
}; };
CV__DEBUG_NS_END
typedef const _InputArray& InputArray; typedef const _InputArray& InputArray;
typedef InputArray InputArrayOfArrays; typedef InputArray InputArrayOfArrays;
typedef const _OutputArray& OutputArray; typedef const _OutputArray& OutputArray;
@@ -56,6 +56,8 @@
namespace cv namespace cv
{ {
CV__DEBUG_NS_BEGIN
//! @cond IGNORED //! @cond IGNORED
@@ -392,6 +394,8 @@ inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf)
inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem) inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem)
{ init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); } { init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); }
CV__DEBUG_NS_END
//////////////////////////////////////////// Mat ////////////////////////////////////////// //////////////////////////////////////////// Mat //////////////////////////////////////////
inline inline
@@ -209,6 +209,8 @@ CV_EXPORTS void scalarToRawData(const cv::Scalar& s, void* buf, int type, int un
#define IPP_DISABLE_RESIZE_NEAREST 1 // Accuracy mismatch (max diff 1) #define IPP_DISABLE_RESIZE_NEAREST 1 // Accuracy mismatch (max diff 1)
#define IPP_DISABLE_RESIZE_AREA 1 // Accuracy mismatch (max diff 1) #define IPP_DISABLE_RESIZE_AREA 1 // Accuracy mismatch (max diff 1)
#define IPP_DISABLE_MINMAX_NAN_SSE42 1 // cv::minMaxIdx problem with NaN input
// Temporary disabled named IPP region. Performance // Temporary disabled named IPP region. Performance
#define IPP_DISABLE_PERF_COPYMAKE 1 // performance variations #define IPP_DISABLE_PERF_COPYMAKE 1 // performance variations
#define IPP_DISABLE_PERF_LUT 1 // there are no performance benefits (PR #2653) #define IPP_DISABLE_PERF_LUT 1 // there are no performance benefits (PR #2653)
@@ -53,7 +53,7 @@
#define CV_VERSION_MAJOR 3 #define CV_VERSION_MAJOR 3
#define CV_VERSION_MINOR 3 #define CV_VERSION_MINOR 3
#define CV_VERSION_REVISION 0 #define CV_VERSION_REVISION 0
#define CV_VERSION_STATUS "-rc" #define CV_VERSION_STATUS "-cvsdk"
#define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR_EXP(__A) #__A
#define CVAUX_STR(__A) CVAUX_STR_EXP(__A) #define CVAUX_STR(__A) CVAUX_STR_EXP(__A)
+6
View File
@@ -2534,6 +2534,12 @@ static bool ipp_minMaxIdx(Mat &src, double* _minVal, double* _maxVal, int* _minI
#if IPP_VERSION_X100 >= 700 #if IPP_VERSION_X100 >= 700
CV_INSTRUMENT_REGION_IPP() CV_INSTRUMENT_REGION_IPP()
#if IPP_DISABLE_MINMAX_NAN_SSE42
// Disable 32F processing only
if(src.depth() == CV_32F && !(ipp::getIppFeatures()&ippCPUID_AVX))
return false;
#endif
IppStatus status; IppStatus status;
IppDataType dataType = ippiGetDataType(src.depth()); IppDataType dataType = ippiGetDataType(src.depth());
float minVal = 0; float minVal = 0;
+8
View File
@@ -1639,6 +1639,14 @@ PARAM_TEST_CASE(ConvertFp16, Channels, bool)
Size roiSize = randomSize(1, MAX_VALUE); Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, 0); Border srcBorder = randomBorder(0, 0);
randomSubMat(src, src_roi, roiSize, srcBorder, stype, -11, 11); // FIXIT: Test with minV, maxV randomSubMat(src, src_roi, roiSize, srcBorder, stype, -11, 11); // FIXIT: Test with minV, maxV
if (stype == CV_MAKE_TYPE(CV_16S, cn)) // eliminate NaN/Inf FP16 values
{
RNG dataRng(rng.next());
Mat src_i32 = cvtest::randomMat(dataRng, roiSize, CV_MAKE_TYPE(CV_32S, cn), 0, 0x7c00, false);
Mat shift_i32 = cvtest::randomMat(dataRng, roiSize, src_i32.type(), -1, 1, false); // values: -1, 0
src_i32 = src_i32 + (shift_i32 * 0x8000);
src_i32.convertTo(src_roi, stype);
}
Border dstBorder = randomBorder(0, 0); Border dstBorder = randomBorder(0, 0);
randomSubMat(dst, dst_roi, roiSize, dstBorder, dtype, 5, 16); randomSubMat(dst, dst_roi, roiSize, dstBorder, dtype, 5, 16);
+2
View File
@@ -9,6 +9,8 @@ endif()
set(the_description "Deep neural network module. It allows to load models from different frameworks and to make forward pass") set(the_description "Deep neural network module. It allows to load models from different frameworks and to make forward pass")
ocv_add_dispatched_file("layers/layers_common" AVX AVX2)
ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java) ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo
-Wmissing-declarations -Wmissing-prototypes -Wmissing-declarations -Wmissing-prototypes
+1 -1
View File
@@ -44,7 +44,7 @@
// This is an umbrealla header to include into you project. // This is an umbrealla header to include into you project.
// We are free to change headers layout in dnn subfolder, so please include // We are free to change headers layout in dnn subfolder, so please include
// this header for future compartibility // this header for future compatibility
/** @defgroup dnn Deep Neural Network module /** @defgroup dnn Deep Neural Network module
+13 -12
View File
@@ -152,7 +152,19 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
int outputNameToIndex(String outputName); int outputNameToIndex(String outputName);
}; };
//! Classical recurrent layer /** @brief Classical recurrent layer
Accepts two inputs @f$x_t@f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t@f$ and @f$h_t@f$.
- input: should contain packed input @f$x_t@f$.
- output: should contain output @f$o_t@f$ (and @f$h_t@f$ if setProduceHiddenOutput() is set to true).
input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t@f$ respectively.
output[0] will have shape [`T`, `N`, @f$N_o@f$], where @f$N_o@f$ is number of rows in @f$ W_{xo} @f$ matrix.
If setProduceHiddenOutput() is set to true then @p output[1] will contain a Mat with shape [`T`, `N`, @f$N_h@f$], where @f$N_h@f$ is number of rows in @f$ W_{hh} @f$ matrix.
*/
class CV_EXPORTS RNNLayer : public Layer class CV_EXPORTS RNNLayer : public Layer
{ {
public: public:
@@ -180,17 +192,6 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
virtual void setProduceHiddenOutput(bool produce = false) = 0; virtual void setProduceHiddenOutput(bool produce = false) = 0;
/** Accepts two inputs @f$x_t@f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t@f$ and @f$h_t@f$.
@param input should contain packed input @f$x_t@f$.
@param output should contain output @f$o_t@f$ (and @f$h_t@f$ if setProduceHiddenOutput() is set to true).
@p input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t@f$ respectively.
@p output[0] will have shape [`T`, `N`, @f$N_o@f$], where @f$N_o@f$ is number of rows in @f$ W_{xo} @f$ matrix.
If setProduceHiddenOutput() is set to true then @p output[1] will contain a Mat with shape [`T`, `N`, @f$N_h@f$], where @f$N_h@f$ is number of rows in @f$ W_{hh} @f$ matrix.
*/
}; };
class CV_EXPORTS BaseConvolutionLayer : public Layer class CV_EXPORTS BaseConvolutionLayer : public Layer
+94 -94
View File
@@ -371,28 +371,28 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
/** @brief Runs forward pass to compute output of layer with name @p outputName. /** @brief Runs forward pass to compute output of layer with name @p outputName.
* @param outputName name for layer which output is needed to get * @param outputName name for layer which output is needed to get
* @return blob for first output of specified layer. * @return blob for first output of specified layer.
* @details By default runs forward pass for the whole network. * @details By default runs forward pass for the whole network.
*/ */
CV_WRAP Mat forward(const String& outputName = String()); CV_WRAP Mat forward(const String& outputName = String());
/** @brief Runs forward pass to compute output of layer with name @p outputName. /** @brief Runs forward pass to compute output of layer with name @p outputName.
* @param outputBlobs contains all output blobs for specified layer. * @param outputBlobs contains all output blobs for specified layer.
* @param outputName name for layer which output is needed to get * @param outputName name for layer which output is needed to get
* @details If @p outputName is empty, runs forward pass for the whole network. * @details If @p outputName is empty, runs forward pass for the whole network.
*/ */
CV_WRAP void forward(std::vector<Mat>& outputBlobs, const String& outputName = String()); CV_WRAP void forward(std::vector<Mat>& outputBlobs, const String& outputName = String());
/** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames. /** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames.
* @param outputBlobs contains blobs for first outputs of specified layers. * @param outputBlobs contains blobs for first outputs of specified layers.
* @param outBlobNames names for layers which outputs are needed to get * @param outBlobNames names for layers which outputs are needed to get
*/ */
CV_WRAP void forward(std::vector<Mat>& outputBlobs, CV_WRAP void forward(std::vector<Mat>& outputBlobs,
const std::vector<String>& outBlobNames); const std::vector<String>& outBlobNames);
/** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames. /** @brief Runs forward pass to compute outputs of layers listed in @p outBlobNames.
* @param outputBlobs contains all output blobs for each layer specified in @p outBlobNames. * @param outputBlobs contains all output blobs for each layer specified in @p outBlobNames.
* @param outBlobNames names for layers which outputs are needed to get * @param outBlobNames names for layers which outputs are needed to get
*/ */
CV_WRAP void forward(std::vector<std::vector<Mat> >& outputBlobs, CV_WRAP void forward(std::vector<std::vector<Mat> >& outputBlobs,
const std::vector<String>& outBlobNames); const std::vector<String>& outBlobNames);
@@ -460,103 +460,103 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
CV_WRAP std::vector<int> getUnconnectedOutLayers() const; CV_WRAP std::vector<int> getUnconnectedOutLayers() const;
/** @brief Returns input and output shapes for all layers in loaded model; /** @brief Returns input and output shapes for all layers in loaded model;
* preliminary inferencing isn't necessary. * preliminary inferencing isn't necessary.
* @param netInputShapes shapes for all input blobs in net input layer. * @param netInputShapes shapes for all input blobs in net input layer.
* @param layersIds output parameter for layer IDs. * @param layersIds output parameter for layer IDs.
* @param inLayersShapes output parameter for input layers shapes; * @param inLayersShapes output parameter for input layers shapes;
* order is the same as in layersIds * order is the same as in layersIds
* @param outLayersShapes output parameter for output layers shapes; * @param outLayersShapes output parameter for output layers shapes;
* order is the same as in layersIds * order is the same as in layersIds
*/ */
CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes, CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
std::vector<int>* layersIds, std::vector<int>* layersIds,
std::vector<std::vector<MatShape> >* inLayersShapes, std::vector<std::vector<MatShape> >* inLayersShapes,
std::vector<std::vector<MatShape> >* outLayersShapes) const; std::vector<std::vector<MatShape> >* outLayersShapes) const;
/** @overload */ /** @overload */
CV_WRAP void getLayersShapes(const MatShape& netInputShape, CV_WRAP void getLayersShapes(const MatShape& netInputShape,
std::vector<int>* layersIds, std::vector<int>* layersIds,
std::vector<std::vector<MatShape> >* inLayersShapes, std::vector<std::vector<MatShape> >* inLayersShapes,
std::vector<std::vector<MatShape> >* outLayersShapes) const; std::vector<std::vector<MatShape> >* outLayersShapes) const;
/** @brief Returns input and output shapes for layer with specified /** @brief Returns input and output shapes for layer with specified
* id in loaded model; preliminary inferencing isn't necessary. * id in loaded model; preliminary inferencing isn't necessary.
* @param netInputShape shape input blob in net input layer. * @param netInputShape shape input blob in net input layer.
* @param layerId id for layer. * @param layerId id for layer.
* @param inLayerShapes output parameter for input layers shapes; * @param inLayerShapes output parameter for input layers shapes;
* order is the same as in layersIds * order is the same as in layersIds
* @param outLayerShapes output parameter for output layers shapes; * @param outLayerShapes output parameter for output layers shapes;
* order is the same as in layersIds * order is the same as in layersIds
*/ */
CV_WRAP void getLayerShapes(const MatShape& netInputShape, CV_WRAP void getLayerShapes(const MatShape& netInputShape,
const int layerId,
std::vector<MatShape>* inLayerShapes,
std::vector<MatShape>* outLayerShapes) const;
/** @overload */
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes,
const int layerId, const int layerId,
std::vector<MatShape>* inLayerShapes, std::vector<MatShape>* inLayerShapes,
std::vector<MatShape>* outLayerShapes) const; std::vector<MatShape>* outLayerShapes) const;
/** @brief Computes FLOP for whole loaded model with specified input shapes.
* @param netInputShapes vector of shapes for all net inputs.
* @returns computed FLOP.
*/
CV_WRAP int64 getFLOPS(const std::vector<MatShape>& netInputShapes) const;
/** @overload */
CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const;
/** @overload */
CV_WRAP int64 getFLOPS(const int layerId,
const std::vector<MatShape>& netInputShapes) const;
/** @overload */
CV_WRAP int64 getFLOPS(const int layerId,
const MatShape& netInputShape) const;
/** @overload */ /** @brief Returns list of types for layer used in model.
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes, * @param layersTypes output parameter for returning types.
const int layerId, */
std::vector<MatShape>* inLayerShapes, CV_WRAP void getLayerTypes(CV_OUT std::vector<String>& layersTypes) const;
std::vector<MatShape>* outLayerShapes) const;
/** @brief Computes FLOP for whole loaded model with specified input shapes.
* @param netInputShapes vector of shapes for all net inputs.
* @returns computed FLOP.
*/
CV_WRAP int64 getFLOPS(const std::vector<MatShape>& netInputShapes) const;
/** @overload */
CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const;
/** @overload */
CV_WRAP int64 getFLOPS(const int layerId,
const std::vector<MatShape>& netInputShapes) const;
/** @overload */
CV_WRAP int64 getFLOPS(const int layerId,
const MatShape& netInputShape) const;
/** @brief Returns list of types for layer used in model. /** @brief Returns count of layers of specified type.
* @param layersTypes output parameter for returning types. * @param layerType type.
*/ * @returns count of layers
CV_WRAP void getLayerTypes(CV_OUT std::vector<String>& layersTypes) const; */
CV_WRAP int getLayersCount(const String& layerType) const;
/** @brief Returns count of layers of specified type. /** @brief Computes bytes number which are requered to store
* @param layerType type. * all weights and intermediate blobs for model.
* @returns count of layers * @param netInputShapes vector of shapes for all net inputs.
*/ * @param weights output parameter to store resulting bytes for weights.
CV_WRAP int getLayersCount(const String& layerType) const; * @param blobs output parameter to store resulting bytes for intermediate blobs.
*/
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @overload */
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @overload */
CV_WRAP void getMemoryConsumption(const int layerId,
const std::vector<MatShape>& netInputShapes,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @overload */
CV_WRAP void getMemoryConsumption(const int layerId,
const MatShape& netInputShape,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @brief Computes bytes number which are requered to store /** @brief Computes bytes number which are requered to store
* all weights and intermediate blobs for model. * all weights and intermediate blobs for each layer.
* @param netInputShapes vector of shapes for all net inputs. * @param netInputShapes vector of shapes for all net inputs.
* @param weights output parameter to store resulting bytes for weights. * @param layerIds output vector to save layer IDs.
* @param blobs output parameter to store resulting bytes for intermediate blobs. * @param weights output parameter to store resulting bytes for weights.
*/ * @param blobs output parameter to store resulting bytes for intermediate blobs.
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes, */
CV_OUT size_t& weights, CV_OUT size_t& blobs) const; CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
/** @overload */ CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape, CV_OUT std::vector<size_t>& blobs) const;
CV_OUT size_t& weights, CV_OUT size_t& blobs) const; /** @overload */
/** @overload */ CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
CV_WRAP void getMemoryConsumption(const int layerId, CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
const std::vector<MatShape>& netInputShapes, CV_OUT std::vector<size_t>& blobs) const;
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @overload */
CV_WRAP void getMemoryConsumption(const int layerId,
const MatShape& netInputShape,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
/** @brief Computes bytes number which are requered to store
* all weights and intermediate blobs for each layer.
* @param netInputShapes vector of shapes for all net inputs.
* @param layerIds output vector to save layer IDs.
* @param weights output parameter to store resulting bytes for weights.
* @param blobs output parameter to store resulting bytes for intermediate blobs.
*/
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
CV_OUT std::vector<size_t>& blobs) const;
/** @overload */
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
CV_OUT std::vector<size_t>& blobs) const;
private: private:
struct Impl; struct Impl;
-3
View File
@@ -969,9 +969,6 @@ struct Net::Impl
} }
} }
#define CV_RETHROW_ERROR(err, newmsg)\
cv::error(err.code, newmsg, err.func.c_str(), err.file.c_str(), err.line)
void allocateLayer(int lid, const LayersShapesMap& layersShapes) void allocateLayer(int lid, const LayersShapesMap& layersShapes)
{ {
CV_TRACE_FUNCTION(); CV_TRACE_FUNCTION();
+18 -3
View File
@@ -285,11 +285,12 @@ public:
const std::vector<float>* reluslope_; const std::vector<float>* reluslope_;
const ActivationLayer* activ_; const ActivationLayer* activ_;
bool is1x1_; bool is1x1_;
bool useAVX;
bool useAVX2; bool useAVX2;
ParallelConv() ParallelConv()
: input_(0), weights_(0), output_(0), ngroups_(0), nstripes_(0), : input_(0), weights_(0), output_(0), ngroups_(0), nstripes_(0),
biasvec_(0), reluslope_(0), activ_(0), is1x1_(false), useAVX2(false) biasvec_(0), reluslope_(0), activ_(0), is1x1_(false), useAVX(false), useAVX2(false)
{} {}
static void run( const Mat& input, Mat& output, const Mat& weights, static void run( const Mat& input, Mat& output, const Mat& weights,
@@ -322,6 +323,7 @@ public:
int inpCnAll = input.size[1], width = input.size[3], height = input.size[2]; int inpCnAll = input.size[1], width = input.size[3], height = input.size[2];
int inpCn = inpCnAll / ngroups; int inpCn = inpCnAll / ngroups;
p.is1x1_ = kernel == Size(0,0) && pad == Size(0, 0); p.is1x1_ = kernel == Size(0,0) && pad == Size(0, 0);
p.useAVX = checkHardwareSupport(CPU_AVX);
p.useAVX2 = checkHardwareSupport(CPU_AVX2); p.useAVX2 = checkHardwareSupport(CPU_AVX2);
int ncn = std::min(inpCn, (int)BLK_SIZE_CN); int ncn = std::min(inpCn, (int)BLK_SIZE_CN);
@@ -504,9 +506,15 @@ public:
int bsz = ofs1 - ofs0; int bsz = ofs1 - ofs0;
#if CV_TRY_AVX2 #if CV_TRY_AVX2
if(useAVX2) if(useAVX2)
fastConv_avx2(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0, opt_AVX2::fastConv(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0,
outShape, bsz, vsz, vsz_a, relu, cn0 == 0); outShape, bsz, vsz, vsz_a, relu, cn0 == 0);
else else
#endif
#if CV_TRY_AVX
if(useAVX)
opt_AVX::fastConv(wptr, wstep, biasptr, rowbuf0, data_out0 + ofs0,
outShape, bsz, vsz, vsz_a, relu, cn0 == 0);
else
#endif #endif
for( int i = 0; i < outCn; i += 2 ) for( int i = 0; i < outCn; i += 2 )
{ {
@@ -795,6 +803,7 @@ public:
b_ = &b; b_ = &b;
c_ = &c; c_ = &c;
nstripes_ = nstripes; nstripes_ = nstripes;
useAVX = checkHardwareSupport(CPU_AVX);
useAVX2 = checkHardwareSupport(CPU_AVX2); useAVX2 = checkHardwareSupport(CPU_AVX2);
} }
@@ -815,7 +824,12 @@ public:
#if CV_TRY_AVX2 #if CV_TRY_AVX2
if( useAVX2 ) if( useAVX2 )
fastGEMM_avx2( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax ); opt_AVX2::fastGEMM( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax );
else
#endif
#if CV_TRY_AVX
if( useAVX )
opt_AVX::fastGEMM( aptr, astep, bptr, bstep, cptr, cstep, mmax, kmax, nmax );
else else
#endif #endif
for( m = 0; m < mmax; m += 2 ) for( m = 0; m < mmax; m += 2 )
@@ -910,6 +924,7 @@ public:
const Mat *a_, *b_; const Mat *a_, *b_;
Mat* c_; Mat* c_;
int nstripes_; int nstripes_;
bool useAVX;
bool useAVX2; bool useAVX2;
}; };
+319 -394
View File
@@ -55,29 +55,13 @@ namespace util
{ {
template <typename T> template <typename T>
std::string to_string(T value) static inline bool SortScorePairDescend(const std::pair<float, T>& pair1,
{
std::ostringstream stream;
stream << value;
return stream.str();
}
template <typename T>
void make_error(const std::string& message1, const T& message2)
{
std::string error(message1);
error += std::string(util::to_string<int>(message2));
CV_Error(Error::StsBadArg, error.c_str());
}
template <typename T>
bool SortScorePairDescend(const std::pair<float, T>& pair1,
const std::pair<float, T>& pair2) const std::pair<float, T>& pair2)
{ {
return pair1.first > pair2.first; return pair1.first > pair2.first;
} }
} } // namespace
class DetectionOutputLayerImpl : public DetectionOutputLayer class DetectionOutputLayerImpl : public DetectionOutputLayer
{ {
@@ -133,7 +117,7 @@ public:
message += " layer parameter does not contain "; message += " layer parameter does not contain ";
message += parameterName; message += parameterName;
message += " parameter."; message += " parameter.";
CV_Error(Error::StsBadArg, message); CV_ErrorNoReturn(Error::StsBadArg, message);
} }
else else
{ {
@@ -209,180 +193,173 @@ public:
CV_TRACE_FUNCTION(); CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str()); CV_TRACE_ARG_VALUE(name, "name", name.c_str());
const float* locationData = inputs[0]->ptr<float>(); std::vector<LabelBBox> allDecodedBBoxes;
const float* confidenceData = inputs[1]->ptr<float>(); std::vector<std::vector<std::vector<float> > > allConfidenceScores;
const float* priorData = inputs[2]->ptr<float>();
int num = inputs[0]->size[0]; int num = inputs[0]->size[0];
int numPriors = inputs[2]->size[2] / 4;
// Retrieve all location predictions. // extract predictions from input layers
std::vector<LabelBBox> allLocationPredictions; {
GetLocPredictions(locationData, num, numPriors, _numLocClasses, int numPriors = inputs[2]->size[2] / 4;
_shareLocation, &allLocationPredictions);
// Retrieve all confidences. const float* locationData = inputs[0]->ptr<float>();
std::vector<std::vector<std::vector<float> > > allConfidenceScores; const float* confidenceData = inputs[1]->ptr<float>();
GetConfidenceScores(confidenceData, num, numPriors, _numClasses, const float* priorData = inputs[2]->ptr<float>();
&allConfidenceScores);
// Retrieve all prior bboxes. It is same within a batch since we assume all // Retrieve all location predictions
// images in a batch are of same dimension. std::vector<LabelBBox> allLocationPredictions;
std::vector<caffe::NormalizedBBox> priorBBoxes; GetLocPredictions(locationData, num, numPriors, _numLocClasses,
std::vector<std::vector<float> > priorVariances; _shareLocation, allLocationPredictions);
GetPriorBBoxes(priorData, numPriors, &priorBBoxes, &priorVariances);
const bool clip_bbox = false; // Retrieve all confidences
// Decode all loc predictions to bboxes. GetConfidenceScores(confidenceData, num, numPriors, _numClasses, allConfidenceScores);
std::vector<LabelBBox> allDecodedBBoxes;
DecodeBBoxesAll(allLocationPredictions, priorBBoxes, priorVariances, num,
_shareLocation, _numLocClasses, _backgroundLabelId,
_codeType, _varianceEncodedInTarget, clip_bbox, &allDecodedBBoxes);
int numKept = 0; // Retrieve all prior bboxes
std::vector<caffe::NormalizedBBox> priorBBoxes;
std::vector<std::vector<float> > priorVariances;
GetPriorBBoxes(priorData, numPriors, priorBBoxes, priorVariances);
// Decode all loc predictions to bboxes
DecodeBBoxesAll(allLocationPredictions, priorBBoxes, priorVariances, num,
_shareLocation, _numLocClasses, _backgroundLabelId,
_codeType, _varianceEncodedInTarget, false, allDecodedBBoxes);
}
size_t numKept = 0;
std::vector<std::map<int, std::vector<int> > > allIndices; std::vector<std::map<int, std::vector<int> > > allIndices;
for (int i = 0; i < num; ++i) for (int i = 0; i < num; ++i)
{ {
const LabelBBox& decodeBBoxes = allDecodedBBoxes[i]; numKept += processDetections_(allDecodedBBoxes[i], allConfidenceScores[i], allIndices);
const std::vector<std::vector<float> >& confidenceScores =
allConfidenceScores[i];
std::map<int, std::vector<int> > indices;
int numDetections = 0;
for (int c = 0; c < (int)_numClasses; ++c)
{
if (c == _backgroundLabelId)
{
// Ignore background class.
continue;
}
if (confidenceScores.size() <= c)
{
// Something bad happened if there are no predictions for current label.
util::make_error<int>("Could not find confidence predictions for label ", c);
}
const std::vector<float>& scores = confidenceScores[c];
int label = _shareLocation ? -1 : c;
if (decodeBBoxes.find(label) == decodeBBoxes.end())
{
// Something bad happened if there are no predictions for current label.
util::make_error<int>("Could not find location predictions for label ", label);
continue;
}
const std::vector<caffe::NormalizedBBox>& bboxes =
decodeBBoxes.find(label)->second;
ApplyNMSFast(bboxes, scores, _confidenceThreshold, _nmsThreshold, 1.0,
_topK, &(indices[c]));
numDetections += indices[c].size();
}
if (_keepTopK > -1 && numDetections > _keepTopK)
{
std::vector<std::pair<float, std::pair<int, int> > > scoreIndexPairs;
for (std::map<int, std::vector<int> >::iterator it = indices.begin();
it != indices.end(); ++it)
{
int label = it->first;
const std::vector<int>& labelIndices = it->second;
if (confidenceScores.size() <= label)
{
// Something bad happened for current label.
util::make_error<int>("Could not find location predictions for label ", label);
continue;
}
const std::vector<float>& scores = confidenceScores[label];
for (size_t j = 0; j < labelIndices.size(); ++j)
{
size_t idx = labelIndices[j];
CV_Assert(idx < scores.size());
scoreIndexPairs.push_back(
std::make_pair(scores[idx], std::make_pair(label, idx)));
}
}
// Keep outputs k results per image.
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
util::SortScorePairDescend<std::pair<int, int> >);
scoreIndexPairs.resize(_keepTopK);
// Store the new indices.
std::map<int, std::vector<int> > newIndices;
for (size_t j = 0; j < scoreIndexPairs.size(); ++j)
{
int label = scoreIndexPairs[j].second.first;
int idx = scoreIndexPairs[j].second.second;
newIndices[label].push_back(idx);
}
allIndices.push_back(newIndices);
numKept += _keepTopK;
}
else
{
allIndices.push_back(indices);
numKept += numDetections;
}
} }
if (numKept == 0) if (numKept == 0)
{ {
CV_ErrorNoReturn(Error::StsError, "Couldn't find any detections"); CV_ErrorNoReturn(Error::StsError, "Couldn't find any detections");
return;
} }
int outputShape[] = {1, 1, numKept, 7}; int outputShape[] = {1, 1, (int)numKept, 7};
outputs[0].create(4, outputShape, CV_32F); outputs[0].create(4, outputShape, CV_32F);
float* outputsData = outputs[0].ptr<float>(); float* outputsData = outputs[0].ptr<float>();
int count = 0; size_t count = 0;
for (int i = 0; i < num; ++i) for (int i = 0; i < num; ++i)
{ {
const std::vector<std::vector<float> >& confidenceScores = count += outputDetections_(i, &outputsData[count * 7],
allConfidenceScores[i]; allDecodedBBoxes[i], allConfidenceScores[i],
const LabelBBox& decodeBBoxes = allDecodedBBoxes[i]; allIndices[i]);
for (std::map<int, std::vector<int> >::iterator it = allIndices[i].begin(); }
it != allIndices[i].end(); ++it) CV_Assert(count == numKept);
}
size_t outputDetections_(
const int i, float* outputsData,
const LabelBBox& decodeBBoxes, const std::vector<std::vector<float> >& confidenceScores,
const std::map<int, std::vector<int> >& indicesMap
)
{
size_t count = 0;
for (std::map<int, std::vector<int> >::const_iterator it = indicesMap.begin(); it != indicesMap.end(); ++it)
{
int label = it->first;
if (confidenceScores.size() <= label)
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find confidence predictions for label %d", label));
const std::vector<float>& scores = confidenceScores[label];
int locLabel = _shareLocation ? -1 : label;
LabelBBox::const_iterator label_bboxes = decodeBBoxes.find(locLabel);
if (label_bboxes == decodeBBoxes.end())
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", locLabel));
const std::vector<int>& indices = it->second;
for (size_t j = 0; j < indices.size(); ++j, ++count)
{
int idx = indices[j];
const caffe::NormalizedBBox& decode_bbox = label_bboxes->second[idx];
outputsData[count * 7] = i;
outputsData[count * 7 + 1] = label;
outputsData[count * 7 + 2] = scores[idx];
outputsData[count * 7 + 3] = decode_bbox.xmin();
outputsData[count * 7 + 4] = decode_bbox.ymin();
outputsData[count * 7 + 5] = decode_bbox.xmax();
outputsData[count * 7 + 6] = decode_bbox.ymax();
}
}
return count;
}
size_t processDetections_(
const LabelBBox& decodeBBoxes, const std::vector<std::vector<float> >& confidenceScores,
std::vector<std::map<int, std::vector<int> > >& allIndices
)
{
std::map<int, std::vector<int> > indices;
size_t numDetections = 0;
for (int c = 0; c < (int)_numClasses; ++c)
{
if (c == _backgroundLabelId)
continue; // Ignore background class.
if (c >= confidenceScores.size())
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find confidence predictions for label %d", c));
const std::vector<float>& scores = confidenceScores[c];
int label = _shareLocation ? -1 : c;
LabelBBox::const_iterator label_bboxes = decodeBBoxes.find(label);
if (label_bboxes == decodeBBoxes.end())
CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
ApplyNMSFast(label_bboxes->second, scores, _confidenceThreshold, _nmsThreshold, 1.0, _topK, indices[c]);
numDetections += indices[c].size();
}
if (_keepTopK > -1 && numDetections > (size_t)_keepTopK)
{
std::vector<std::pair<float, std::pair<int, int> > > scoreIndexPairs;
for (std::map<int, std::vector<int> >::iterator it = indices.begin();
it != indices.end(); ++it)
{ {
int label = it->first; int label = it->first;
if (confidenceScores.size() <= label) const std::vector<int>& labelIndices = it->second;
{ if (label >= confidenceScores.size())
// Something bad happened if there are no predictions for current label. CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
util::make_error<int>("Could not find confidence predictions for label ", label);
continue;
}
const std::vector<float>& scores = confidenceScores[label]; const std::vector<float>& scores = confidenceScores[label];
int locLabel = _shareLocation ? -1 : label; for (size_t j = 0; j < labelIndices.size(); ++j)
if (decodeBBoxes.find(locLabel) == decodeBBoxes.end())
{ {
// Something bad happened if there are no predictions for current label. size_t idx = labelIndices[j];
util::make_error<int>("Could not find location predictions for label ", locLabel); CV_Assert(idx < scores.size());
continue; scoreIndexPairs.push_back(std::make_pair(scores[idx], std::make_pair(label, idx)));
}
const std::vector<caffe::NormalizedBBox>& bboxes =
decodeBBoxes.find(locLabel)->second;
std::vector<int>& indices = it->second;
for (size_t j = 0; j < indices.size(); ++j)
{
int idx = indices[j];
outputsData[count * 7] = i;
outputsData[count * 7 + 1] = label;
outputsData[count * 7 + 2] = scores[idx];
caffe::NormalizedBBox clipBBox = bboxes[idx];
outputsData[count * 7 + 3] = clipBBox.xmin();
outputsData[count * 7 + 4] = clipBBox.ymin();
outputsData[count * 7 + 5] = clipBBox.xmax();
outputsData[count * 7 + 6] = clipBBox.ymax();
++count;
} }
} }
// Keep outputs k results per image.
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
util::SortScorePairDescend<std::pair<int, int> >);
scoreIndexPairs.resize(_keepTopK);
std::map<int, std::vector<int> > newIndices;
for (size_t j = 0; j < scoreIndexPairs.size(); ++j)
{
int label = scoreIndexPairs[j].second.first;
int idx = scoreIndexPairs[j].second.second;
newIndices[label].push_back(idx);
}
allIndices.push_back(newIndices);
return (size_t)_keepTopK;
}
else
{
allIndices.push_back(indices);
return numDetections;
} }
} }
// Compute bbox size.
float BBoxSize(const caffe::NormalizedBBox& bbox, // **************************************************************
const bool normalized=true) // Utility functions
// **************************************************************
// Compute bbox size
template<bool normalized>
static float BBoxSize(const caffe::NormalizedBBox& bbox)
{ {
if (bbox.xmax() < bbox.xmin() || bbox.ymax() < bbox.ymin()) if (bbox.xmax() < bbox.xmin() || bbox.ymax() < bbox.ymin())
{ {
// If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0. return 0; // If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
return 0;
} }
else else
{ {
@@ -407,193 +384,155 @@ public:
} }
} }
// Clip the caffe::NormalizedBBox such that the range for each corner is [0, 1].
void ClipBBox(const caffe::NormalizedBBox& bbox,
caffe::NormalizedBBox* clipBBox)
{
clipBBox->set_xmin(std::max(std::min(bbox.xmin(), 1.f), 0.f));
clipBBox->set_ymin(std::max(std::min(bbox.ymin(), 1.f), 0.f));
clipBBox->set_xmax(std::max(std::min(bbox.xmax(), 1.f), 0.f));
clipBBox->set_ymax(std::max(std::min(bbox.ymax(), 1.f), 0.f));
clipBBox->clear_size();
clipBBox->set_size(BBoxSize(*clipBBox));
clipBBox->set_difficult(bbox.difficult());
}
// Decode a bbox according to a prior bbox. // Decode a bbox according to a prior bbox
void DecodeBBox( template<bool variance_encoded_in_target>
static void DecodeBBox(
const caffe::NormalizedBBox& prior_bbox, const std::vector<float>& prior_variance, const caffe::NormalizedBBox& prior_bbox, const std::vector<float>& prior_variance,
const CodeType code_type, const bool variance_encoded_in_target, const CodeType code_type,
const bool clip_bbox, const caffe::NormalizedBBox& bbox, const bool clip_bbox, const caffe::NormalizedBBox& bbox,
caffe::NormalizedBBox* decode_bbox) { caffe::NormalizedBBox& decode_bbox)
if (code_type == caffe::PriorBoxParameter_CodeType_CORNER) { {
if (variance_encoded_in_target) { float bbox_xmin = variance_encoded_in_target ? bbox.xmin() : prior_variance[0] * bbox.xmin();
// variance is encoded in target, we simply need to add the offset float bbox_ymin = variance_encoded_in_target ? bbox.ymin() : prior_variance[1] * bbox.ymin();
// predictions. float bbox_xmax = variance_encoded_in_target ? bbox.xmax() : prior_variance[2] * bbox.xmax();
decode_bbox->set_xmin(prior_bbox.xmin() + bbox.xmin()); float bbox_ymax = variance_encoded_in_target ? bbox.ymax() : prior_variance[3] * bbox.ymax();
decode_bbox->set_ymin(prior_bbox.ymin() + bbox.ymin()); switch(code_type)
decode_bbox->set_xmax(prior_bbox.xmax() + bbox.xmax()); {
decode_bbox->set_ymax(prior_bbox.ymax() + bbox.ymax()); case caffe::PriorBoxParameter_CodeType_CORNER:
} else { decode_bbox.set_xmin(prior_bbox.xmin() + bbox_xmin);
// variance is encoded in bbox, we need to scale the offset accordingly. decode_bbox.set_ymin(prior_bbox.ymin() + bbox_ymin);
decode_bbox->set_xmin( decode_bbox.set_xmax(prior_bbox.xmax() + bbox_xmax);
prior_bbox.xmin() + prior_variance[0] * bbox.xmin()); decode_bbox.set_ymax(prior_bbox.ymax() + bbox_ymax);
decode_bbox->set_ymin( break;
prior_bbox.ymin() + prior_variance[1] * bbox.ymin()); case caffe::PriorBoxParameter_CodeType_CENTER_SIZE:
decode_bbox->set_xmax( {
prior_bbox.xmax() + prior_variance[2] * bbox.xmax()); float prior_width = prior_bbox.xmax() - prior_bbox.xmin();
decode_bbox->set_ymax( CV_Assert(prior_width > 0);
prior_bbox.ymax() + prior_variance[3] * bbox.ymax()); float prior_height = prior_bbox.ymax() - prior_bbox.ymin();
} CV_Assert(prior_height > 0);
} else if (code_type == caffe::PriorBoxParameter_CodeType_CENTER_SIZE) { float prior_center_x = (prior_bbox.xmin() + prior_bbox.xmax()) * .5;
float prior_width = prior_bbox.xmax() - prior_bbox.xmin(); float prior_center_y = (prior_bbox.ymin() + prior_bbox.ymax()) * .5;
CV_Assert(prior_width > 0);
float prior_height = prior_bbox.ymax() - prior_bbox.ymin();
CV_Assert(prior_height > 0);
float prior_center_x = (prior_bbox.xmin() + prior_bbox.xmax()) / 2.;
float prior_center_y = (prior_bbox.ymin() + prior_bbox.ymax()) / 2.;
float decode_bbox_center_x, decode_bbox_center_y; float decode_bbox_center_x, decode_bbox_center_y;
float decode_bbox_width, decode_bbox_height; float decode_bbox_width, decode_bbox_height;
if (variance_encoded_in_target) { decode_bbox_center_x = bbox_xmin * prior_width + prior_center_x;
// variance is encoded in target, we simply need to retore the offset decode_bbox_center_y = bbox_ymin * prior_height + prior_center_y;
// predictions. decode_bbox_width = exp(bbox_xmax) * prior_width;
decode_bbox_center_x = bbox.xmin() * prior_width + prior_center_x; decode_bbox_height = exp(bbox_ymax) * prior_height;
decode_bbox_center_y = bbox.ymin() * prior_height + prior_center_y; decode_bbox.set_xmin(decode_bbox_center_x - decode_bbox_width * .5);
decode_bbox_width = exp(bbox.xmax()) * prior_width; decode_bbox.set_ymin(decode_bbox_center_y - decode_bbox_height * .5);
decode_bbox_height = exp(bbox.ymax()) * prior_height; decode_bbox.set_xmax(decode_bbox_center_x + decode_bbox_width * .5);
} else { decode_bbox.set_ymax(decode_bbox_center_y + decode_bbox_height * .5);
// variance is encoded in bbox, we need to scale the offset accordingly. break;
decode_bbox_center_x = }
prior_variance[0] * bbox.xmin() * prior_width + prior_center_x; default:
decode_bbox_center_y = CV_ErrorNoReturn(Error::StsBadArg, "Unknown type.");
prior_variance[1] * bbox.ymin() * prior_height + prior_center_y; };
decode_bbox_width = if (clip_bbox)
exp(prior_variance[2] * bbox.xmax()) * prior_width; {
decode_bbox_height = // Clip the caffe::NormalizedBBox such that the range for each corner is [0, 1]
exp(prior_variance[3] * bbox.ymax()) * prior_height; decode_bbox.set_xmin(std::max(std::min(decode_bbox.xmin(), 1.f), 0.f));
decode_bbox.set_ymin(std::max(std::min(decode_bbox.ymin(), 1.f), 0.f));
decode_bbox.set_xmax(std::max(std::min(decode_bbox.xmax(), 1.f), 0.f));
decode_bbox.set_ymax(std::max(std::min(decode_bbox.ymax(), 1.f), 0.f));
} }
decode_bbox.clear_size();
decode_bbox->set_xmin(decode_bbox_center_x - decode_bbox_width / 2.); decode_bbox.set_size(BBoxSize<true>(decode_bbox));
decode_bbox->set_ymin(decode_bbox_center_y - decode_bbox_height / 2.);
decode_bbox->set_xmax(decode_bbox_center_x + decode_bbox_width / 2.);
decode_bbox->set_ymax(decode_bbox_center_y + decode_bbox_height / 2.);
} else {
CV_Error(Error::StsBadArg, "Unknown LocLossType.");
}
float bbox_size = BBoxSize(*decode_bbox);
decode_bbox->set_size(bbox_size);
if (clip_bbox) {
ClipBBox(*decode_bbox, decode_bbox);
}
} }
// Decode a set of bboxes according to a set of prior bboxes. // Decode a set of bboxes according to a set of prior bboxes
void DecodeBBoxes( static void DecodeBBoxes(
const std::vector<caffe::NormalizedBBox>& prior_bboxes, const std::vector<caffe::NormalizedBBox>& prior_bboxes,
const std::vector<std::vector<float> >& prior_variances, const std::vector<std::vector<float> >& prior_variances,
const CodeType code_type, const bool variance_encoded_in_target, const CodeType code_type, const bool variance_encoded_in_target,
const bool clip_bbox, const std::vector<caffe::NormalizedBBox>& bboxes, const bool clip_bbox, const std::vector<caffe::NormalizedBBox>& bboxes,
std::vector<caffe::NormalizedBBox>* decode_bboxes) { std::vector<caffe::NormalizedBBox>& decode_bboxes)
CV_Assert(prior_bboxes.size() == prior_variances.size()); {
CV_Assert(prior_bboxes.size() == bboxes.size()); CV_Assert(prior_bboxes.size() == prior_variances.size());
int num_bboxes = prior_bboxes.size(); CV_Assert(prior_bboxes.size() == bboxes.size());
if (num_bboxes >= 1) { size_t num_bboxes = prior_bboxes.size();
CV_Assert(prior_variances[0].size() == 4); CV_Assert(num_bboxes == 0 || prior_variances[0].size() == 4);
} decode_bboxes.clear(); decode_bboxes.resize(num_bboxes);
decode_bboxes->clear(); if(variance_encoded_in_target)
for (int i = 0; i < num_bboxes; ++i) { {
caffe::NormalizedBBox decode_bbox; for (int i = 0; i < num_bboxes; ++i)
DecodeBBox(prior_bboxes[i], prior_variances[i], code_type, DecodeBBox<true>(prior_bboxes[i], prior_variances[i], code_type,
variance_encoded_in_target, clip_bbox, bboxes[i], &decode_bbox); clip_bbox, bboxes[i], decode_bboxes[i]);
decode_bboxes->push_back(decode_bbox); }
} else
{
for (int i = 0; i < num_bboxes; ++i)
DecodeBBox<false>(prior_bboxes[i], prior_variances[i], code_type,
clip_bbox, bboxes[i], decode_bboxes[i]);
}
} }
// Decode all bboxes in a batch. // Decode all bboxes in a batch
void DecodeBBoxesAll(const std::vector<LabelBBox>& all_loc_preds, static void DecodeBBoxesAll(const std::vector<LabelBBox>& all_loc_preds,
const std::vector<caffe::NormalizedBBox>& prior_bboxes, const std::vector<caffe::NormalizedBBox>& prior_bboxes,
const std::vector<std::vector<float> >& prior_variances, const std::vector<std::vector<float> >& prior_variances,
const int num, const bool share_location, const int num, const bool share_location,
const int num_loc_classes, const int background_label_id, const int num_loc_classes, const int background_label_id,
const CodeType code_type, const bool variance_encoded_in_target, const CodeType code_type, const bool variance_encoded_in_target,
const bool clip, std::vector<LabelBBox>* all_decode_bboxes) { const bool clip, std::vector<LabelBBox>& all_decode_bboxes)
CV_Assert(all_loc_preds.size() == num); {
all_decode_bboxes->clear(); CV_Assert(all_loc_preds.size() == num);
all_decode_bboxes->resize(num); all_decode_bboxes.clear();
for (int i = 0; i < num; ++i) { all_decode_bboxes.resize(num);
// Decode predictions into bboxes. for (int i = 0; i < num; ++i)
LabelBBox& decode_bboxes = (*all_decode_bboxes)[i]; {
for (int c = 0; c < num_loc_classes; ++c) { // Decode predictions into bboxes.
int label = share_location ? -1 : c; const LabelBBox& loc_preds = all_loc_preds[i];
if (label == background_label_id) { LabelBBox& decode_bboxes = all_decode_bboxes[i];
// Ignore background class. for (int c = 0; c < num_loc_classes; ++c)
continue; {
} int label = share_location ? -1 : c;
if (all_loc_preds[i].find(label) == all_loc_preds[i].end()) { if (label == background_label_id)
// Something bad happened if there are no predictions for current label. continue; // Ignore background class.
util::make_error<int>("Could not find location predictions for label ", label); LabelBBox::const_iterator label_loc_preds = loc_preds.find(label);
} if (label_loc_preds == loc_preds.end())
const std::vector<caffe::NormalizedBBox>& label_loc_preds = CV_ErrorNoReturn_(cv::Error::StsError, ("Could not find location predictions for label %d", label));
all_loc_preds[i].find(label)->second; DecodeBBoxes(prior_bboxes, prior_variances,
DecodeBBoxes(prior_bboxes, prior_variances, code_type, variance_encoded_in_target, clip,
code_type, variance_encoded_in_target, clip, label_loc_preds->second, decode_bboxes[label]);
label_loc_preds, &(decode_bboxes[label])); }
} }
}
} }
// Get prior bounding boxes from prior_data. // Get prior bounding boxes from prior_data
// prior_data: 1 x 2 x num_priors * 4 x 1 blob. // prior_data: 1 x 2 x num_priors * 4 x 1 blob.
// num_priors: number of priors. // num_priors: number of priors.
// prior_bboxes: stores all the prior bboxes in the format of caffe::NormalizedBBox. // prior_bboxes: stores all the prior bboxes in the format of caffe::NormalizedBBox.
// prior_variances: stores all the variances needed by prior bboxes. // prior_variances: stores all the variances needed by prior bboxes.
void GetPriorBBoxes(const float* priorData, const int& numPriors, static void GetPriorBBoxes(const float* priorData, const int& numPriors,
std::vector<caffe::NormalizedBBox>* priorBBoxes, std::vector<caffe::NormalizedBBox>& priorBBoxes,
std::vector<std::vector<float> >* priorVariances) std::vector<std::vector<float> >& priorVariances)
{ {
priorBBoxes->clear(); priorBBoxes.clear(); priorBBoxes.resize(numPriors);
priorVariances->clear(); priorVariances.clear(); priorVariances.resize(numPriors);
for (int i = 0; i < numPriors; ++i) for (int i = 0; i < numPriors; ++i)
{ {
int startIdx = i * 4; int startIdx = i * 4;
caffe::NormalizedBBox bbox; caffe::NormalizedBBox& bbox = priorBBoxes[i];
bbox.set_xmin(priorData[startIdx]); bbox.set_xmin(priorData[startIdx]);
bbox.set_ymin(priorData[startIdx + 1]); bbox.set_ymin(priorData[startIdx + 1]);
bbox.set_xmax(priorData[startIdx + 2]); bbox.set_xmax(priorData[startIdx + 2]);
bbox.set_ymax(priorData[startIdx + 3]); bbox.set_ymax(priorData[startIdx + 3]);
float bboxSize = BBoxSize(bbox); bbox.set_size(BBoxSize<true>(bbox));
bbox.set_size(bboxSize);
priorBBoxes->push_back(bbox);
} }
for (int i = 0; i < numPriors; ++i) for (int i = 0; i < numPriors; ++i)
{ {
int startIdx = (numPriors + i) * 4; int startIdx = (numPriors + i) * 4;
std::vector<float> var; // not needed here: priorVariances[i].clear();
for (int j = 0; j < 4; ++j) for (int j = 0; j < 4; ++j)
{ {
var.push_back(priorData[startIdx + j]); priorVariances[i].push_back(priorData[startIdx + j]);
} }
priorVariances->push_back(var);
} }
} }
// Scale the caffe::NormalizedBBox w.r.t. height and width.
void ScaleBBox(const caffe::NormalizedBBox& bbox,
const int height, const int width,
caffe::NormalizedBBox* scaleBBox)
{
scaleBBox->set_xmin(bbox.xmin() * width);
scaleBBox->set_ymin(bbox.ymin() * height);
scaleBBox->set_xmax(bbox.xmax() * width);
scaleBBox->set_ymax(bbox.ymax() * height);
scaleBBox->clear_size();
bool normalized = !(width > 1 || height > 1);
scaleBBox->set_size(BBoxSize(*scaleBBox, normalized));
scaleBBox->set_difficult(bbox.difficult());
}
// Get location predictions from loc_data. // Get location predictions from loc_data.
// loc_data: num x num_preds_per_class * num_loc_classes * 4 blob. // loc_data: num x num_preds_per_class * num_loc_classes * 4 blob.
// num: the number of images. // num: the number of images.
@@ -603,19 +542,19 @@ public:
// share_location: if true, all classes share the same location prediction. // share_location: if true, all classes share the same location prediction.
// loc_preds: stores the location prediction, where each item contains // loc_preds: stores the location prediction, where each item contains
// location prediction for an image. // location prediction for an image.
void GetLocPredictions(const float* locData, const int num, static void GetLocPredictions(const float* locData, const int num,
const int numPredsPerClass, const int numLocClasses, const int numPredsPerClass, const int numLocClasses,
const bool shareLocation, std::vector<LabelBBox>* locPreds) const bool shareLocation, std::vector<LabelBBox>& locPreds)
{ {
locPreds->clear(); locPreds.clear();
if (shareLocation) if (shareLocation)
{ {
CV_Assert(numLocClasses == 1); CV_Assert(numLocClasses == 1);
} }
locPreds->resize(num); locPreds.resize(num);
for (int i = 0; i < num; ++i) for (int i = 0; i < num; ++i, locData += numPredsPerClass * numLocClasses * 4)
{ {
LabelBBox& labelBBox = (*locPreds)[i]; LabelBBox& labelBBox = locPreds[i];
for (int p = 0; p < numPredsPerClass; ++p) for (int p = 0; p < numPredsPerClass; ++p)
{ {
int startIdx = p * numLocClasses * 4; int startIdx = p * numLocClasses * 4;
@@ -626,13 +565,13 @@ public:
{ {
labelBBox[label].resize(numPredsPerClass); labelBBox[label].resize(numPredsPerClass);
} }
labelBBox[label][p].set_xmin(locData[startIdx + c * 4]); caffe::NormalizedBBox& bbox = labelBBox[label][p];
labelBBox[label][p].set_ymin(locData[startIdx + c * 4 + 1]); bbox.set_xmin(locData[startIdx + c * 4]);
labelBBox[label][p].set_xmax(locData[startIdx + c * 4 + 2]); bbox.set_ymin(locData[startIdx + c * 4 + 1]);
labelBBox[label][p].set_ymax(locData[startIdx + c * 4 + 3]); bbox.set_xmax(locData[startIdx + c * 4 + 2]);
bbox.set_ymax(locData[startIdx + c * 4 + 3]);
} }
} }
locData += numPredsPerClass * numLocClasses * 4;
} }
} }
@@ -643,25 +582,24 @@ public:
// num_classes: number of classes. // num_classes: number of classes.
// conf_preds: stores the confidence prediction, where each item contains // conf_preds: stores the confidence prediction, where each item contains
// confidence prediction for an image. // confidence prediction for an image.
void GetConfidenceScores(const float* confData, const int num, static void GetConfidenceScores(const float* confData, const int num,
const int numPredsPerClass, const int numClasses, const int numPredsPerClass, const int numClasses,
std::vector<std::vector<std::vector<float> > >* confPreds) std::vector<std::vector<std::vector<float> > >& confPreds)
{ {
confPreds->clear(); confPreds.clear(); confPreds.resize(num);
confPreds->resize(num); for (int i = 0; i < num; ++i, confData += numPredsPerClass * numClasses)
for (int i = 0; i < num; ++i)
{ {
std::vector<std::vector<float> >& labelScores = (*confPreds)[i]; std::vector<std::vector<float> >& labelScores = confPreds[i];
labelScores.resize(numClasses); labelScores.resize(numClasses);
for (int p = 0; p < numPredsPerClass; ++p) for (int c = 0; c < numClasses; ++c)
{ {
int startIdx = p * numClasses; std::vector<float>& classLabelScores = labelScores[c];
for (int c = 0; c < numClasses; ++c) classLabelScores.resize(numPredsPerClass);
for (int p = 0; p < numPredsPerClass; ++p)
{ {
labelScores[c].push_back(confData[startIdx + c]); classLabelScores[p] = confData[p * numClasses + c];
} }
} }
confData += numPredsPerClass * numClasses;
} }
} }
@@ -674,40 +612,35 @@ public:
// nms_threshold: a threshold used in non maximum suppression. // nms_threshold: a threshold used in non maximum suppression.
// top_k: if not -1, keep at most top_k picked indices. // top_k: if not -1, keep at most top_k picked indices.
// indices: the kept indices of bboxes after nms. // indices: the kept indices of bboxes after nms.
void ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes, static void ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes,
const std::vector<float>& scores, const float score_threshold, const std::vector<float>& scores, const float score_threshold,
const float nms_threshold, const float eta, const int top_k, const float nms_threshold, const float eta, const int top_k,
std::vector<int>* indices) { std::vector<int>& indices)
// Sanity check. {
CV_Assert(bboxes.size() == scores.size()); CV_Assert(bboxes.size() == scores.size());
// Get top_k scores (with corresponding indices). // Get top_k scores (with corresponding indices).
std::vector<std::pair<float, int> > score_index_vec; std::vector<std::pair<float, int> > score_index_vec;
GetMaxScoreIndex(scores, score_threshold, top_k, &score_index_vec); GetMaxScoreIndex(scores, score_threshold, top_k, score_index_vec);
// Do nms. // Do nms.
float adaptive_threshold = nms_threshold; float adaptive_threshold = nms_threshold;
indices->clear(); indices.clear();
while (score_index_vec.size() != 0) { while (score_index_vec.size() != 0) {
const int idx = score_index_vec.front().second; const int idx = score_index_vec.front().second;
bool keep = true; bool keep = true;
for (int k = 0; k < indices->size(); ++k) { for (int k = 0; k < (int)indices.size() && keep; ++k) {
if (keep) { const int kept_idx = indices[k];
const int kept_idx = (*indices)[k]; float overlap = JaccardOverlap<true>(bboxes[idx], bboxes[kept_idx]);
float overlap = JaccardOverlap(bboxes[idx], bboxes[kept_idx]); keep = overlap <= adaptive_threshold;
keep = overlap <= adaptive_threshold; }
} else { if (keep)
break; indices.push_back(idx);
} score_index_vec.erase(score_index_vec.begin());
if (keep && eta < 1 && adaptive_threshold > 0.5) {
adaptive_threshold *= eta;
}
} }
if (keep) {
indices->push_back(idx);
}
score_index_vec.erase(score_index_vec.begin());
if (keep && eta < 1 && adaptive_threshold > 0.5) {
adaptive_threshold *= eta;
}
}
} }
// Get max scores with corresponding indices. // Get max scores with corresponding indices.
@@ -715,74 +648,66 @@ public:
// threshold: only consider scores higher than the threshold. // threshold: only consider scores higher than the threshold.
// top_k: if -1, keep all; otherwise, keep at most top_k. // top_k: if -1, keep all; otherwise, keep at most top_k.
// score_index_vec: store the sorted (score, index) pair. // score_index_vec: store the sorted (score, index) pair.
void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold,const int top_k, static void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold, const int top_k,
std::vector<std::pair<float, int> >* score_index_vec) std::vector<std::pair<float, int> >& score_index_vec)
{ {
CV_DbgAssert(score_index_vec.empty());
// Generate index score pairs. // Generate index score pairs.
for (size_t i = 0; i < scores.size(); ++i) for (size_t i = 0; i < scores.size(); ++i)
{ {
if (scores[i] > threshold) if (scores[i] > threshold)
{ {
score_index_vec->push_back(std::make_pair(scores[i], i)); score_index_vec.push_back(std::make_pair(scores[i], i));
} }
} }
// Sort the score pair according to the scores in descending order // Sort the score pair according to the scores in descending order
std::stable_sort(score_index_vec->begin(), score_index_vec->end(), std::stable_sort(score_index_vec.begin(), score_index_vec.end(),
util::SortScorePairDescend<int>); util::SortScorePairDescend<int>);
// Keep top_k scores if needed. // Keep top_k scores if needed.
if (top_k > -1 && top_k < (int)score_index_vec->size()) if (top_k > -1 && top_k < (int)score_index_vec.size())
{ {
score_index_vec->resize(top_k); score_index_vec.resize(top_k);
}
}
// Compute the intersection between two bboxes.
void IntersectBBox(const caffe::NormalizedBBox& bbox1,
const caffe::NormalizedBBox& bbox2,
caffe::NormalizedBBox* intersect_bbox) {
if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin())
{
// Return [0, 0, 0, 0] if there is no intersection.
intersect_bbox->set_xmin(0);
intersect_bbox->set_ymin(0);
intersect_bbox->set_xmax(0);
intersect_bbox->set_ymax(0);
}
else
{
intersect_bbox->set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
intersect_bbox->set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
intersect_bbox->set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
intersect_bbox->set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
} }
} }
// Compute the jaccard (intersection over union IoU) overlap between two bboxes. // Compute the jaccard (intersection over union IoU) overlap between two bboxes.
float JaccardOverlap(const caffe::NormalizedBBox& bbox1, template<bool normalized>
const caffe::NormalizedBBox& bbox2, static float JaccardOverlap(const caffe::NormalizedBBox& bbox1,
const bool normalized=true) const caffe::NormalizedBBox& bbox2)
{ {
caffe::NormalizedBBox intersect_bbox; caffe::NormalizedBBox intersect_bbox;
IntersectBBox(bbox1, bbox2, &intersect_bbox); if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
float intersect_width, intersect_height; bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin())
if (normalized)
{ {
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin(); // Return [0, 0, 0, 0] if there is no intersection.
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin(); intersect_bbox.set_xmin(0);
intersect_bbox.set_ymin(0);
intersect_bbox.set_xmax(0);
intersect_bbox.set_ymax(0);
} }
else else
{ {
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin() + 1; intersect_bbox.set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin() + 1; intersect_bbox.set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
intersect_bbox.set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
intersect_bbox.set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
} }
float intersect_width, intersect_height;
intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin();
intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin();
if (intersect_width > 0 && intersect_height > 0) if (intersect_width > 0 && intersect_height > 0)
{ {
if (!normalized)
{
intersect_width++;
intersect_height++;
}
float intersect_size = intersect_width * intersect_height; float intersect_size = intersect_width * intersect_height;
float bbox1_size = BBoxSize(bbox1); float bbox1_size = BBoxSize<true>(bbox1);
float bbox2_size = BBoxSize(bbox2); float bbox2_size = BBoxSize<true>(bbox2);
return intersect_size / (bbox1_size + bbox2_size - intersect_size); return intersect_size / (bbox1_size + bbox2_size - intersect_size);
} }
else else
@@ -119,7 +119,7 @@ public:
class FullyConnected : public ParallelLoopBody class FullyConnected : public ParallelLoopBody
{ {
public: public:
FullyConnected() : srcMat(0), weights(0), biasMat(0), activ(0), dstMat(0), nstripes(0), useAVX2(false) {} FullyConnected() : srcMat(0), weights(0), biasMat(0), activ(0), dstMat(0), nstripes(0), useAVX(false), useAVX2(false) {}
static void run(const Mat& srcMat, const Mat& weights, const Mat& biasMat, static void run(const Mat& srcMat, const Mat& weights, const Mat& biasMat,
Mat& dstMat, const ActivationLayer* activ, int nstripes) Mat& dstMat, const ActivationLayer* activ, int nstripes)
@@ -139,6 +139,7 @@ public:
p.dstMat = &dstMat; p.dstMat = &dstMat;
p.nstripes = nstripes; p.nstripes = nstripes;
p.activ = activ; p.activ = activ;
p.useAVX = checkHardwareSupport(CPU_AVX);
p.useAVX2 = checkHardwareSupport(CPU_AVX2); p.useAVX2 = checkHardwareSupport(CPU_AVX2);
parallel_for_(Range(0, nstripes), p, nstripes); parallel_for_(Range(0, nstripes), p, nstripes);
@@ -176,7 +177,12 @@ public:
#if CV_TRY_AVX2 #if CV_TRY_AVX2
if( useAVX2 ) if( useAVX2 )
fastGEMM1T_avx2( sptr, wptr, wstep, biasptr, dptr, nw, vecsize); opt_AVX2::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
else
#endif
#if CV_TRY_AVX
if( useAVX )
opt_AVX::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
else else
#endif #endif
{ {
@@ -185,19 +191,19 @@ public:
#if CV_SIMD128 #if CV_SIMD128
for( ; i <= nw - 4; i += 4, wptr += 4*wstep ) for( ; i <= nw - 4; i += 4, wptr += 4*wstep )
{ {
vfloat32x4 vs0 = v_setall_f32(0.f), vs1 = v_setall_f32(0.f); v_float32x4 vs0 = v_setall_f32(0.f), vs1 = v_setall_f32(0.f);
vfloat32x4 vs2 = v_setall_f32(0.f), vs3 = v_setall_f32(0.f); v_float32x4 vs2 = v_setall_f32(0.f), vs3 = v_setall_f32(0.f);
for( k = 0; k < vecsize; k += 4 ) for( k = 0; k < vecsize; k += 4 )
{ {
vfloat32x4 v = v_load_aligned(sptr + k); v_float32x4 v = v_load_aligned(sptr + k);
vs0 += v*v_load_aligned(wptr + k); vs0 += v*v_load_aligned(wptr + k);
vs1 += v*v_load_aligned(wptr + wstep + k); vs1 += v*v_load_aligned(wptr + wstep + k);
vs2 += v*v_load_aligned(wptr + wstep*2 + k); vs2 += v*v_load_aligned(wptr + wstep*2 + k);
vs3 += v*v_load_aligned(wptr + wstep*3 + k); vs3 += v*v_load_aligned(wptr + wstep*3 + k);
} }
vfloat32x4 s = v_reduce_sum4(vs0, vs1, vs2, vs3); v_float32x4 s = v_reduce_sum4(vs0, vs1, vs2, vs3);
s += v_load(biasptr + i); s += v_load(biasptr + i);
v_store(dptr + i, s); v_store(dptr + i, s);
} }
@@ -228,6 +234,7 @@ public:
const ActivationLayer* activ; const ActivationLayer* activ;
Mat* dstMat; Mat* dstMat;
int nstripes; int nstripes;
bool useAVX;
bool useAVX2; bool useAVX2;
}; };
+4 -13
View File
@@ -45,6 +45,10 @@
#include <opencv2/dnn.hpp> #include <opencv2/dnn.hpp>
#include <opencv2/dnn/shape_utils.hpp> #include <opencv2/dnn/shape_utils.hpp>
// dispatched AVX/AVX2 optimizations
#include "layers/layers_common.simd.hpp"
#include "layers/layers_common.simd_declarations.hpp"
namespace cv namespace cv
{ {
namespace dnn namespace dnn
@@ -64,19 +68,6 @@ void getConvPoolPaddings(const Size& inp, const Size& out,
const Size &kernel, const Size &stride, const Size &kernel, const Size &stride,
const String &padMode, Size &pad); const String &padMode, Size &pad);
#if CV_TRY_AVX2
void fastConv_avx2(const float* weights, size_t wstep, const float* bias,
const float* rowbuf, float* output, const int* outShape,
int blockSize, int vecsize, int vecsize_aligned,
const float* relu, bool initOutput);
void fastGEMM1T_avx2( const float* vec, const float* weights,
size_t wstep, const float* bias,
float* dst, int nvecs, int vecsize );
void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr0,
size_t bstep, float* cptr, size_t cstep,
int ma, int na, int nb );
#endif
} }
} }
@@ -40,17 +40,34 @@
// //
//M*/ //M*/
#include "precomp.hpp"
#include "layers_common.hpp"
#include "opencv2/core/hal/intrin.hpp" #include "opencv2/core/hal/intrin.hpp"
namespace cv { namespace cv {
namespace dnn { namespace dnn {
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
void fastConv_avx2( const float* weights, size_t wstep, const float* bias, void fastConv( const float* weights, size_t wstep, const float* bias,
const float* rowbuf, float* output, const int* outShape, const float* rowbuf, float* output, const int* outShape,
int blockSize, int vecsize, int vecsize_aligned, int blockSize, int vecsize, int vecsize_aligned,
const float* relu, bool initOutput ) const float* relu, bool initOutput );
void fastGEMM1T( const float* vec, const float* weights,
size_t wstep, const float* bias,
float* dst, int nvecs, int vecsize );
void fastGEMM( const float* aptr, size_t astep, const float* bptr,
size_t bstep, float* cptr, size_t cstep,
int ma, int na, int nb );
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_AVX
#if !CV_FMA // AVX workaround
#undef _mm256_fmadd_ps
#define _mm256_fmadd_ps(a, b, c) _mm256_add_ps(c, _mm256_mul_ps(a, b))
#endif
void fastConv( const float* weights, size_t wstep, const float* bias,
const float* rowbuf, float* output, const int* outShape,
int blockSize, int vecsize, int vecsize_aligned,
const float* relu, bool initOutput )
{ {
int outCn = outShape[1]; int outCn = outShape[1];
size_t outPlaneSize = outShape[2]*outShape[3]; size_t outPlaneSize = outShape[2]*outShape[3];
@@ -215,9 +232,9 @@ void fastConv_avx2( const float* weights, size_t wstep, const float* bias,
} }
// dst = vec * weights^t + bias // dst = vec * weights^t + bias
void fastGEMM1T_avx2( const float* vec, const float* weights, void fastGEMM1T( const float* vec, const float* weights,
size_t wstep, const float* bias, size_t wstep, const float* bias,
float* dst, int nvecs, int vecsize ) float* dst, int nvecs, int vecsize )
{ {
int i = 0; int i = 0;
@@ -277,9 +294,9 @@ void fastGEMM1T_avx2( const float* vec, const float* weights,
_mm256_zeroupper(); _mm256_zeroupper();
} }
void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr, void fastGEMM( const float* aptr, size_t astep, const float* bptr,
size_t bstep, float* cptr, size_t cstep, size_t bstep, float* cptr, size_t cstep,
int ma, int na, int nb ) int ma, int na, int nb )
{ {
int n = 0; int n = 0;
for( ; n <= nb - 16; n += 16 ) for( ; n <= nb - 16; n += 16 )
@@ -347,5 +364,7 @@ void fastGEMM_avx2( const float* aptr, size_t astep, const float* bptr,
_mm256_zeroupper(); _mm256_zeroupper();
} }
} #endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
}
CV_CPU_OPTIMIZATION_NAMESPACE_END
}} // namespace
+19 -6
View File
@@ -11,14 +11,18 @@ else:
ignored_arg_types = ["RNG*"] ignored_arg_types = ["RNG*"]
gen_template_check_self = Template(""" if(!PyObject_TypeCheck(self, &pyopencv_${name}_Type)) gen_template_check_self = Template(""" $cname* _self_ = NULL;
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
_self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
if (_self_ == NULL)
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)"); return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
$cname* _self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
""") """)
gen_template_check_self_algo = Template(""" if(!PyObject_TypeCheck(self, &pyopencv_${name}_Type)) gen_template_check_self_algo = Template(""" $cname* _self_ = NULL;
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
_self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
if (_self_ == NULL)
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)"); return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
$cname* _self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
""") """)
gen_template_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type); gen_template_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
@@ -200,7 +204,10 @@ static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *clo
gen_template_get_prop_algo = Template(""" gen_template_get_prop_algo = Template("""
static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure) static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
{ {
return pyopencv_from(dynamic_cast<$cname*>(p->v.get())${access}${member}); $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
if (_self_ == NULL)
return failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
return pyopencv_from(_self_${access}${member});
} }
""") """)
@@ -224,7 +231,13 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
return -1; return -1;
} }
return pyopencv_to(value, dynamic_cast<$cname*>(p->v.get())${access}${member}) ? 0 : -1; $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
if (_self_ == NULL)
{
failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
return -1;
}
return pyopencv_to(value, _self_${access}${member}) ? 0 : -1;
} }
""") """)