Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt the convertor to tensorrt backend #47

Merged
merged 6 commits into from
May 16, 2018

Conversation

kuke
Copy link

@kuke kuke commented May 9, 2018

Resolve #46

The TensorRT backend for onnx only supports onnx==1.0.1 right now, while we were carrying out experiments on master branch of ONNX and caffe2 backend. Hence, we need to make some adaptions to enable the converted models running with TensorRT backend.

Now the conversion's correctness of all the current supported models has been validated on TensorRT, including:

  • fit_a_line
  • recognize_digits
  • VGG16 & ResNet50
  • MobileNet
  • SE_ResNeXt

onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=model_name,
initializer=weights,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TensorRT backend distinguishes weights and tensors, so we have to use initializer to initialize parameters.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great - so this is consistent with our original plan to add the initializer in at some point! Very happy to see this

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also solves some problems we are having when trying to use other ONNX convertors

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to initialize the tmp inputs and outputs to the ops too? @nickyfantasy is having issues converting the model to the qualcomm DLC spec

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. initializer is the officially recommended to initialize parameters, and the issues under onnx/models show that they may deprecate the Constant op initialization someday.

It should not be the proper way to initialize the tmp inputs and outputs to the ops. Let's figure out what happened here after Qualcomm prepare related operators.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kuke I think @nickyfantasy found out why that issue was happening. you are right, it isn't the right way to initialize tmp inputs/outputs, so we are good.

outputs=outputs['Out'],
scale=1.0 - attrs['dropout_prob'])
return (dropout_op, scale_op)
if __onnx_ver__ == '1.0.1':
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TensorRT doesn't support Scale op

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way we could use a version range or max / min comparison instead of hardcoding a specific version? And in the last possible resort where we were going to, perhaps make it a constant at the top?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I understood what this means fully: "note that our implementation of Dropout does scaling in the training phase", but do we still need to scale given this context

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we temporarily fix the version number to 1.0.1 right now? because there are several releases, and I have not checked the changes in the definition of operators.

You got the point. Yes, we need to scale the output of Dropout op, otherwise inference wouldn't get right result.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kuke Okay, no worries, but we would probably need to come back to this, as it will bite as we try to make our ONNX models compatible for various backends.

inputs=inputs['Y'],
outputs=y_flat_out,
axis=attrs['y_num_col_dims'])
if __onnx_ver__ == '1.0.1':
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input dim of Flatten op is limited to equal to 3.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be awesome as a comment in the code :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

output_node = make_node(
'Reshape',
inputs=matmul_out,
shape=out_shape,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shape is an attribute in onnx v1.0.1

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, code comment

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Collaborator

@varunarora varunarora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its fair to update the pip requirements file also to 1.0.1.

onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=model_name,
initializer=weights,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great - so this is consistent with our original plan to add the initializer in at some point! Very happy to see this

onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=model_name,
initializer=weights,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also solves some problems we are having when trying to use other ONNX convertors

@@ -68,13 +72,6 @@ def activation_ops(act_type, operator, block):
act_type, inputs=inputs.values()[0], outputs=outputs.values()[0])


def and_op():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for removing this placeholder function?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nvm I realize this is merged into the elementwise stuff

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is no longer needed.

@@ -87,36 +84,52 @@ def batch_norm_op(operator, block):
inputs, attrs, outputs = op_io_info(operator)

x_shape = block.vars[get_old_name(inputs['X'][0])].shape
reshape_node = None
nodes = ()
if len(x_shape) == 2:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of us are stuck on why we do it this way. Then using a constant-less version for v1.0.1. Would love if you could add in some comments here - mostly for educating us.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the comment about why we need reshape here. And why didn't use Constant op in branch 1.0.1? the answer is that in onnx1.0.1 shape is used as an attribute and doesn't need a constant op to feed value.

'momentum': attrs['momentum']
}
if __onnx_ver__ == u'1.0.1':
kwargs['consumed_inputs'] = [0, 0, 0, 1, 1]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you figure the value of this out? Any reference to papers / code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No docs found. If don't set the consumed_inputs, ONNX will give an error

onnx.onnx_cpp2py_export.checker.ValidationError: Input index 3 must be set to consumed for operator BatchNormalization

So I looked into the code in ONNX 1.0.1, finally find this attribute and its proper usage.

fluid_to_onnx.py Outdated
onnx_nodes.append(param_node)
weight, val_info = paddle_onnx_weight(
var=var, scope=inference_scope)
weights.append(weight), weights_value_info.append(val_info)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh just do the two appends over two lines, so this doesn't confuse anyone

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=model_name,
initializer=weights,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to initialize the tmp inputs and outputs to the ops too? @nickyfantasy is having issues converting the model to the qualcomm DLC spec

inputs=inputs['Y'],
outputs=y_flat_out,
axis=attrs['y_num_col_dims'])
if __onnx_ver__ == '1.0.1':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be awesome as a comment in the code :)

output_node = make_node(
'Reshape',
inputs=matmul_out,
shape=out_shape,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, code comment

'Flatten',
inputs=inputs['Y'],
outputs=y_flat_out,
axis=attrs['y_num_col_dims'])

# Mat mul
matmul_out = [outputs['Out'][0] + '@matmul_0']
matmul_node = make_node(
'MatMul', inputs=x_flat_out + y_flat_out, outputs=matmul_out)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickyfantasy is asking if we can use the Mul op here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems cannot, Mul op is for element-wise production

Copy link
Author

@kuke kuke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@varunarora Thanks for the review!

I find that the ONNX release 1.1.2 is far behind the master branch, not the same as I thought. Maybe we'd better only consider v1.0.1 and the latest master branch of ONNX temporarily, and go back to the
compatibility some day in the future.

@@ -68,13 +72,6 @@ def activation_ops(act_type, operator, block):
act_type, inputs=inputs.values()[0], outputs=outputs.values()[0])


def and_op():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is no longer needed.

from caffe2.python.onnx.backend import Caffe2Backend
rep = Caffe2Backend.prepare(onnx_model, device='CPU')
else:
import onnx_tensorrt.backend as backend
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Appreciate that.

onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=model_name,
initializer=weights,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. initializer is the officially recommended to initialize parameters, and the issues under onnx/models show that they may deprecate the Constant op initialization someday.

It should not be the proper way to initialize the tmp inputs and outputs to the ops. Let's figure out what happened here after Qualcomm prepare related operators.

fluid_to_onnx.py Outdated
onnx_nodes.append(param_node)
weight, val_info = paddle_onnx_weight(
var=var, scope=inference_scope)
weights.append(weight), weights_value_info.append(val_info)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

output_node = make_node(
'Reshape',
inputs=matmul_out,
shape=out_shape,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

'Flatten',
inputs=inputs['Y'],
outputs=y_flat_out,
axis=attrs['y_num_col_dims'])

# Mat mul
matmul_out = [outputs['Out'][0] + '@matmul_0']
matmul_node = make_node(
'MatMul', inputs=x_flat_out + y_flat_out, outputs=matmul_out)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems cannot, Mul op is for element-wise production

'momentum': attrs['momentum']
}
if __onnx_ver__ == u'1.0.1':
kwargs['consumed_inputs'] = [0, 0, 0, 1, 1]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No docs found. If don't set the consumed_inputs, ONNX will give an error

onnx.onnx_cpp2py_export.checker.ValidationError: Input index 3 must be set to consumed for operator BatchNormalization

So I looked into the code in ONNX 1.0.1, finally find this attribute and its proper usage.

@@ -87,36 +84,52 @@ def batch_norm_op(operator, block):
inputs, attrs, outputs = op_io_info(operator)

x_shape = block.vars[get_old_name(inputs['X'][0])].shape
reshape_node = None
nodes = ()
if len(x_shape) == 2:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the comment about why we need reshape here. And why didn't use Constant op in branch 1.0.1? the answer is that in onnx1.0.1 shape is used as an attribute and doesn't need a constant op to feed value.

outputs=outputs['Out'],
scale=1.0 - attrs['dropout_prob'])
return (dropout_op, scale_op)
if __onnx_ver__ == '1.0.1':
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we temporarily fix the version number to 1.0.1 right now? because there are several releases, and I have not checked the changes in the definition of operators.

You got the point. Yes, we need to scale the output of Dropout op, otherwise inference wouldn't get right result.

inputs=inputs['Y'],
outputs=y_flat_out,
axis=attrs['y_num_col_dims'])
if __onnx_ver__ == '1.0.1':
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@varunarora
Copy link
Collaborator

Got it. Instead, why don't we just make 1.0.1 as our main version supported. And then do a if version > 1.0.1: use original op written for a higher version.

We can't guarantee support of master, but we can expect 1.0.0 or 1.0.1 as a stable point for all backends.

@kuke
Copy link
Author

kuke commented May 16, 2018

@varunarora Thanks! It is good to use 1.0.1 as the stable point. I'll try to test changes and make them work on both 1.0.1 and latest master. We can go back to make the compatibility more elegant in future.

@kuke kuke merged commit f90177e into PaddlePaddle:develop May 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants