Skip to content

← Reductions and dim step 5 of 7

Medium Primitives

Per-channel statistics

Jump to the task

For an image batch shaped (batch, channels, height, width), a per-channel mean averages over batch and spatial positions. The channel axis remains:

import torch

x = torch.arange(16, dtype=torch.float32).reshape(2, 2, 2, 2)
y = x.mean(dim=(0, 2, 3))
print(list(y.shape))  # [2]
print(y.tolist())  # [5.5, 9.5]

The tuple names the original axes to reduce. Axis 1, channels, is absent from the tuple and therefore remains in the result.

Why name the axes together?

The starter chains mean(dim=3), mean(dim=2) and mean(dim=0). For this rectangular input, it computes the same mathematical mean: each group at a given stage contains the same number of entries. Floating-point rounding can still differ between implementations.

A tuple makes the intended reduction easier to inspect and avoids tracking how axis numbers change after each step. A wrong index may reduce the wrong axis or raise an error, depending on the remaining rank.

The harness counts dispatched operations. The chained version dispatches three means; the tuple version meets the limit with one mean operation. This count is not a measurement of GPU kernels, memory passes or elapsed time. Benchmark those separately when performance matters.

Keep dimensions for broadcasting

kept = x.mean(dim=(0, 2, 3), keepdim=True)
print(list(kept.shape))  # [1, 2, 1, 1]
centered = x - kept
print(list(centered.shape))  # [2, 2, 2, 2]

Each reduced axis stays present with size one, so the means broadcast back over x. Subtracting them centers each channel; a complete normalization may require additional statistics and scaling. BatchNorm's stored running means are 1-D channel vectors, not this four-dimensional broadcast shape.

Negative indices can name axes relative to the end. For this 4-D input, (0, -2, -1) identifies the same axes as (0, 2, 3). It is not a general solution for arbitrary ranks: extra spatial axes or a different batch layout need a corresponding reduction rule.

Your task

def channel_means(x: torch.Tensor) -> torch.Tensor

Given a floating-point tensor shaped (batch, channels, height, width) with positive dimensions, return a 1-D tensor of length channels containing each channel's mean over batch, height and width. Use at most two dispatched operations on the harness inputs.