Md. Asif Uddin
    Problem I.5.B03

    A shape and parameter audit of a four-layer MLP

    shape▲△△

    Exact integer counts; memory in decimal megabytes.

    STATEMENT

    Audit a classifier layer by layer: the shape of every matrix, the shape of every intermediate, the parameter count of each layer and of the whole model, and the memory that model occupies in fp32. Then answer the question the audit exists to answer — where is the money.

    GIVEN

    An MLP with widths

    (d0,d1,d2,d3,d4)=(784, 512, 256, 128, 10)(d_0, d_1, d_2, d_3, d_4) = (784,\ 512,\ 256,\ 128,\ 10)

    Four affine layers, ReLU after the first three, no activation on the head. One example at a time, so the input is a row x∈R1×784\vec{x} \in \R^{1 \times 784}.

    FIND

    A table of W(ℓ)\mat{W}^{(\ell)} and b(ℓ)\vec{b}^{(\ell)} shapes, the shape of each a(ℓ)\vec{a}^{(\ell)}, per-layer and total parameter counts, the fp32 size, and the share of the total held by the first layer.

    STRATEGY

    Count with equation (I.5.2), one layer at a time. The two habits worth building are writing the bias into the count rather than waving it away, and checking that each layer’s output shape is the next layer’s input shape before adding anything up.

    SOLUTION

    Step 1 — shapes. A layer holds W(ℓ)∈Rdℓ−1×dℓ\mat{W}^{(\ell)} \in \R^{d_{\ell-1} \times d_\ell} and b(ℓ)∈R1×dℓ\vec{b}^{(\ell)} \in \R^{1 \times d_\ell}, and the row passing through is (1×dℓ−1)(dℓ−1×dℓ)→(1×dℓ)(1 \times d_{\ell-1})(d_{\ell-1} \times d_\ell) \to (1 \times d_\ell).

    ℓ\ellW(ℓ)\mat{W}^{(\ell)}b(ℓ)\vec{b}^{(\ell)}a(ℓ)\vec{a}^{(\ell)}
    1784×512784 \times 5121×5121 \times 5121×5121 \times 512
    2512×256512 \times 2561×2561 \times 2561×2561 \times 256
    3256×128256 \times 1281×1281 \times 1281×1281 \times 128
    4128×10128 \times 101×101 \times 101×101 \times 10

    Every inner dimension meets. The batch dimension is untouched throughout, which is what makes the same weights work for one example or ten thousand.

    Step 2 — parameters, layer by layer. dℓ−1dℓ+dℓd_{\ell-1}d_\ell + d_\ell:

    784⋅512+512=401 408+512=401 920784 \cdot 512 + 512 = 401\,408 + 512 = 401\,920

    512⋅256+256=131 072+256=131 328512 \cdot 256 + 256 = 131\,072 + 256 = 131\,328

    256⋅128+128=32 768+128=32 896256 \cdot 128 + 128 = 32\,768 + 128 = 32\,896

    128⋅10+10=1 280+10=1 290128 \cdot 10 + 10 = 1\,280 + 10 = 1\,290

    Step 3 — the total.

    N=401 920+131 328+32 896+1 290=567 434N = 401\,920 + 131\,328 + 32\,896 + 1\,290 = 567\,434

    Step 4 — memory. At 4 bytes per fp32 parameter, 567 434×4=2 269 736567\,434 \times 4 = 2\,269\,736 bytes: 2.272.27 MB, or 2.1652.165 MiB. Training with Adam multiplies that by roughly four, since the optimiser carries two moment estimates alongside the gradient — a point Chapter I.7 makes properly.

    Step 5 — where the money is.

    401 920567 434=70.83%\frac{401\,920}{567\,434} = 70.83\%

    The first layer holds seven parameters in ten. It is not the widest layer and it is not doing the classification; it is simply the one facing the input, and the input is 784 numbers wide. This is the general shape of the bill: an MLP pays for its interface with the data.

    Answer

    ℓ\ellshapeparameters
    1784×512784 \times 512401 920401\,920
    2512×256512 \times 256131 328131\,328
    3256×128256 \times 12832 89632\,896
    4128×10128 \times 101 2901\,290
    total567 434\mathbf{567\,434}

    2 269 7362\,269\,736 bytes in fp32, which is 2.272.27 MB. The first layer holds 70.83%70.83\% of the model.

    Check — sanity

    The chain of shapes closes. 784→512→256→128→10784 \to 512 \to 256 \to 128 \to 10, with each layer’s output width equal to the next layer’s input width, and the final width equal to the number of classes. A single mismatch anywhere would make the model unrunnable, so this check is free and catches most typing errors.

    The biases are a rounding error, and are still counted. 512+256+128+10=906512 + 256 + 128 + 10 = 906 of 567 434567\,434, or 0.16%0.16\%. They are cheap, which is a reason to keep them rather than a reason to omit them from the count — and I.5.X03 shows what dropping them costs.

    The layer sizes fall as the widths multiply out. 401 920:131 328:32 896:1 290401\,920 : 131\,328 : 32\,896 : 1\,290 is close to 4:1.3:0.33:0.0134 : 1.3 : 0.33 : 0.013, matching the products 784⋅512784 \cdot 512, 512⋅256512 \cdot 256, 256⋅128256 \cdot 128, 128⋅10128 \cdot 10. Parameters track the product of adjacent widths, exactly as (I.5.2) says.

    Where this breaks

    The count is a count of parameters, and parameters are only one of three things that occupy memory. Activations scale with the batch: at batch 1024 the intermediates alone are 1024×(512+256+128+10)×4=3 710 9761024 \times (512 + 256 + 128 + 10) \times 4 = 3\,710\,976 bytes, more than the model. Optimiser state scales with the parameters. Gradients match the parameters again. Quoting a parameter count as though it were a memory requirement is the most common way to underestimate what a model needs by an order of magnitude — and the ratio is worst exactly where it matters, which is during training rather than inference.

    Variation

    Re-audit with widths (784,2048,10)(784, 2048, 10) — a wider model with one hidden layer instead of three. Compare the totals before computing them, then check the prediction. Which is larger, and by how much?

    Draws on