code: def test_convolution_sum_relu_fusion(
      self,
      stride,
      pad,
      kernel,
      size,
      input_channels,
      output_channels,
      batch_size,
      use_bias,
      group,
      sum_add,
      gc,
      dc,
  ):
      conv_S0 = core.CreateOperator(
          "Conv",
          ["SX0", "Sw0", "Sb0"] if use_bias else ["SX0", "Sw0"],
          ["S0"],
          stride=stride,
          pad=pad,
          kernel=kernel,
          group=group,
          device_option=dc[0],
      )
      conv = core.CreateOperator(
          "Conv",
          ["X0", "w0", "b0"] if use_bias else ["X0", "w0"],
          ["Y0"],
          stride=stride,
          pad=pad,
          kernel=kernel,
          group=group,
          device_option=dc[0],
      )
      sum = core.CreateOperator(
          sum_add, ["S0", "Y0"], ["S0"], device_option=dc[0]
      )
      relu = core.CreateOperator(
          "Relu", ["S0"], ["S0"], device_option=dc[0]
      )
  
      # Manual fusion for Conv + Sum + ReLU
      conv_S1 = core.CreateOperator(
          "Conv",
          ["SX1", "Sw1", "Sb1"] if use_bias else ["SX1", "Sw1"],
          ["S1"],
          stride=stride,
          pad=pad,
          kernel=kernel,
          group=group,
          device_option=dc[1],
      )
      conv_fusion = core.CreateOperator(
          "ConvFusion",
          ["X1", "w1", "b1", "S1"] if use_bias else ["X1", "w1", "S1"],
          ["S1"],
          stride=stride,
          pad=pad,
          kernel=kernel,
          group=group,
          fusion_type=3,
          device_option=dc[1],
      )
      SX = (
          np.random.rand(
              batch_size, input_channels * group, size, size
          ).astype(np.float32)
          - 0.5
      )
      Sw = (
          np.random.rand(
              output_channels * group, input_channels, kernel, kernel
          ).astype(np.float32)
          - 0.5
      )
      Sb = (
          np.random.rand(output_channels * group).astype(np.float32)
          - 0.5
      )
      X = (
          np.random.rand(
              batch_size, input_channels * group, size, size
          ).astype(np.float32)
          - 0.5
      )
      w = (
          np.random.rand(
              output_channels * group, input_channels, kernel, kernel
          ).astype(np.float32)
          - 0.5
      )
      b = (
          np.random.rand(output_channels * group).astype(np.float32)
          - 0.5
      )
  
      old_ws_name = workspace.CurrentWorkspace()
      workspace.SwitchWorkspace("_device_check_", True)
      workspace.FeedBlob("SX0", SX, dc[0])
      workspace.FeedBlob("Sw0", Sw, dc[0])
      workspace.FeedBlob("Sb0", Sb, dc[0])
      workspace.FeedBlob("X0", X, dc[0])
      workspace.FeedBlob("w0", w, dc[0])
      workspace.FeedBlob("b0", b, dc[0])
      workspace.RunOperatorOnce(conv_S0)
      workspace.RunOperatorOnce(conv)
      workspace.RunOperatorOnce(sum)
      workspace.RunOperatorOnce(relu)
      S0 = workspace.FetchBlob("S0")
  
      workspace.ResetWorkspace()
      workspace.FeedBlob("SX1", SX, dc[1])
      workspace.FeedBlob("Sw1", Sw, dc[1])
      workspace.FeedBlob("Sb1", Sb, dc[1])
      workspace.FeedBlob("X1", X, dc[1])
      workspace.FeedBlob("w1", w, dc[1])
      workspace.FeedBlob("b1", b, dc[1])
      workspace.RunOperatorOnce(conv_S1)
      workspace.RunOperatorOnce(conv_fusion)
      S1 = workspace.FetchBlob("S1")
  
      if not np.allclose(S0, S1, atol=0.01, rtol=0.01):
          print(S1.flatten())
          print(S0.flatten())
          print(np.max(np.abs(S1 - S0)))
          self.assertTrue(False)
  
      # Auto fusion for Conv + Sum + ReLU
      workspace.ResetWorkspace()
      old_net = caffe2_pb2.NetDef()
      conv_S0_old = caffe2_pb2.OperatorDef()
      conv_S0_old.CopyFrom(conv_S0)
      conv_S0_old.device_option.CopyFrom(dc[1])
      conv_old = caffe2_pb2.OperatorDef()
      conv_old.CopyFrom(conv)
      conv_old.device_option.CopyFrom(dc[1])
      sum_old = caffe2_pb2.OperatorDef()
      sum_old.CopyFrom(sum)
      sum_old.device_option.CopyFrom(dc[1])
      relu_old = caffe2_pb2.OperatorDef()
      relu_old.CopyFrom(relu)
      relu_old.device_option.CopyFrom(dc[1])
      old_net.op.extend([conv_S0_old, conv_old, sum_old, relu_old])
      workspace.FeedBlob("SX0", SX, dc[1])
      workspace.FeedBlob("Sw0", Sw, dc[1])
      workspace.FeedBlob("Sb0", Sb, dc[1])
      workspace.FeedBlob("X0", X, dc[1])
      workspace.FeedBlob("w0", w, dc[1])
      workspace.FeedBlob("b0", b, dc[1])
      net = core.Net("net")
      net.Proto().CopyFrom(old_net)
      optimizeForMKLDNN(net)
      self.assertTrue(len(net.Proto().op) == 2)
      self.assertTrue(net.Proto().op[1].type == "ConvFusion")
      workspace.RunNetOnce(net.Proto())
      # The output tensor name will be changed by optimization
      # sometimes when applying conv sum fusion
      S2 = workspace.FetchBlob(net.Proto().op[-1].output[0])
      if not np.allclose(S0, S2, atol=0.01, rtol=0.01):
          print(S2.flatten())
          print(S0.flatten())
          print(np.max(np.abs(S2 - S0)))
          self.assertTrue(False)
  
      workspace.SwitchWorkspace(old_ws_name)
  
file_path: pytorch/caffe2/python/ideep/convfusion_op_test.py
imports: import unittest
  import hypothesis.strategies
  from hypothesis import given
  import numpy
  import math
  from caffe2.proto import caffe2_pb2
  from caffe2.python import core, workspace
  from caffe2.python.transformations import optimizeForMKLDNN
  import caffe2.python.hypothesis_test_util
  import caffe2.python.ideep_test_util
label_desc: Use image node_id 3 for calling the ConvFusionTest obj's underlying member method code with example usage: obj.test_convolution_sum_relu_fusion(stride, pad, kernel, size, input_channels, output_channels, batch_size, use_bias, group, sum_add, gc, dc) without return types