Skip to content

Commit e012ccd

Browse files
committed
Merge pull request opencv#9517 from dkurt:tf_mobilenet
2 parents f413667 + d891e9b commit e012ccd

File tree

5 files changed

+151
-19
lines changed

5 files changed

+151
-19
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
359359
static Ptr<ReLULayer> create(const LayerParams &params);
360360
};
361361

362+
class CV_EXPORTS ReLU6Layer : public ActivationLayer
363+
{
364+
public:
365+
static Ptr<ReLU6Layer> create(const LayerParams &params);
366+
};
367+
362368
class CV_EXPORTS ChannelsPReLULayer : public ActivationLayer
363369
{
364370
public:

modules/dnn/src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ void initializeLayerFactory()
9494
CV_DNN_REGISTER_LAYER_CLASS(LPNormalize, LPNormalizeLayer);
9595

9696
CV_DNN_REGISTER_LAYER_CLASS(ReLU, ReLULayer);
97+
CV_DNN_REGISTER_LAYER_CLASS(ReLU6, ReLU6Layer);
9798
CV_DNN_REGISTER_LAYER_CLASS(ChannelsPReLU, ChannelsPReLULayer);
9899
CV_DNN_REGISTER_LAYER_CLASS(Sigmoid, SigmoidLayer);
99100
CV_DNN_REGISTER_LAYER_CLASS(TanH, TanHLayer);

modules/dnn/src/layers/elementwise_layers.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,62 @@ struct ReLUFunctor
248248
int64 getFLOPSPerElement() const { return 1; }
249249
};
250250

251+
struct ReLU6Functor
252+
{
253+
typedef ReLU6Layer Layer;
254+
float minValue, maxValue;
255+
256+
ReLU6Functor(float minValue_ = 0.0f, float maxValue_ = 6.0f)
257+
: minValue(minValue_), maxValue(maxValue_)
258+
{
259+
CV_Assert(minValue <= maxValue);
260+
}
261+
262+
void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
263+
{
264+
for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
265+
{
266+
int i = 0;
267+
#if CV_SIMD128
268+
v_float32x4 minV = v_setall_f32(minValue), maxV = v_setall_f32(maxValue);
269+
for( ; i <= len - 16; i += 16 )
270+
{
271+
v_float32x4 x0 = v_load(srcptr + i);
272+
v_float32x4 x1 = v_load(srcptr + i + 4);
273+
v_float32x4 x2 = v_load(srcptr + i + 8);
274+
v_float32x4 x3 = v_load(srcptr + i + 12);
275+
x0 = v_min(v_max(minV, x0), maxV);
276+
x1 = v_min(v_max(minV, x1), maxV);
277+
x2 = v_min(v_max(minV, x2), maxV);
278+
x3 = v_min(v_max(minV, x3), maxV);
279+
v_store(dstptr + i, x0);
280+
v_store(dstptr + i + 4, x1);
281+
v_store(dstptr + i + 8, x2);
282+
v_store(dstptr + i + 12, x3);
283+
}
284+
#endif
285+
for( ; i < len; i++ )
286+
{
287+
float x = srcptr[i];
288+
if (x >= minValue)
289+
dstptr[i] = x <= maxValue ? x : maxValue;
290+
else
291+
dstptr[i] = minValue;
292+
}
293+
}
294+
}
295+
296+
#ifdef HAVE_HALIDE
297+
void attachHalide(const Halide::Expr& input, Halide::Func& top)
298+
{
299+
Halide::Var x("x"), y("y"), c("c"), n("n");
300+
top(x, y, c, n) = clamp(input, minValue, maxValue);
301+
}
302+
#endif // HAVE_HALIDE
303+
304+
int64 getFLOPSPerElement() const { return 2; }
305+
};
306+
251307
struct TanHFunctor
252308
{
253309
typedef TanHLayer Layer;
@@ -517,6 +573,15 @@ Ptr<ReLULayer> ReLULayer::create(const LayerParams& params)
517573
return l;
518574
}
519575

576+
Ptr<ReLU6Layer> ReLU6Layer::create(const LayerParams& params)
577+
{
578+
float minValue = params.get<float>("min_value", 0.0f);
579+
float maxValue = params.get<float>("max_value", 6.0f);
580+
Ptr<ReLU6Layer> l(new ElementWiseLayer<ReLU6Functor>(ReLU6Functor(minValue, maxValue)));
581+
l->setParamsFrom(params);
582+
return l;
583+
}
584+
520585
Ptr<TanHLayer> TanHLayer::create(const LayerParams& params)
521586
{
522587
Ptr<TanHLayer> l(new ElementWiseLayer<TanHFunctor>());

modules/dnn/src/tensorflow/tf_importer.cpp

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,38 @@ static Mat getTensorContent(const tensorflow::TensorProto &tensor)
8585
switch (tensor.dtype())
8686
{
8787
case tensorflow::DT_FLOAT:
88-
return Mat(1, content.size() / sizeof(float), CV_32FC1, (void*)content.c_str()).clone();
88+
{
89+
if (!content.empty())
90+
return Mat(1, content.size() / sizeof(float), CV_32FC1, (void*)content.c_str()).clone();
91+
else
92+
{
93+
const RepeatedField<float>& field = tensor.float_val();
94+
CV_Assert(!field.empty());
95+
return Mat(1, field.size(), CV_32FC1, (void*)field.data()).clone();
96+
}
97+
}
8998
case tensorflow::DT_DOUBLE:
90-
return Mat(1, content.size() / sizeof(double), CV_64FC1, (void*)content.c_str()).clone();
99+
{
100+
if (!content.empty())
101+
return Mat(1, content.size() / sizeof(double), CV_64FC1, (void*)content.c_str()).clone();
102+
else
103+
{
104+
const RepeatedField<double>& field = tensor.double_val();
105+
CV_Assert(!field.empty());
106+
return Mat(1, field.size(), CV_64FC1, (void*)field.data()).clone();
107+
}
108+
}
91109
case tensorflow::DT_INT32:
92-
return Mat(1, content.size() / sizeof(int32_t), CV_32SC1, (void*)content.c_str()).clone();
110+
{
111+
if (!content.empty())
112+
return Mat(1, content.size() / sizeof(int32_t), CV_32SC1, (void*)content.c_str()).clone();
113+
else
114+
{
115+
const RepeatedField<int32_t>& field = tensor.int_val();
116+
CV_Assert(!field.empty());
117+
return Mat(1, field.size(), CV_32SC1, (void*)field.data()).clone();
118+
}
119+
}
93120
case tensorflow::DT_HALF:
94121
{
95122
Mat halfs;
@@ -573,7 +600,7 @@ void TFImporter::populateNet(Net dstNet)
573600
if(layers_to_ignore.find(li) != layers_to_ignore.end())
574601
continue;
575602

576-
if (type == "Conv2D" || type == "SpaceToBatchND")
603+
if (type == "Conv2D" || type == "SpaceToBatchND" || type == "DepthwiseConv2dNative")
577604
{
578605
// The first node of dilated convolution subgraph.
579606
// Extract input node, dilation rate and paddings.
@@ -621,7 +648,28 @@ void TFImporter::populateNet(Net dstNet)
621648
}
622649

623650
kernelFromTensor(getConstBlob(layer, value_id), layerParams.blobs[0]);
624-
const int* kshape = layerParams.blobs[0].size.p;
651+
int* kshape = layerParams.blobs[0].size.p;
652+
if (type == "DepthwiseConv2dNative")
653+
{
654+
const int chMultiplier = kshape[0];
655+
const int inCh = kshape[1];
656+
const int height = kshape[2];
657+
const int width = kshape[3];
658+
659+
Mat copy = layerParams.blobs[0].clone();
660+
float* src = (float*)copy.data;
661+
float* dst = (float*)layerParams.blobs[0].data;
662+
for (int i = 0; i < chMultiplier; ++i)
663+
for (int j = 0; j < inCh; ++j)
664+
for (int s = 0; s < height * width; ++s)
665+
{
666+
int src_i = (i * inCh + j) * height * width + s;
667+
int dst_i = (j * chMultiplier + i) * height* width + s;
668+
dst[dst_i] = src[src_i];
669+
}
670+
kshape[0] = inCh * chMultiplier;
671+
kshape[1] = 1;
672+
}
625673
layerParams.set("kernel_h", kshape[2]);
626674
layerParams.set("kernel_w", kshape[3]);
627675
layerParams.set("num_output", kshape[0]);
@@ -689,6 +737,10 @@ void TFImporter::populateNet(Net dstNet)
689737
layerParams.blobs.resize(1);
690738

691739
StrIntVector next_layers = getNextLayers(net, name, "BiasAdd");
740+
if (next_layers.empty())
741+
{
742+
next_layers = getNextLayers(net, name, "Add");
743+
}
692744
if (next_layers.size() == 1) {
693745
layerParams.set("bias_term", true);
694746
layerParams.blobs.resize(2);
@@ -840,20 +892,20 @@ void TFImporter::populateNet(Net dstNet)
840892
{
841893
// Multiplication by constant.
842894
CV_Assert(layer.input_size() == 2);
895+
Mat scaleMat = getTensorContent(getConstBlob(layer, value_id));
896+
CV_Assert(scaleMat.type() == CV_32FC1);
843897

844-
float scale;
845-
if (!getConstBlob(layer, value_id).float_val().empty())
846-
scale = getConstBlob(layer, value_id).float_val()[0];
847-
else
898+
int id;
899+
if (scaleMat.total() == 1) // is a scalar.
848900
{
849-
Mat scaleMat;
850-
blobFromTensor(getConstBlob(layer, value_id), scaleMat);
851-
CV_Assert(scaleMat.total() == 1 && scaleMat.type() == CV_32FC1);
852-
scale = scaleMat.at<float>(0, 0);
901+
layerParams.set("scale", scaleMat.at<float>(0));
902+
id = dstNet.addLayer(name, "Power", layerParams);
903+
}
904+
else // is a vector
905+
{
906+
layerParams.blobs.resize(1, scaleMat);
907+
id = dstNet.addLayer(name, "Scale", layerParams);
853908
}
854-
layerParams.set("scale", scale);
855-
856-
int id = dstNet.addLayer(name, "Power", layerParams);
857909
layer_id[name] = id;
858910

859911
Pin inp0 = parsePin(layer.input(0));
@@ -1006,12 +1058,13 @@ void TFImporter::populateNet(Net dstNet)
10061058
}
10071059
else if (type == "Abs" || type == "Tanh" || type == "Sigmoid" ||
10081060
type == "Relu" || type == "Elu" || type == "Softmax" ||
1009-
type == "Identity")
1061+
type == "Identity" || type == "Relu6")
10101062
{
10111063
std::string dnnType = type;
10121064
if (type == "Abs") dnnType = "AbsVal";
10131065
else if (type == "Tanh") dnnType = "TanH";
10141066
else if (type == "Relu") dnnType = "ReLU";
1067+
else if (type == "Relu6") dnnType = "ReLU6";
10151068
else if (type == "Elu") dnnType = "ELU";
10161069

10171070
int id = dstNet.addLayer(name, dnnType, layerParams);

modules/dnn/test/test_tf_importer.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ static void runTensorFlowNet(const std::string& prefix,
9393
normAssert(target, output, "", l1, lInf);
9494
}
9595

96-
TEST(Test_TensorFlow, single_conv)
96+
TEST(Test_TensorFlow, conv)
9797
{
9898
runTensorFlowNet("single_conv");
9999
runTensorFlowNet("atrous_conv2d_valid");
100100
runTensorFlowNet("atrous_conv2d_same");
101+
runTensorFlowNet("depthwise_conv2d");
101102
}
102103

103104
TEST(Test_TensorFlow, padding)
@@ -116,8 +117,9 @@ TEST(Test_TensorFlow, pad_and_concat)
116117
runTensorFlowNet("pad_and_concat");
117118
}
118119

119-
TEST(Test_TensorFlow, fused_batch_norm)
120+
TEST(Test_TensorFlow, batch_norm)
120121
{
122+
runTensorFlowNet("batch_norm");
121123
runTensorFlowNet("fused_batch_norm");
122124
}
123125

@@ -133,6 +135,11 @@ TEST(Test_TensorFlow, deconvolution)
133135
runTensorFlowNet("deconvolution");
134136
}
135137

138+
TEST(Test_TensorFlow, matmul)
139+
{
140+
runTensorFlowNet("matmul");
141+
}
142+
136143
TEST(Test_TensorFlow, fp16)
137144
{
138145
const float l1 = 1e-3;

0 commit comments

Comments
 (0)