code: def test_cpu2gpu_gpu2cpu_gradients(self):
      model = model_helper.ModelHelper(name="copy_test")
  
      batch = 32
      cpu_opt = core.DeviceOption(caffe2_pb2.CPU, 0)
      gpu_opt = core.DeviceOption(workspace.GpuDeviceType, 0)
  
      with core.NameScope("cpu"):
          with core.DeviceScope(cpu_opt):
              x_cpu = brew.fc(model, "data", "x_cpu", 16, 8)
  
      with core.NameScope("gpu_0"):
          with core.DeviceScope(gpu_opt):
              x_gpu = model.CopyCPUToGPU(x_cpu, "x_gpu")
              pred_gpu = brew.fc(model, x_gpu, "pred_gpu", 8, 4)
              pred_cpu = model.CopyGPUToCPU(pred_gpu, "pred_cpu")
  
      with core.DeviceScope(cpu_opt):
          with core.NameScope("cpu"):
              (softmax, loss) = model.SoftmaxWithLoss(
                  [pred_cpu, "label"],
                  ["softmax", "loss"],
              )
  
      gradient_map = model.AddGradientOperators([loss])
  
      # Add param updates (for cpu and gpu)
      init_net = model.param_init_net
      with core.DeviceScope(cpu_opt):
          with core.NameScope("cpu"):
              ONE = init_net.ConstantFill(
                  [], "ONE", shape=[1], value=1.0
              )
              LR = init_net.ConstantFill(
                  [], "LR", shape=[1], value=-2.0
              )
              for param in model.GetParams():
                  model.WeightedSum(
                      [param, ONE, gradient_map[param], LR],
                      param,
                  )
  
      with core.NameScope("gpu_0"):
          with core.DeviceScope(gpu_opt):
              ONE = init_net.ConstantFill(
                  [], "ONE", shape=[1], value=1.0
              )
              LR = init_net.ConstantFill(
                  [], "LR", shape=[1], value=-2.0
              )
              for param in model.GetParams():
                  model.WeightedSum(
                      [param, ONE, gradient_map[param], LR],
                      param,
                  )
  
      with core.DeviceScope(cpu_opt):
          workspace.FeedBlob(
              "cpu/data",
              np.random.rand(batch, 16).astype(np.float32),
          )
          workspace.FeedBlob(
              "cpu/label",
              np.random.randint(4, size=batch).astype(np.int32),
          )
  
      workspace.RunNetOnce(model.param_init_net)
      workspace.CreateNet(model.net)
  
      initial_params = {
          p: workspace.FetchBlob(p) for p in model.GetParams()
      }
      workspace.RunNet(model.net.Proto().name)
      updated_params = {
          p: workspace.FetchBlob(p) for p in model.GetParams()
      }
  
      for p in model.GetParams():
          g = gradient_map[p]
          expected = initial_params[p] - 2.0 * workspace.FetchBlob(g)
          actual = updated_params[p]
          self.assertTrue(
              np.array_equal(expected, updated_params[p]),
              "Mismatch: {}: {}, {}".format(p, expected, actual),
          )
  
file_path: pytorch/caffe2/python/operator_test/copy_ops_test.py
imports: import numpy
  import unittest
  from caffe2.proto import caffe2_pb2
  from caffe2.python import workspace, core, model_helper, brew, test_util
label_desc: Use image node_id 7 for calling the CopyOpsTest obj's underlying member method code with example usage: obj.test_cpu2gpu_gpu2cpu_gradients() without return types