test_onnxifi.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import numpy as np
  2. import time
  3. import unittest
  4. import onnx
  5. import onnx.defs
  6. from onnx.backend.base import namedtupledict
  7. from onnx.helper import make_node, make_graph, make_tensor_value_info, make_model
  8. from caffe2.proto import caffe2_pb2
  9. from caffe2.python import core, workspace
  10. from caffe2.python.models.download import ModelDownloader
  11. from caffe2.python.onnx.onnxifi import onnxifi_caffe2_net
  12. from caffe2.python.onnx.tests.test_utils import TestCase
  13. ONNXIFI_DATATYPE_FLOAT32 = 1
  14. def _print_net(net):
  15. for i in net.external_input:
  16. print("Input: {}".format(i))
  17. for i in net.external_output:
  18. print("Output: {}".format(i))
  19. for op in net.op:
  20. print("Op {}".format(op.type))
  21. for x in op.input:
  22. print(" input: {}".format(x))
  23. for y in op.output:
  24. print(" output: {}".format(y))
  25. class OnnxifiTest(TestCase):
  26. @unittest.skip("Need ONNXIFI backend support")
  27. def test_relu_graph(self):
  28. batch_size = 1
  29. X = np.random.randn(batch_size, 1, 3, 2).astype(np.float32)
  30. graph_def = make_graph(
  31. [make_node("Relu", ["X"], ["Y"])],
  32. name="test",
  33. inputs=[make_tensor_value_info("X", onnx.TensorProto.FLOAT,
  34. [batch_size, 1, 3, 2])],
  35. outputs=[make_tensor_value_info("Y", onnx.TensorProto.FLOAT,
  36. [batch_size, 1, 3, 2])])
  37. model_def = make_model(graph_def, producer_name='relu-test')
  38. op = core.CreateOperator(
  39. "Onnxifi",
  40. ["X"],
  41. ["Y"],
  42. onnx_model=model_def.SerializeToString(),
  43. input_names=["X"],
  44. output_names=["Y"],
  45. output_shape_hint_0=[ONNXIFI_DATATYPE_FLOAT32, batch_size, 1, 3, 2])
  46. workspace.FeedBlob("X", X)
  47. workspace.RunOperatorOnce(op)
  48. Y = workspace.FetchBlob("Y")
  49. np.testing.assert_almost_equal(Y, np.maximum(X, 0))
  50. @unittest.skip("Need ONNXIFI backend support")
  51. def test_conv_graph(self):
  52. X = np.array([[[[0., 1., 2., 3., 4.], # (1, 1, 5, 5) input tensor
  53. [5., 6., 7., 8., 9.],
  54. [10., 11., 12., 13., 14.],
  55. [15., 16., 17., 18., 19.],
  56. [20., 21., 22., 23., 24.]]]]).astype(np.float32)
  57. W = np.array([[[[1., 1., 1.], # (1, 1, 3, 3) tensor for convolution weights
  58. [1., 1., 1.],
  59. [1., 1., 1.]]]]).astype(np.float32)
  60. Y_without_padding = np.array([[[[54., 63., 72.], # (1, 1, 3, 3) output tensor
  61. [99., 108., 117.],
  62. [144., 153., 162.]]]]).astype(np.float32)
  63. graph_def = make_graph(
  64. [make_node(
  65. 'Conv',
  66. inputs=['X', 'W'],
  67. outputs=['Y'],
  68. kernel_shape=[3, 3],
  69. # Default values for other attributes: strides=[1, 1], dilations=[1, 1], groups=1
  70. pads=[0, 0, 0, 0],
  71. )],
  72. name="test",
  73. inputs=[make_tensor_value_info("X", onnx.TensorProto.FLOAT, [1, 1, 5, 5]),
  74. make_tensor_value_info("W", onnx.TensorProto.FLOAT, [1, 1, 3, 3]),
  75. ],
  76. outputs=[make_tensor_value_info("Y", onnx.TensorProto.FLOAT,
  77. [1, 1, 3, 3])])
  78. model_def = make_model(graph_def, producer_name='conv-test')
  79. # We intentional rewrite the input/output name so test that the
  80. # input/output binding of c2 op is positional
  81. op = core.CreateOperator(
  82. "Onnxifi",
  83. ["X0"],
  84. ["Y0"],
  85. onnx_model=model_def.SerializeToString(),
  86. initializers=["W", "W0"],
  87. input_names=["X"],
  88. output_names=["Y"],
  89. output_shape_hint_0=[ONNXIFI_DATATYPE_FLOAT32, 1, 1, 3, 3])
  90. workspace.FeedBlob("X0", X)
  91. workspace.FeedBlob("W0", W)
  92. workspace.RunOperatorOnce(op)
  93. Y = workspace.FetchBlob("Y0")
  94. np.testing.assert_almost_equal(Y, Y_without_padding)
  95. class OnnxifiTransformTest(TestCase):
  96. def setUp(self):
  97. self.model_downloader = ModelDownloader()
  98. def _add_head_tail(self, pred_net, new_head, new_tail):
  99. orig_head = pred_net.external_input[0]
  100. orig_tail = pred_net.external_output[0]
  101. # Add head
  102. head = caffe2_pb2.OperatorDef()
  103. head.type = "Copy"
  104. head.input.append(new_head)
  105. head.output.append(orig_head)
  106. dummy = caffe2_pb2.NetDef()
  107. dummy.op.extend(pred_net.op)
  108. del pred_net.op[:]
  109. pred_net.op.extend([head])
  110. pred_net.op.extend(dummy.op)
  111. pred_net.external_input[0] = new_head
  112. # Add tail
  113. tail = caffe2_pb2.OperatorDef()
  114. tail.type = "Copy"
  115. tail.input.append(orig_tail)
  116. tail.output.append(new_tail)
  117. pred_net.op.extend([tail])
  118. pred_net.external_output[0] = new_tail
  119. @unittest.skip("Need ONNXIFI backend support")
  120. def test_resnet50_core(self):
  121. N = 1
  122. repeat = 1
  123. print("Batch size: {}, repeat inference {} times".format(N, repeat))
  124. init_net, pred_net, _ = self.model_downloader.get_c2_model('resnet50')
  125. self._add_head_tail(pred_net, 'real_data', 'real_softmax')
  126. input_blob_dims = (N, 3, 224, 224)
  127. input_name = "real_data"
  128. device_option = core.DeviceOption(caffe2_pb2.CPU, 0)
  129. init_net.device_option.CopyFrom(device_option)
  130. pred_net.device_option.CopyFrom(device_option)
  131. for op in pred_net.op:
  132. op.device_option.CopyFrom(device_option)
  133. net_outputs = pred_net.external_output
  134. Y_c2 = None
  135. data = np.random.randn(*input_blob_dims).astype(np.float32)
  136. c2_time = 1
  137. workspace.SwitchWorkspace("onnxifi_test", True)
  138. with core.DeviceScope(device_option):
  139. workspace.FeedBlob(input_name, data)
  140. workspace.RunNetOnce(init_net)
  141. workspace.CreateNet(pred_net)
  142. start = time.time()
  143. for _ in range(repeat):
  144. workspace.RunNet(pred_net.name)
  145. end = time.time()
  146. c2_time = end - start
  147. output_values = [workspace.FetchBlob(name) for name in net_outputs]
  148. Y_c2 = namedtupledict('Outputs', net_outputs)(*output_values)
  149. workspace.ResetWorkspace()
  150. # Fill the workspace with the weights
  151. with core.DeviceScope(device_option):
  152. workspace.RunNetOnce(init_net)
  153. # Cut the graph
  154. start = time.time()
  155. pred_net_cut = onnxifi_caffe2_net(pred_net,
  156. {input_name: input_blob_dims},
  157. infer_shapes=True)
  158. del init_net, pred_net
  159. #_print_net(pred_net_cut)
  160. Y_trt = None
  161. input_name = pred_net_cut.external_input[0]
  162. print("C2 runtime: {}s".format(c2_time))
  163. with core.DeviceScope(device_option):
  164. workspace.FeedBlob(input_name, data)
  165. workspace.CreateNet(pred_net_cut)
  166. end = time.time()
  167. print("Conversion time: {:.2f}s".format(end - start))
  168. start = time.time()
  169. for _ in range(repeat):
  170. workspace.RunNet(pred_net_cut.name)
  171. end = time.time()
  172. trt_time = end - start
  173. print("Onnxifi runtime: {}s, improvement: {}%".format(trt_time, (c2_time - trt_time) / c2_time * 100))
  174. output_values = [workspace.FetchBlob(name) for name in net_outputs]
  175. Y_trt = namedtupledict('Outputs', net_outputs)(*output_values)
  176. np.testing.assert_allclose(Y_c2, Y_trt, rtol=1e-3)