Skip to content

Commit 9b73fee

Browse files
committed
Made separate functions for computing output shapes for all layers. Removed output blobs allocation from layers
1 parent 27bf9e2 commit 9b73fee

37 files changed

+1102
-897
lines changed

modules/dnn/include/opencv2/dnn/all_layers.hpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -121,21 +121,7 @@ namespace dnn
121121
* @details If this parameter is empty or unset then @p outTailShape = [`Wh`.size(0)] will be used,
122122
* where `Wh` is parameter from setWeights().
123123
*/
124-
virtual void setOutShape(const std::vector<int> &outTailShape = std::vector<int>()) = 0;
125-
126-
/** @brief Set @f$ h_{t-1} @f$ value that will be used in next forward() calls.
127-
* @details By-default @f$ h_{t-1} @f$ is inited by zeros and updated after each forward() call.
128-
*/
129-
virtual void setH(const Mat &H) = 0;
130-
/** @brief Returns current @f$ h_{t-1} @f$ value (deep copy). */
131-
virtual Mat getH() const = 0;
132-
133-
/** @brief Set @f$ c_{t-1} @f$ value that will be used in next forward() calls.
134-
* @details By-default @f$ c_{t-1} @f$ is inited by zeros and updated after each forward() call.
135-
*/
136-
virtual void setC(const Mat &C) = 0;
137-
/** @brief Returns current @f$ c_{t-1} @f$ value (deep copy). */
138-
virtual Mat getC() const = 0;
124+
virtual void setOutShape(const MatShape &outTailShape = MatShape()) = 0;
139125

140126
/** @brief Specifies either interpet first dimension of input blob as timestamp dimenion either as sample.
141127
*
@@ -289,7 +275,7 @@ namespace dnn
289275
class CV_EXPORTS ReshapeLayer : public Layer
290276
{
291277
public:
292-
std::vector<int> newShapeDesc;
278+
MatShape newShapeDesc;
293279
Range newShapeRange;
294280

295281
static Ptr<ReshapeLayer> create(const LayerParams& params);

modules/dnn/include/opencv2/dnn/dnn.hpp

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
5353
//! @addtogroup dnn
5454
//! @{
5555

56+
typedef std::vector<int> MatShape;
57+
5658
/** @brief Initialize dnn module and built-in layers.
5759
*
5860
* This function automatically called on most of OpenCV builds,
@@ -87,33 +89,35 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
8789
//! List of learned parameters must be stored here to allow read them by using Net::getParam().
8890
CV_PROP_RW std::vector<Mat> blobs;
8991

90-
/** @brief Allocates internal buffers and output blobs with respect to the shape of inputs.
92+
/** @brief Computes and sets internal parameters according to inputs, outputs and blobs.
9193
* @param[in] input vector of already allocated input blobs
92-
* @param[out] output vector of output blobs, which must be allocated
94+
* @param[out] output vector of already allocated output blobs
9395
*
94-
* This method must create each produced blob according to shape of @p input blobs and internal layer params.
95-
* If this method is called first time then @p output vector consists from empty blobs and its size determined by number of output connections.
96-
* This method can be called multiple times if size of any @p input blob was changed.
96+
* If this method is called after network has allocated all memory for input and output blobs
97+
* and before inferencing.
9798
*/
98-
virtual void allocate(const std::vector<Mat*> &input, std::vector<Mat> &output) = 0;
99+
virtual void finalize(const std::vector<Mat*> &input, std::vector<Mat> &output);
99100

100101
/** @brief Given the @p input blobs, computes the output @p blobs.
101102
* @param[in] input the input blobs.
102103
* @param[out] output allocated output blobs, which will store results of the computation.
104+
* @param[out] internals allocated internal blobs
103105
*/
104-
virtual void forward(std::vector<Mat*> &input, std::vector<Mat> &output) = 0;
106+
virtual void forward(std::vector<Mat*> &input, std::vector<Mat> &output, std::vector<Mat> &internals) = 0;
105107

106108
/** @brief @overload */
107-
CV_WRAP void allocate(const std::vector<Mat> &inputs, CV_OUT std::vector<Mat> &outputs);
109+
CV_WRAP void finalize(const std::vector<Mat> &inputs, CV_OUT std::vector<Mat> &outputs);
108110

109111
/** @brief @overload */
110-
CV_WRAP std::vector<Mat> allocate(const std::vector<Mat> &inputs);
112+
CV_WRAP std::vector<Mat> finalize(const std::vector<Mat> &inputs);
111113

112114
/** @brief @overload */
113-
CV_WRAP void forward(const std::vector<Mat> &inputs, CV_IN_OUT std::vector<Mat> &outputs);
115+
CV_WRAP void forward(const std::vector<Mat> &inputs, CV_IN_OUT std::vector<Mat> &outputs,
116+
CV_IN_OUT std::vector<Mat> &internals);
114117

115118
/** @brief Allocates layer and computes output. */
116-
CV_WRAP void run(const std::vector<Mat> &inputs, CV_OUT std::vector<Mat> &outputs);
119+
CV_WRAP void run(const std::vector<Mat> &inputs, CV_OUT std::vector<Mat> &outputs,
120+
CV_IN_OUT std::vector<Mat> &internals);
117121

118122
/** @brief Returns index of input blob into the input array.
119123
* @param inputName label of input blob
@@ -127,6 +131,11 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
127131
*/
128132
virtual int outputNameToIndex(String outputName);
129133

134+
virtual bool getMemoryShapes(const std::vector<MatShape> &inputs,
135+
const int requiredOutputs,
136+
std::vector<MatShape> &outputs,
137+
std::vector<MatShape> &internals) const;
138+
130139
CV_PROP String name; //!< Name of the layer instance, can be used for logging or other internal purposes.
131140
CV_PROP String type; //!< Type name which was used for creating layer by layer factory.
132141

@@ -275,6 +284,45 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
275284
/** @brief Returns indexes of layers with unconnected outputs.
276285
*/
277286
CV_WRAP std::vector<int> getUnconnectedOutLayers() const;
287+
/** @brief Returns input and output shapes for all layers in loaded model;
288+
* preliminary inferencing isn't necessary.
289+
* @param netInputShapes shapes for all input blobs in net input layer.
290+
* @param layersIds output parameter for layer IDs.
291+
* @param inLayersShapes output parameter for input layers shapes;
292+
* order is the same as in layersIds
293+
* @param outLayersShapes output parameter for output layers shapes;
294+
* order is the same as in layersIds
295+
*/
296+
CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
297+
std::vector<int>* layersIds,
298+
std::vector<std::vector<MatShape> >* inLayersShapes,
299+
std::vector<std::vector<MatShape> >* outLayersShapes) const;
300+
301+
/** @overload */
302+
CV_WRAP void getLayersShapes(const MatShape& netInputShape,
303+
std::vector<int>* layersIds,
304+
std::vector<std::vector<MatShape> >* inLayersShapes,
305+
std::vector<std::vector<MatShape> >* outLayersShapes) const;
306+
307+
/** @brief Returns input and output shapes for layer with specified
308+
* id in loaded model; preliminary inferencing isn't necessary.
309+
* @param netInputShape shape input blob in net input layer.
310+
* @param layerId id for layer.
311+
* @param inLayerShapes output parameter for input layers shapes;
312+
* order is the same as in layersIds
313+
* @param outLayerShapes output parameter for output layers shapes;
314+
* order is the same as in layersIds
315+
*/
316+
CV_WRAP void getLayerShapes(const MatShape& netInputShape,
317+
const int layerId,
318+
std::vector<MatShape>* inLayerShapes,
319+
std::vector<MatShape>* outLayerShapes) const;
320+
321+
/** @overload */
322+
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes,
323+
const int layerId,
324+
std::vector<MatShape>* inLayerShapes,
325+
std::vector<MatShape>* outLayerShapes) const;
278326
private:
279327

280328
struct Impl;

modules/dnn/include/opencv2/dnn/shape_utils.hpp

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,6 @@ inline std::ostream &operator<< (std::ostream &s, cv::Range &r)
5555
return s << "[" << r.start << ", " << r.end << ")";
5656
}
5757

58-
//Reshaping
59-
//TODO: add -1 specifier for automatic size inferring
60-
61-
/*template<typename Mat>
62-
void reshape(Mat &m, const BlobShape &shape)
63-
{
64-
m = m.reshape(1, shape.dims(), shape.ptr());
65-
}
66-
67-
template<typename Mat>
68-
Mat reshaped(const Mat &m, const BlobShape &shape)
69-
{
70-
return m.reshape(1, shape.dims(), shape.ptr());
71-
}*/
72-
73-
7458
//Slicing
7559

7660
struct _Range : public cv::Range
@@ -139,12 +123,76 @@ static inline Mat getPlane(const Mat &m, int n, int cn)
139123
return m(range).reshape(1, m.dims-2, sz);
140124
}
141125

142-
static inline size_t shapeTotal(const std::vector<int>& shape)
126+
static inline MatShape shape(const int* dims, const int n = 4)
127+
{
128+
MatShape shape;
129+
shape.assign(dims, dims + n);
130+
return shape;
131+
}
132+
133+
static inline MatShape shape(const MatSize& size)
134+
{
135+
return shape((const int*)size, size.dims());
136+
}
137+
138+
static inline MatShape shape(const Mat& mat)
139+
{
140+
return shape(mat.size);
141+
}
142+
143+
namespace {inline bool is_neg(int i) { return i < 0; }}
144+
145+
static inline MatShape shape(int a0, int a1=-1, int a2=-1, int a3=-1)
146+
{
147+
int dims[] = {a0, a1, a2, a3};
148+
MatShape s = shape(dims);
149+
s.erase(std::remove_if(s.begin(), s.end(), is_neg), s.end());
150+
return s;
151+
}
152+
153+
static inline int total(const MatShape& shape, int start = -1, int end = -1)
154+
{
155+
if (start == -1) start = 0;
156+
if (end == -1) end = shape.size();
157+
158+
if (shape.empty())
159+
return 0;
160+
161+
int elems = 1;
162+
CV_Assert(start < shape.size() && end <= shape.size() &&
163+
start <= end);
164+
for(int i = start; i < end; i++)
165+
{
166+
elems *= shape[i];
167+
}
168+
return elems;
169+
}
170+
171+
static inline MatShape concat(const MatShape& a, const MatShape& b)
143172
{
144-
size_t i, n = shape.size(), p = 1;
145-
for( i = 0; i < n; i++ ) p *= shape[i];
173+
MatShape c = a;
174+
c.insert(c.end(), b.begin(), b.end());
146175

147-
return p;
176+
return c;
177+
}
178+
179+
inline void print(const MatShape& shape, const String& name = "")
180+
{
181+
printf("%s: [", name.c_str());
182+
size_t i, n = shape.size();
183+
for( i = 0; i < n; i++ )
184+
printf(" %d", shape[i]);
185+
printf(" ]\n");
186+
}
187+
188+
inline int clamp(int ax, int dims)
189+
{
190+
return ax < 0 ? ax + dims : ax;
191+
}
192+
193+
inline int clamp(int ax, const MatShape& shape)
194+
{
195+
return clamp(ax, shape.size());
148196
}
149197

150198
}

modules/dnn/misc/python/pyopencv_dnn.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#ifdef HAVE_OPENCV_DNN
22
typedef dnn::DictValue LayerId;
3+
typedef std::vector<dnn::MatShape> vector_MatShape;
4+
typedef std::vector<std::vector<dnn::MatShape> > vector_vector_MatShape;
35

46
template<>
57
bool pyopencv_to(PyObject *o, dnn::DictValue &dv, const char *name)

modules/dnn/perf/perf_convolution.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "perf_precomp.hpp"
2+
#include <opencv2/dnn/shape_utils.hpp>
23

34
namespace cvtest
45
{
@@ -21,14 +22,14 @@ CV_ENUM(GroupSize, GROUP_OFF, GROUP_2);
2122
//Squared Size
2223
#define SSZ(n) cv::Size(n, n)
2324

24-
typedef std::pair<std::vector<int>, int> InpShapeNumOut;
25+
typedef std::pair<MatShape, int> InpShapeNumOut;
2526
typedef tuple<Size, InpShapeNumOut, GroupSize, StrideSize> ConvParam; //kernel_size, inp shape, groups, stride
2627
typedef TestBaseWithParam<ConvParam> ConvolutionPerfTest;
2728

28-
static inline std::vector<int> blobShape(int count, int nplanes, int height, int width)
29+
static inline MatShape blobShape(int count, int nplanes, int height, int width)
2930
{
3031
int data[] = {count, nplanes, height, width};
31-
return std::vector<int>(data, data+4);
32+
return MatShape(data, data+4);
3233
}
3334

3435
PERF_TEST_P( ConvolutionPerfTest, perf, Combine(
@@ -44,7 +45,7 @@ PERF_TEST_P( ConvolutionPerfTest, perf, Combine(
4445

4546
ConvParam params = GetParam();
4647
int ksz = get<0>(params).width;
47-
std::vector<int> inpShape = get<1>(params).first;
48+
MatShape inpShape = get<1>(params).first;
4849
int outCn = get<1>(params).second;
4950
int groups = get<2>(params);
5051
int stride = (ksz >= 11) ? 4 : (int)get<3>(params);
@@ -69,12 +70,25 @@ PERF_TEST_P( ConvolutionPerfTest, perf, Combine(
6970
lp.blobs.push_back(biasBlob);
7071

7172
std::vector<Mat*> inpBlobs(1, &inpBlob);
72-
std::vector<Mat> outBlobs;
73+
std::vector<Mat> outBlobs, internalBlobs;
7374

7475
cv::setNumThreads(cv::getNumberOfCPUs());
7576

7677
Ptr<Layer> layer = cv::dnn::LayerFactory::createLayerInstance("Convolution", lp);
77-
layer->allocate(inpBlobs, outBlobs);
78+
std::vector<MatShape> inputShapes(1, shape(inpBlob)), outShapes, internals;
79+
layer->getMemoryShapes(inputShapes, 0, outShapes, internals);
80+
for (int i = 0; i < outShapes.size(); i++)
81+
{
82+
outBlobs.push_back(Mat(outShapes[i], CV_32F));
83+
}
84+
for (int i = 0; i < internals.size(); i++)
85+
{
86+
internalBlobs.push_back(Mat());
87+
if (total(internals[i]))
88+
internalBlobs.back().create(internals[i], CV_32F);
89+
}
90+
91+
layer->finalize(inpBlobs, outBlobs);
7892

7993
Mat inpBlob2D = inpBlob.reshape(1, outCn);
8094
Mat wgtBlob2D = wgtBlob.reshape(1, outCn*(inpCn/groups));
@@ -83,7 +97,7 @@ PERF_TEST_P( ConvolutionPerfTest, perf, Combine(
8397

8498
TEST_CYCLE_N(10)
8599
{
86-
layer->forward(inpBlobs, outBlobs);
100+
layer->forward(inpBlobs, outBlobs, internalBlobs);
87101
}
88102

89103
SANITY_CHECK_NOTHING();

modules/dnn/src/caffe/caffe_importer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class CaffeImporter : public Importer
192192
}
193193
}
194194

195-
void blobShapeFromProto(const caffe::BlobProto &pbBlob, std::vector<int>& shape)
195+
void blobShapeFromProto(const caffe::BlobProto &pbBlob, MatShape& shape)
196196
{
197197
shape.clear();
198198
if (pbBlob.has_num() || pbBlob.has_channels() || pbBlob.has_height() || pbBlob.has_width())
@@ -215,7 +215,7 @@ class CaffeImporter : public Importer
215215

216216
void blobFromProto(const caffe::BlobProto &pbBlob, cv::Mat &dstBlob)
217217
{
218-
std::vector<int> shape;
218+
MatShape shape;
219219
blobShapeFromProto(pbBlob, shape);
220220

221221
dstBlob.create((int)shape.size(), &shape[0], CV_32F);

0 commit comments

Comments
 (0)