human
Complete this python program:
def apply_batch_normalization(computation_graph):
assistant
#Here is the Python code you requested.

    """Transform a graph into a batch-normalized training graph.
    Parameters
    computation_graph : :class:`~blocks.graph.ComputationGraph`
    The computation graph containing :class:`BatchNormalization`
    brick applications.
    Returns
    batch_normed_graph : :class:`~blocks.graph.ComputationGraph`
    The computation graph, with :class:`BatchNormalization`
    applications transformed to use minibatch statistics instead
    of accumulated population statistics.
    See Also
    :func:`batch_normalization`, for an alternative method to produce
    batch normalized graphs.
    Examples
    First, we\ll create a :class:`~blocks.bricks.BatchNormalizedMLP`.
    >>> import theano
    >>> from blocks.bricks import BatchNormalizedMLP, Tanh
    >>> from blocks.initialization import Constant, IsotropicGaussian
    >>> mlp = BatchNormalizedMLP([Tanh(), Tanh()], [4, 5, 6],
    ...                          weights_init=IsotropicGaussian(0.1),
    ...                          biases_init=Constant(0))
    >>> mlp.initialize()
    Now, we\ll construct an output variable as we would normally. This
    is getting normalized by the *population* statistics, which by
    default are initialized to 0 (mean) and 1 (standard deviation),
    respectively.
    >>> x = theano.tensor.matrix()
    >>> y = mlp.apply(x)
    Finally, we\ll create a :class:`~blocks.graph.ComputationGraph`
    and transform it to switch to minibatch standardization:
    >>> from blocks.graph import ComputationGraph
    >>> cg = apply_batch_normalization(ComputationGraph([y]))
    >>> y_bn = cg.outputs[0]
    Let\s verify that these two graphs behave differently on the
    same data:
    >>> import numpy
    >>> data = numpy.arange(12, dtype=theano.config.floatX).reshape(3, 4)
    >>> inf_y = y.eval({x: data})
    >>> trn_y = y_bn.eval({x: data})
    >>> numpy.allclose(inf_y, trn_y)
    False
    """
    from blocks.bricks import BatchNormalization
    from ..filter import VariableFilter, get_application_call
    def make_variable_filter(role):
        return VariableFilter(bricks=[BatchNormalization], roles=[role])
    def get_app_call_dict(variable_filter):
        return collections.OrderedDict(((get_application_call(v), v) for v in variable_filter(computation_graph)))
    (inputs, outputs, means, stdevs) = map(get_app_call_dict, map(make_variable_filter, [INPUT, OUTPUT, BATCH_NORM_OFFSET, BATCH_NORM_DIVISOR]))
    assert (len(set([len(inputs), len(outputs), len(means), len(stdevs)])) == 1)
    app_calls = inputs.keys()
    remove = _training_mode_application_calls(app_calls)
    for app_call in app_calls:
        if (app_call in remove):
            for mapping in (inputs, outputs, means, stdevs):
                del mapping[app_call]
    replacements = []
    for app_call in inputs:
        old_output = outputs[app_call]
        op = inputs[app_call].owner.op
        assert (isinstance(op, theano.tensor.Elemwise) and isinstance(op.scalar_op, theano.scalar.basic.Identity))
        unpacked = inputs[app_call].owner.inputs[0]
        with app_call.application.brick:
            new_output = app_call.application.brick.apply(unpacked)
        new_app_call = get_application_call(new_output)
        assert new_app_call.metadata['training_mode']
        replacements.append((old_output, new_output))
    return computation_graph.replace(replacements)