Count the FLOPs of one attention layer over n visual tokens, then recount after pruning to a fraction of them, and report the reduction.
Attention has two cost terms with different growth rates. Use this standard count (one multiply-accumulate = 2 FLOPs):
FLOPs(n)=8nd2+4n2d
The projection term is linear in n; the attention term is quadratic. For a language prompt of 30 tokens the linear term dominates completely, but a single AnyRes image is 2000+ visual tokens, and there the quadratic term takes over. That crossover is why visual-token pruning exists at all: dropping tokens buys a superlinear saving, whereas making the model narrower only buys a linear one.
Pruning keeps floor(n * keep_ratio) tokens, and the reduction is:
reduction %=100(1−FLOPs(n)FLOPs(nkept))
Halving the tokens therefore saves strictly more than 50% - and the more quadratic the regime, the closer to 75%.
Implement:
def attention_flops(num_tokens, dim, keep_ratio=1.0):
Return [flops_full, tokens_kept, flops_pruned, reduction_percent] - three ints and a float rounded to 4 decimals.
[int, int, int, float]
print(attention_flops(576, 1024, 0.5))
Output:
[6190792704, 288, 2755657728, 55.4878]
print(attention_flops(576, 1024, 0.5))
[6190792704, 288, 2755657728, 55.4878]
Full cost is 85761024^2 = 4831838208 projections plus 4576^21024 = 1358954496 attention, totalling 6190792704. At 288 tokens both terms shrink - the first by half, the second by four - giving 2755657728, a 55.4878% reduction from halving the tokens.
FLOPs(n) = 8 * n * d * d + 4 * n * n * dtokens_kept = floor(num_tokens * keep_ratio) and is at least 1 for the given inputsreduction_percent is relative to the full count, rounded to 4 decimalskeep_ratio of 1.0 must give a reduction of exactly 0.0