faustomorales / keras-ocr

A packaged and flexible version of the CRAFT text detector and Keras CRNN recognition model.
https://keras-ocr.readthedocs.io/
MIT License
1.38k stars 355 forks source link

ONNX conversion of the Detection Model #116

Open bhavitvyamalik opened 4 years ago

bhavitvyamalik commented 4 years ago

I converted keras-ocr detection model (craft_mlt_25k.h5) to ONNX via keras2onnx. It converted successfully and I even used onnx.checker.check_model() to check the converted model which gave no errors but when I ran prediction with that model it gave me the following error:

RuntimeException: [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Non-zero status code returned while running Conv node. Name:'convolution_output22_nchwc' Status Message: /onnxruntime_src/onnxruntime/core/providers/common.h:95 onnxruntime::common::Status onnxruntime::ComputePadAndOutputShape(int64_t, int64_t, int64_t, int64_t, onnxruntime::AutoPadType, int64_t*, int64_t*, int64_t*) [with bool ForceSymmetricAutoPadding = false; int64_t = long int] dilation == 1 was false. Dilation not supported for AutoPadType::SAME_UPPER or AutoPadType::SAME_LOWER.

I made sure to preprocess the image similarly as the model is expecting (include reshape) but nothing helped. Any thoughts?

faustomorales commented 4 years ago

Interesting! Reading that error, it seems that ONNX doesn't support automatic padding while also using dilation. You can avoid using automatic padding by setting a fixed input size so that the padding is fixed.

This code doesn't work, because the input shape is (None, None, 3).

import tensorflow as tf
import numpy as np
import onnxruntime
import keras2onnx
import keras_ocr

# There seems to be an outage right now preventing weights from downloading.
detector = keras_ocr.detection.Detector(weights=None)
model = detector.model
onnx_model = keras2onnx.convert_keras(model, model.name)

# runtime prediction
content = onnx_model.SerializeToString()
sess = onnxruntime.InferenceSession(content)
x = [np.random.uniform(size=(1, 480, 480, 3)).astype('float32')]
feed = dict([(input.name, x[n]) for n, input in enumerate(sess.get_inputs())])
pred_onnx = sess.run(None, feed)

However, if we wrap the model using a fixed input size, it seems to work without errors.

fixed_size_x = tf.keras.layers.Input((480, 480, 3))
fixed_size_y = detector.model(fixed_size_x) # Run the fixed size input through the model
fixed_size_model = tf.keras.models.Model(inputs=fixed_size_x, outputs=fixed_size_y)

onnx_model = keras2onnx.convert_keras(fixed_size_model, fixed_size_model.name)
# runtime prediction
content = onnx_model.SerializeToString()
sess = onnxruntime.InferenceSession(content)
x = [np.random.uniform(size=(1, 480, 480, 3)).astype('float32')]
feed = dict([(input.name, x[n]) for n, input in enumerate(sess.get_inputs())])
pred_onnx = sess.run(None, feed)
pred_keras = fixed_size_model.predict(x[0])
np.testing.assert_almost_equal(pred_onnx[0], pred_keras, decimal=3)

All that said, I haven't checked to make sure the output is totally correct but it looks mostly okay. Please let us know if you get this working!

bhavitvyamalik commented 4 years ago

Yeah it's working with fixed image size. I'll need to do some post-processing before checking output with my image as it returns an array of (240,240,2) shape. Will check that and get back to you. Thanks!