@@ -1160,8 +1160,35 @@ void TFImporter::populateNet(Net dstNet)
1160
1160
int id;
1161
1161
if (scaleMat.total () == 1 ) // is a scalar.
1162
1162
{
1163
- layerParams.set (" scale" , scaleMat.at <float >(0 ));
1164
- id = dstNet.addLayer (name, " Power" , layerParams);
1163
+ // Try to match with a LeakyRelu:
1164
+ // node {
1165
+ // name: "LeakyRelu/mul"
1166
+ // op: "Mul"
1167
+ // input: "LeakyRelu/alpha"
1168
+ // input: "input"
1169
+ // }
1170
+ // node {
1171
+ // name: "LeakyRelu/Maximum"
1172
+ // op: "Maximum"
1173
+ // input: "LeakyRelu/mul"
1174
+ // input: "input"
1175
+ // }
1176
+ StrIntVector next_layers = getNextLayers (net, name, " Maximum" );
1177
+ if (!next_layers.empty ())
1178
+ {
1179
+ int maximumLayerIdx = next_layers[0 ].second ;
1180
+ ExcludeLayer (net, maximumLayerIdx, 0 , false );
1181
+ layers_to_ignore.insert (next_layers[0 ].first );
1182
+
1183
+ layerParams.set (" negative_slope" , scaleMat.at <float >(0 ));
1184
+ id = dstNet.addLayer (name, " ReLU" , layerParams);
1185
+ }
1186
+ else
1187
+ {
1188
+ // Just a multiplication.
1189
+ layerParams.set (" scale" , scaleMat.at <float >(0 ));
1190
+ id = dstNet.addLayer (name, " Power" , layerParams);
1191
+ }
1165
1192
}
1166
1193
else // is a vector
1167
1194
{
@@ -1241,16 +1268,37 @@ void TFImporter::populateNet(Net dstNet)
1241
1268
if (layer.input_size () != 5 )
1242
1269
CV_Error (Error::StsNotImplemented,
1243
1270
" Expected gamma, beta, mean and std" );
1271
+ Pin inpId = parsePin (layer.input (0 ));
1272
+
1273
+ bool isTraining = hasLayerAttr (layer, " is_training" ) && getLayerAttr (layer, " is_training" ).b ();
1244
1274
1245
1275
layerParams.blobs .resize (4 );
1246
- // gamma
1247
- blobFromTensor (getConstBlob (layer, value_id, 1 ), layerParams.blobs [2 ]);
1248
- // beta
1249
- blobFromTensor (getConstBlob (layer, value_id, 2 ), layerParams.blobs [3 ]);
1250
- // mean
1251
- blobFromTensor (getConstBlob (layer, value_id, 3 ), layerParams.blobs [0 ]);
1252
- // std
1253
- blobFromTensor (getConstBlob (layer, value_id, 4 ), layerParams.blobs [1 ]);
1276
+ Mat gamma, beta, mean, std;
1277
+ blobFromTensor (getConstBlob (layer, value_id, 1 ), gamma);
1278
+ blobFromTensor (getConstBlob (layer, value_id, 2 ), beta);
1279
+ if (isTraining)
1280
+ {
1281
+ mean = Mat::zeros (1 , beta.total (), CV_32F);
1282
+ std = Mat::ones (1 , beta.total (), CV_32F);
1283
+
1284
+ // Add an extra layer: Mean-Variance normalization
1285
+ LayerParams mvnParams;
1286
+ std::string mvnName = name + " /MVN" ;
1287
+ CV_Assert (layer_id.find (mvnName) == layer_id.end ());
1288
+ int mvnId = dstNet.addLayer (mvnName, " MVN" , mvnParams);
1289
+ layer_id[mvnName] = mvnId;
1290
+ connect (layer_id, dstNet, inpId, mvnId, 0 );
1291
+ inpId = Pin (mvnName);
1292
+ }
1293
+ else
1294
+ {
1295
+ blobFromTensor (getConstBlob (layer, value_id, 3 ), mean);
1296
+ blobFromTensor (getConstBlob (layer, value_id, 4 ), std);
1297
+ }
1298
+ layerParams.blobs [0 ] = mean;
1299
+ layerParams.blobs [1 ] = std;
1300
+ layerParams.blobs [2 ] = gamma;
1301
+ layerParams.blobs [3 ] = beta;
1254
1302
1255
1303
if (hasLayerAttr (layer, " epsilon" ))
1256
1304
layerParams.set (" eps" , getLayerAttr (layer, " epsilon" ).f ());
@@ -1262,7 +1310,7 @@ void TFImporter::populateNet(Net dstNet)
1262
1310
layer_id[name] = id;
1263
1311
1264
1312
// one input only
1265
- connect (layer_id, dstNet, parsePin (layer. input ( 0 )) , id, 0 );
1313
+ connect (layer_id, dstNet, inpId , id, 0 );
1266
1314
}
1267
1315
else if (type == " Conv2DBackpropInput" )
1268
1316
{
@@ -1293,13 +1341,42 @@ void TFImporter::populateNet(Net dstNet)
1293
1341
kernelFromTensor (getConstBlob (layer, value_id, 1 ), layerParams.blobs [0 ]);
1294
1342
1295
1343
const int * kshape = layerParams.blobs [0 ].size .p ;
1296
- layerParams.set (" kernel_h" , kshape[2 ]);
1297
- layerParams.set (" kernel_w" , kshape[3 ]);
1344
+ const int kernelH = kshape[2 ];
1345
+ const int kernelW = kshape[3 ];
1346
+ layerParams.set (" kernel_h" , kernelH);
1347
+ layerParams.set (" kernel_w" , kernelW);
1298
1348
layerParams.set (" num_output" , kshape[1 ]);
1299
1349
1300
1350
setStrides (layerParams, layer);
1301
1351
setPadding (layerParams, layer);
1302
1352
1353
+ // For convolution layer, output shape computes as
1354
+ // o = 1 + (i - k + 2*p) / s
1355
+ // i - input size, o - output size, k - kernel size, p - pad, s - stride
1356
+ // In TensorFlow, p == 0 is padMode == 'VALID' or p == (k - 1) / 2
1357
+ // considering that k is odd.
1358
+ // SAME: o = 1 + (i - 1) / s
1359
+ // VALID: o = 1 + i / s
1360
+ // Deconvolution's layer output shape computes as
1361
+ // SAME: o = 1 + (i - 1)*s
1362
+ // VALID: o = (i - 1)*s
1363
+ // If output_shape differs from formulas above then adjust padding is applied.
1364
+
1365
+ const int strideY = layerParams.get <int >(" stride_h" );
1366
+ const int strideX = layerParams.get <int >(" stride_w" );
1367
+ Mat outShape = getTensorContent (getConstBlob (layer, value_id, 0 ));
1368
+ const int outH = outShape.at <int >(2 );
1369
+ const int outW = outShape.at <int >(1 );
1370
+ if (layerParams.get <String>(" pad_mode" ) == " SAME" )
1371
+ {
1372
+ layerParams.set (" adj_w" , (outW - 1 ) % strideX);
1373
+ layerParams.set (" adj_h" , (outH - 1 ) % strideY);
1374
+ }
1375
+ else if (layerParams.get <String>(" pad_mode" ) == " VALID" )
1376
+ {
1377
+ layerParams.set (" adj_w" , (outW - kernelW) % strideX);
1378
+ layerParams.set (" adj_h" , (outH - kernelH) % strideY);
1379
+ }
1303
1380
int id = dstNet.addLayer (name, " Deconvolution" , layerParams);
1304
1381
layer_id[name] = id;
1305
1382
0 commit comments