Md. Asif Uddin
Problem I.2.B06

What one perceptron costs, and what a bank of them costs

complexity▲△△

Exact counts.

STATEMENT

Count the parameters and the forward FLOPs of a single perceptron over dd inputs, then extend to a one-vs-rest bank of KK perceptrons. Evaluate at two realistic sizes.

GIVEN

A perceptron y^=sign(w,x+b)\hat{y} = \mathrm{sign}(\langle\vec{w},\vec{x}\rangle + b) with wRd\vec{w} \in \R^{d}. Count a multiply and an add as one FLOP each; ignore the sign, which is one comparison.

FIND

Parameters and FLOPs as functions of dd; then of dd and KK; then numbers at (d,K)=(784,10)(d, K) = (784, 10) and (4096,1000)(4096, 1000).

STRATEGY

Count the arithmetic in the definition literally rather than recalling a rule. The inner product is the only expensive part, and everything else is O(1)O(1).

SOLUTION

Step 1 — one perceptron, parameters. The weight vector holds dd numbers and the bias holds one:

Nparams=d+1N_{\text{params}} = d + 1

Step 2 — one perceptron, FLOPs. The inner product j=1dwjxj\sum_{j=1}^{d} w_j x_j needs dd multiplications and d1d-1 additions. Adding the bias is one more addition, bringing the additions to dd. Total:

NFLOPs=d+d=2dN_{\text{FLOPs}} = d + d = 2d

The convenient way to remember this: one multiply–add per parameter, and there are dd weights doing real work. That rule of thumb survives all the way to Chapter II.8, where the 2N2N per token in C6NDC \approx 6ND is the same count.

Step 3 — a bank of KK. One-vs-rest trains KK independent perceptrons, one per class, each over the same dd inputs. Nothing is shared:

Nparams=K(d+1),NFLOPs=2dKN_{\text{params}} = K(d+1), \qquad N_{\text{FLOPs}} = 2dK

Equivalently the bank is one matrix WRd×K\mat{W} \in \R^{d\times K} and one bias row, so the forward pass is a single (1×d)(d×K)(1\times d)(d\times K) product — the same object as a linear layer in Chapter I.5, arrived at from the other direction.

Step 4 — evaluate.

ddParamsFLOPs
223344
7847847857851,5681{,}568
409640964,0974{,}0978,1928{,}192
ddKKParamsFLOPs
78478410107,8507{,}85015,68015{,}680
40964096100010004,097,0004{,}097{,}0008,192,0008{,}192{,}000

Answer

one:N=d+1,F=2dbank of K:N=K(d+1),F=2dK\text{one:}\quad N = d + 1,\quad F = 2d \qquad\qquad \text{bank of }K:\quad N = K(d+1),\quad F = 2dK

At d=784d = 784, K=10K = 10: 7,8507{,}850 parameters and 15,68015{,}680 FLOPs per example. At d=4096d = 4096, K=1000K = 1000: 4,097,0004{,}097{,}000 parameters and 8,192,0008{,}192{,}000 FLOPs.

Check — numeric · i-2-b06-perceptron-cost.py
params = d + 1
flops  = 2 * d
print(f"d={d} K={K} params {K * (d + 1)} flops {2 * d * K}")

Prints all six rows above.

Executed in CI. The digits above are the digits it printed.

Check — sanity

FLOPs are about twice the parameters. 8,192,000/4,097,000=1.99958{,}192{,}000 / 4{,}097{,}000 = 1.9995, approaching 22 as dd grows because the bias becomes negligible. If your ratio were near 11 or near 44, a multiply or an add went missing.

Both scale linearly in each variable separately. Ten times the classes gives ten times the cost; ten times the input width gives ten times the cost. There is no interaction term, because a one-vs-rest bank shares nothing between classes.

The d=784d = 784, K=10K = 10 figure is checkable against a known object. That is MNIST with a linear classifier, and 7,8507{,}850 is the familiar parameter count for exactly that model. Landing on a number that appears in the literature is weak evidence, but it is evidence.

Where this breaks

The count assumes the input is dense. For sparse x\vec{x} with only sds \ll d non-zeros, the inner product costs 2s2s rather than 2d2d, and a bag-of-words perceptron over a 10610^6-word vocabulary with 2020 words per document costs 4040 FLOPs and not two million. The parameter count is unchanged — the memory is still d+1d+1 — which is why sparsity helps compute far more than it helps storage.

Variation

Add the backward pass. The perceptron rule updates d+1d+1 numbers on a mistake and none otherwise. Compute the expected cost per example when a fraction pp of examples cause updates, and compare with a gradient method that updates on every example.

Draws on