def activation_channels_apoz(activation):
    """Calculate the APoZ of each of an activation's channels.

    APoZ is the Average Percentage of Zeros (or simply: average sparsity) and is defined in:
    "Network Trimming: A Data-Driven Neuron Pruning Approach towards Efficient Deep Architectures".

    The activation usually has the shape: (batch_size, num_channels, h, w).

    "We first use global average pooling to convert the output of layer i, which is a
    c x h x w tensor, into a 1 x c vector."

    Returns - for each channel: the batch-mean of its sparsity.
    """
    if activation.dim() == 4:
        view_2d = activation.view(-1, activation.size(2) * activation.size(3))
        featuremap_apoz = view_2d.abs().gt(0).sum(dim=1).float() / (activation
            .size(2) * activation.size(3))
        featuremap_apoz_mat = featuremap_apoz.view(activation.size(0),
            activation.size(1))
    elif activation.dim() == 2:
        featuremap_apoz_mat = activation.abs().gt(0).sum(dim=1).float(
            ) / activation.size(1)
    else:
        raise ValueError('activation_channels_apoz: Unsupported shape: '.
            format(activation.shape))
    return 100 - featuremap_apoz_mat.mean(dim=0).mul(100).cpu()
