Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

@Rodrigo2019, I'm sorry for the delay. The problem is that at OpenCV 3.3.0 reshape layer had a kind of condition to make a data permutation (like from NHWC data layout to NCHW). We've removed it. Shortly your model is a sequence of the following layers:

Placeholder conv2d_1_input
Const conv2d_1/kernel
Conv2D conv2d_1/convolution
Const conv2d_1/bias
BiasAdd conv2d_1/BiasAdd
Relu activation_1/Relu
MaxPool max_pooling2d_1/MaxPool
Const conv2d_2/kernel
Conv2D conv2d_2/convolution
Const conv2d_2/bias
BiasAdd conv2d_2/BiasAdd
Relu activation_2/Relu
MaxPool max_pooling2d_2/MaxPool
Const reshape_1/Reshape/shape
Reshape reshape_1/Reshape
Const dense_1/kernel
MatMul dense_1/MatMul
Const dense_1/bias
BiasAdd dense_1/BiasAdd
Relu activation_3/Relu
Const dense_2/kernel
MatMul dense_2/MatMul
Const dense_2/bias
BiasAdd dense_2/BiasAdd
Softmax activation_4/Softmax

And we have to add one permutation manually to indicate that fully-connected layer expects NHWC input (default TensorFlow data layout).

The easiest way is to use text graph representation. To do it just run the following script:

import tensorflow as tf

# Read the graph.
with tf.gfile.FastGFile('model_final.pb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())

# Remove Const nodes.
for i in reversed(range(len(graph_def.node))):
    if graph_def.node[i].op == 'Const':
        del graph_def.node[i]
    for attr in ['T', 'data_format', 'Tshape', 'N', 'Tidx', 'Tdim',
                 'use_cudnn_on_gpu', 'Index', 'Tperm', 'is_training',
                 'Tpaddings']:
        if attr in graph_def.node[i].attr:
            del graph_def.node[i].attr[attr]

# Save as text.
tf.train.write_graph(graph_def, "", "model_final.pbtxt", as_text=True)

And replace

node {
  name: "reshape_1/Reshape"
  op: "Reshape"
  input: "max_pooling2d_2/MaxPool"
  input: "reshape_1/Reshape/shape"
}

onto

node {
  name: "order"
  op: "Const"
  attr {
    key: "value"
    value {
      tensor {
        dtype: DT_INT32
        tensor_shape {
        }
        int_val: 0
        int_val: 1
        int_val: 2
        int_val: 3
      }
    }
  }
}
node {
  name: "max_pooling2d_2/MaxPool/transpose"
  op: "Transpose"
  input: "max_pooling2d_2/MaxPool"
  input: "order"
}
node {
  name: "reshape_1/Reshape"
  op: "Reshape"
  input: "max_pooling2d_2/MaxPool/transpose"
  input: "reshape_1/Reshape/shape"
}

Now the following script that matches TensorFlow's output with OpenCV's one produces 2.91038e-11 maximal absolute difference.

import numpy as np
import tensorflow as tf
import time

with tf.gfile.FastGFile('model_final.pb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())

with tf.Session() as sess:
    sess.graph.as_default()
    tf.import_graph_def(graph_def, name='')
    for node in graph_def.node:
        print node.op, node.name

    # Generate input
    np.random.seed(2701)
    inp = np.random.standard_normal([1, 28, 92, 1]).astype(np.float32)

    # Get output tensor
    outTensor = sess.graph.get_tensor_by_name('activation_4/Softmax:0')
    out = sess.run(outTensor, feed_dict={'conv2d_1_input:0': inp})

import cv2 as cv
cvNet = cv.dnn.readNetFromTensorflow('model_final.pb', 'model_final.pbtxt')
cvNet.setInput(inp.transpose(0, 3, 1, 2))
cvOut = cvNet.forward()
print np.max(np.abs(cvOut - out))