<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def apply_regression(input_, regression_fn, target, regression_args=(), regression_kwargs=None, name=PROVIDED, loss_weight=None, per_example_weights=None):
 """Applies the given regression and adds the loss to the bookkeeper. This does not change tensor. Args: input_: A Tensor or a Pretty Tensor holding the input. regression_fn: A function that takes (in order) tensor, labels. target: The targe of the regression. regression_args: Other arguments for the regression. regression_kwargs: Keyword args for the regression. name: The name, also added to regression_kwargs. loss_weight: A scalar multiplier for the loss. per_example_weights: A Tensor with a weight per example. Returns: The loss tensor's name. Raises: ValueError: If the target is not a compatible shape with input_. """

  if regression_kwargs is None:
    regression_kwargs = {}
  if name is not None and 'name' not in regression_kwargs:
    regression_kwargs['name'] = name
  elif name is None:
    name = input_.tensor.op.name

  tensor = input_.tensor
  loss = regression_fn(tensor, target, *regression_args, **regression_kwargs)
  if loss_weight is not None:
    loss *= loss_weight
  if per_example_weights is not None:
    per_example_weights = _convert_and_assert_per_example_weights_compatible(
        input_,
        per_example_weights,
        dtype=loss.dtype)
    loss *= per_example_weights
  # Use mean so that the learning rate is independent of the batch size.
  if name is None:
    name = loss.op.name
  if tensor.get_shape()[0].value is not None:
    # Try to use division instead of reduce_mean because reduce_mean doesn't
    # work on GPU.
    avg_loss = tf.reduce_sum(loss) / tensor.get_shape()[0].value
  else:
    avg_loss = tf.reduce_mean(loss)
  return input_.add_loss(avg_loss, name=name)