Skip to content

Commit cad7c4d

Browse files
committed
MobileNet-SSD and VGG-SSD topologies in Halide
1 parent 1caca21 commit cad7c4d

File tree

6 files changed

+221
-159
lines changed

6 files changed

+221
-159
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
146146
*/
147147
virtual void copyToHost() = 0;
148148

149+
/**
150+
* @brief Indicate that an actual data is on CPU.
151+
*/
152+
virtual void setHostDirty() = 0;
153+
149154
int backendId; //!< Backend identifier.
150155
int targetId; //!< Target identifier.
151156
};

modules/dnn/src/dnn.cpp

Lines changed: 110 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -199,125 +199,6 @@ struct LayerPin
199199
}
200200
};
201201

202-
// Objects of this class manages wrappers. For every CPU memory pointer and shape
203-
// one and only wrapper. Now it support wrapping for single backend and target.
204-
class BackendWrapManager
205-
{
206-
public:
207-
Ptr<BackendWrapper> wrap(const Mat& m, int backendId, int targetId)
208-
{
209-
CV_TRACE_FUNCTION();
210-
211-
CV_Assert(backendId != DNN_BACKEND_DEFAULT);
212-
213-
std::map<void*, Ptr<BackendWrapper> >::iterator hostsIt;
214-
// Check that the same CPU memory was previously wrapped.
215-
hostsIt = hostWrappers.find(m.data);
216-
if (hostsIt == hostWrappers.end())
217-
{
218-
// If not wrapped before.
219-
return (hostWrappers[m.data] = wrapHost(m, backendId, targetId));
220-
}
221-
else
222-
{
223-
// Find if wrapper of this host and shape was created before.
224-
std::map<std::pair<void*, MatSize>, Ptr<BackendWrapper> >::iterator it;
225-
std::pair<void*, MatSize> key(m.data, m.size);
226-
it = extraWrappers.find(key);
227-
if (it == extraWrappers.end())
228-
{
229-
MatShape shape(m.dims);
230-
for (int i = 0; i < m.dims; ++i)
231-
shape[i] = m.size.p[i];
232-
return (extraWrappers[key] = wrapUser(hostsIt->second, shape));
233-
}
234-
else
235-
return it->second;
236-
}
237-
}
238-
239-
std::vector<Ptr<BackendWrapper> > wrap(const std::vector<Mat*>& mats,
240-
int backendId, int targetId)
241-
{
242-
const int num = mats.size();
243-
std::vector<Ptr<BackendWrapper> > dst(num);
244-
for (int i = 0; i < num; ++i)
245-
{
246-
dst[i] = wrap(*mats[i], backendId, targetId);
247-
}
248-
return dst;
249-
}
250-
251-
std::vector<Ptr<BackendWrapper> > wrap(const std::vector<Mat>& mats,
252-
int backendId, int targetId)
253-
{
254-
const int num = mats.size();
255-
std::vector<Ptr<BackendWrapper> > dst(num);
256-
for (int i = 0; i < num; ++i)
257-
{
258-
dst[i] = wrap(mats[i], backendId, targetId);
259-
}
260-
return dst;
261-
}
262-
263-
void reset()
264-
{
265-
CV_TRACE_FUNCTION();
266-
267-
hostWrappers.clear();
268-
extraWrappers.clear();
269-
}
270-
271-
private:
272-
// Backend-specific wrapping function.
273-
Ptr<BackendWrapper> wrapHost(const Mat& m, int backendId, int targetId)
274-
{
275-
if (backendId == DNN_BACKEND_DEFAULT)
276-
{
277-
return Ptr<BackendWrapper>();
278-
}
279-
else if (backendId == DNN_BACKEND_HALIDE)
280-
{
281-
CV_Assert(haveHalide());
282-
#ifdef HAVE_HALIDE
283-
return Ptr<BackendWrapper>(new HalideBackendWrapper(targetId, m));
284-
#endif // HAVE_HALIDE
285-
}
286-
else
287-
{
288-
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
289-
}
290-
return Ptr<BackendWrapper>();
291-
}
292-
293-
// Backend-specific wrapping function.
294-
Ptr<BackendWrapper> wrapUser(const Ptr<BackendWrapper>& host, const MatShape& shape)
295-
{
296-
int backendId = host->backendId;
297-
if (backendId == DNN_BACKEND_DEFAULT)
298-
{
299-
return Ptr<BackendWrapper>();
300-
}
301-
else if (backendId == DNN_BACKEND_HALIDE)
302-
{
303-
CV_Assert(haveHalide());
304-
#ifdef HAVE_HALIDE
305-
return Ptr<BackendWrapper>(new HalideBackendWrapper(host, shape));
306-
#endif // HAVE_HALIDE
307-
}
308-
else
309-
{
310-
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
311-
}
312-
return Ptr<BackendWrapper>();
313-
}
314-
315-
// Wrappers that initialized for memory hosts (first wrapping of CPU data).
316-
std::map<void*, Ptr<BackendWrapper> > hostWrappers;
317-
// The rest of wrappers. They initialized for non-host cv::Mat.
318-
std::map<std::pair<void*, MatSize>, Ptr<BackendWrapper> > extraWrappers;
319-
};
320-
321202
struct LayerData
322203
{
323204
LayerData() : id(-1), flag(0) {}
@@ -340,6 +221,8 @@ struct LayerData
340221
std::set<int> inputLayersId;
341222
std::set<int> requiredOutputs;
342223
std::vector<LayerPin> consumers;
224+
std::vector<Ptr<BackendWrapper> > outputBlobsWrappers;
225+
std::vector<Ptr<BackendWrapper> > inputBlobsWrappers;
343226

344227
Ptr<Layer> layerInstance;
345228
std::vector<Mat> outputBlobs;
@@ -618,6 +501,24 @@ struct BlobManager
618501
std::map<LayerPin, Mat> memHosts;
619502
};
620503

504+
static Ptr<BackendWrapper> wrapMat(int backendId, int targetId, const cv::Mat& m)
505+
{
506+
if (backendId == DNN_BACKEND_DEFAULT)
507+
{
508+
return Ptr<BackendWrapper>();
509+
}
510+
else if (backendId == DNN_BACKEND_HALIDE)
511+
{
512+
CV_Assert(haveHalide());
513+
#ifdef HAVE_HALIDE
514+
return Ptr<BackendWrapper>(new HalideBackendWrapper(targetId, m));
515+
#endif // HAVE_HALIDE
516+
}
517+
else
518+
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
519+
return Ptr<BackendWrapper>();
520+
}
521+
621522
struct Net::Impl
622523
{
623524
typedef std::map<int, LayerShapes> LayersShapesMap;
@@ -650,15 +551,71 @@ struct Net::Impl
650551
int preferableBackend;
651552
int preferableTarget;
652553
String halideConfigFile;
653-
// Backend-specific wrapping manager.
654-
BackendWrapManager backendWrapper;
554+
// Map host data to backend specific wrapper.
555+
std::map<void*, Ptr<BackendWrapper> > backendWrappers;
655556

656557
int lastLayerId;
657558

658559
bool netWasAllocated;
659560
bool fusion;
660561
std::vector<int64> layersTimings;
661562

563+
Ptr<BackendWrapper> wrap(const Mat& host)
564+
{
565+
if (preferableBackend == DNN_BACKEND_DEFAULT)
566+
return Ptr<BackendWrapper>();
567+
568+
MatShape shape(host.dims);
569+
for (int i = 0; i < host.dims; ++i)
570+
shape[i] = host.size[i];
571+
572+
void* data = host.data;
573+
if (backendWrappers.find(data) != backendWrappers.end())
574+
{
575+
Ptr<BackendWrapper> baseBuffer = backendWrappers[data];
576+
if (preferableBackend == DNN_BACKEND_HALIDE)
577+
{
578+
CV_Assert(haveHalide());
579+
#ifdef HAVE_HALIDE
580+
return Ptr<BackendWrapper>(new HalideBackendWrapper(baseBuffer, shape));
581+
#endif // HAVE_HALIDE
582+
}
583+
else
584+
CV_Error(Error::StsNotImplemented, "Unknown backend identifier");
585+
}
586+
587+
Ptr<BackendWrapper> wrapper = wrapMat(preferableBackend, preferableTarget, host);
588+
backendWrappers[data] = wrapper;
589+
return wrapper;
590+
}
591+
592+
class HalideCompiler : public ParallelLoopBody
593+
{
594+
public:
595+
HalideCompiler(const MapIdToLayerData& layers_, int preferableTarget_)
596+
: layers(&layers_), preferableTarget(preferableTarget_) {}
597+
598+
void operator()(const Range& r) const
599+
{
600+
MapIdToLayerData::const_iterator it = layers->begin();
601+
for (int i = 0; i < r.start && it != layers->end(); ++i, ++it) {}
602+
for (int i = r.start; i < r.end && it != layers->end(); ++i, ++it)
603+
{
604+
const LayerData &ld = it->second;
605+
Ptr<Layer> layer = ld.layerInstance;
606+
bool skip = ld.skipFlags.find(DNN_BACKEND_HALIDE)->second;
607+
if (layer->supportBackend(DNN_BACKEND_HALIDE) && !skip)
608+
{
609+
Ptr<BackendNode> node = ld.backendNodes.find(DNN_BACKEND_HALIDE)->second;
610+
dnn::compileHalide(ld.outputBlobs, node, preferableTarget);
611+
}
612+
}
613+
}
614+
private:
615+
const MapIdToLayerData* layers;
616+
int preferableTarget;
617+
};
618+
662619
void compileHalide()
663620
{
664621
CV_TRACE_FUNCTION();
@@ -682,10 +639,9 @@ struct Net::Impl
682639
ld.inputBlobs, ld.outputBlobs,
683640
preferableTarget);
684641
}
685-
dnn::compileHalide(ld.outputBlobs, ld.backendNodes[DNN_BACKEND_HALIDE],
686-
preferableTarget);
687642
}
688643
}
644+
parallel_for_(Range(0, layers.size()), HalideCompiler(layers, preferableTarget));
689645
}
690646

691647
void clear()
@@ -917,7 +873,6 @@ struct Net::Impl
917873
{
918874
CV_TRACE_FUNCTION();
919875

920-
backendWrapper.reset();
921876
if (preferableBackend == DNN_BACKEND_DEFAULT)
922877
{
923878
CV_Assert(preferableTarget == DNN_TARGET_CPU);
@@ -967,12 +922,10 @@ struct Net::Impl
967922
}
968923
// No layers fusion.
969924
ldTop.skipFlags[preferableBackend] = false;
970-
std::vector<Ptr<BackendWrapper> > inputs =
971-
backendWrapper.wrap(ldTop.inputBlobs, preferableBackend,
972-
preferableTarget);
973925
if (preferableBackend == DNN_BACKEND_HALIDE)
974926
{
975-
ldTop.backendNodes[DNN_BACKEND_HALIDE] = layerTop->initHalide(inputs);
927+
ldTop.backendNodes[DNN_BACKEND_HALIDE] =
928+
layerTop->initHalide(ldTop.inputBlobsWrappers);
976929
baseIt = it;
977930
}
978931
else
@@ -1021,12 +974,14 @@ struct Net::Impl
1021974

1022975
//bind inputs
1023976
ld.inputBlobs.resize(ninputs);
977+
ld.inputBlobsWrappers.resize(ninputs);
1024978
for (size_t i = 0; i < ninputs; i++)
1025979
{
1026980
LayerPin from = ld.inputBlobsId[i];
1027981
CV_Assert(from.valid());
1028982
CV_DbgAssert(layers.count(from.lid) && (int)layers[from.lid].outputBlobs.size() > from.oid);
1029983
ld.inputBlobs[i] = &layers[from.lid].outputBlobs[from.oid];
984+
ld.inputBlobsWrappers[i] = layers[from.lid].outputBlobsWrappers[from.oid];
1030985
}
1031986

1032987
LayersShapesMap::const_iterator layerShapesIt = layersShapes.find(lid);
@@ -1036,6 +991,11 @@ struct Net::Impl
1036991
std::vector<LayerPin> pinsForInternalBlobs;
1037992
bool maximizeReuse = preferableBackend == DNN_BACKEND_HALIDE;
1038993
blobManager.allocateBlobsForLayer(ld, layerShapesIt->second, pinsForInternalBlobs, maximizeReuse);
994+
ld.outputBlobsWrappers.resize(ld.outputBlobs.size());
995+
for (int i = 0; i < ld.outputBlobs.size(); ++i)
996+
{
997+
ld.outputBlobsWrappers[i] = wrap(ld.outputBlobs[i]);
998+
}
1039999

10401000
Ptr<Layer> layerPtr = ld.getLayerInstance();
10411001
{
@@ -1256,6 +1216,8 @@ struct Net::Impl
12561216
getLayersShapes(inputShapes, layersShapes);
12571217

12581218
blobManager.reset();
1219+
backendWrappers.clear();
1220+
blobManager.addReference(LayerPin(0, 0));
12591221
for (it = layers.begin(); it != layers.end(); ++it)
12601222
{
12611223
const LayerData& ld = it->second;
@@ -1291,18 +1253,28 @@ struct Net::Impl
12911253
!layer->supportBackend(preferableBackend))
12921254
{
12931255
if( !ld.skipFlags[DNN_BACKEND_DEFAULT] )
1256+
{
1257+
for (int i = 0, n = ld.inputBlobsWrappers.size(); i < n; ++i)
1258+
{
1259+
if (!ld.inputBlobsWrappers[i].empty())
1260+
ld.inputBlobsWrappers[i]->copyToHost();
1261+
}
12941262
layer->forward(ld.inputBlobs, ld.outputBlobs, ld.internals);
1263+
for (int i = 0, n = ld.outputBlobsWrappers.size(); i < n; ++i)
1264+
{
1265+
if (!ld.outputBlobsWrappers[i].empty())
1266+
ld.outputBlobsWrappers[i]->setHostDirty();
1267+
}
1268+
}
12951269
else
12961270
tm.reset();
12971271
}
12981272
else if (!ld.skipFlags[preferableBackend])
12991273
{
1300-
std::vector<Ptr<BackendWrapper> > outputs =
1301-
backendWrapper.wrap(ld.outputBlobs, preferableBackend, preferableTarget);
13021274
Ptr<BackendNode> node = ld.backendNodes[preferableBackend];
13031275
if (preferableBackend == DNN_BACKEND_HALIDE)
13041276
{
1305-
forwardHalide(outputs, node);
1277+
forwardHalide(ld.outputBlobsWrappers, node);
13061278
}
13071279
else
13081280
{
@@ -1421,11 +1393,10 @@ struct Net::Impl
14211393
CV_Error(Error::StsOutOfRange, "Layer \"" + ld.name + "\" produce only " + toString(ld.outputBlobs.size()) +
14221394
" outputs, the #" + toString(pin.oid) + " was requsted");
14231395
}
1424-
if (preferableBackend != DNN_BACKEND_DEFAULT)
1396+
if (preferableBackend != DNN_TARGET_CPU)
14251397
{
14261398
// Transfer data to CPU if it's require.
1427-
backendWrapper.wrap(ld.outputBlobs[pin.oid], preferableBackend,
1428-
preferableTarget)->copyToHost();
1399+
ld.outputBlobsWrappers[pin.oid]->copyToHost();
14291400
}
14301401
else
14311402
{
@@ -1633,13 +1604,18 @@ void Net::setInput(const Mat &blob_, const String& name)
16331604

16341605
LayerData &ld = impl->layers[pin.lid];
16351606
ld.outputBlobs.resize( std::max(pin.oid+1, (int)ld.requiredOutputs.size()) );
1607+
ld.outputBlobsWrappers.resize(ld.outputBlobs.size());
16361608
MatShape prevShape = shape(ld.outputBlobs[pin.oid]);
16371609
bool oldShape = prevShape == shape(blob_);
16381610
if (oldShape)
16391611
blob_.copyTo(ld.outputBlobs[pin.oid]);
16401612
else
16411613
ld.outputBlobs[pin.oid] = blob_.clone();
16421614

1615+
if (!ld.outputBlobsWrappers[pin.oid].empty())
1616+
{
1617+
ld.outputBlobsWrappers[pin.oid]->setHostDirty();
1618+
}
16431619
impl->netWasAllocated = impl->netWasAllocated && oldShape;
16441620
}
16451621

0 commit comments

Comments
 (0)