Clone variables unused by the attack on all GPUs. Specifically, the
    ground-truth label, y, has to be preserved until the training step.

    :param inputs: A list of dictionaries as the inputs to each step.
    :param outputs: A list of dictionaries as the outputs of each step.
    :param g0_inputs: Initial variables to be cloned.
    :return: Updated inputs and outputs.

def clone_g0_inputs_on_ngpus(self, inputs, outputs, g0_inputs):
    """
    Clone variables unused by the attack on all GPUs. Specifically, the
    ground-truth label, y, has to be preserved until the training step.

    :param inputs: A list of dictionaries as the inputs to each step.
    :param outputs: A list of dictionaries as the outputs of each step.
    :param g0_inputs: Initial variables to be cloned.
    :return: Updated inputs and outputs.
    """
    assert len(inputs) == len(outputs), (
        'Inputs and outputs should have the same number of elements.')

    inputs[0].update(g0_inputs)
    outputs[0].update(g0_inputs)

    # Copy g0_inputs forward
    for i in range(1, len(inputs)):
      # Create the graph for i'th step of attack
      device_name = inputs[i]['x'].device
      with tf.device(device_name):
        with tf.variable_scope('step%d' % i):
          for k, v in g0_inputs.iteritems():
            if k not in inputs[i]:
              v_copy = clone_variable(k, v)
              inputs[i][k] = v_copy
              outputs[i][k] = v_copy

    return inputs, outputs