Coming from flax tabulate¶
This page is for people who print model tables with Flax's nnx.tabulate (or Linen's
Module.tabulate) and now have a PyTorch model. tl.summary(model, x) is the counterpart:
one call runs the model on a real input and returns one table with a row per module, its
output shape and its parameters, and a totals footer. The Flax example was written against
the Flax release TorchLens's JAX backend tests pin (flax==0.12.8 with jax[cpu]==0.10.2)
and skips where Flax is not installed. Checked 2026-11-03.
The same task in both¶
The task: the table of a two-layer network, and its total parameter count.
In Flax¶
# migration-test: tool=flax expected=True
import jax.numpy as jnp
from flax import nnx
class MLP(nnx.Module):
def __init__(self, rngs):
self.linear1 = nnx.Linear(8, 16, rngs=rngs)
self.linear2 = nnx.Linear(16, 4, rngs=rngs)
def __call__(self, x):
return self.linear2(nnx.relu(self.linear1(x)))
table = nnx.tabulate(MLP(nnx.Rngs(0)), jnp.zeros((2, 8)))
RESULT = "Total Parameters: 212" in table
In TorchLens¶
# migration-test: tool=torchlens expected=(212, 848, True)
import torch
from torch import nn
import torchlens as tl
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(8, 16)
self.linear2 = nn.Linear(16, 4)
def forward(self, x):
return self.linear2(torch.relu(self.linear1(x)))
report = tl.summary(MLP(), torch.zeros(2, 8), columns=["+input"])
RESULT = (report.total_params, report.totals.params_bytes, "linear1 (Linear)" in report)
print(report) shows:
MLP | input (2, 8) float32 | eval mode, no_grad, state restored
view: hybrid, all 3 ops
name (type) input output params (%) fwd flops
----------------------------------------------------------------
linear1 (Linear) (2, 8) (2, 16) 144 ##. 67.9% 544
relu_1_2 (2, 16) (2, 16) - - 32
linear2 (Linear) (2, 16) (2, 4) 68 #.. 32.1% 264
----------------------------------------------------------------
Params 212 declared | trainable 212 (100%) | size 848 B
Compute 840 FLOPs fwd (fma=2) | 384 MACs | 3/3 ops known (formula-exact)
The footer goes on with Memory, Graph and Capture lines (left out here). The functional
torch.relu gets its own row because it belongs to no module; Flax's table has no row for
nnx.relu for the same reason, and TorchLens shows it so that every executed operation is
counted once.
Translation table¶
flax tabulate |
TorchLens tl.summary |
Notes |
|---|---|---|
nnx.tabulate(model, x) |
tl.summary(model, x) |
Both run the model on the input. TorchLens returns the report (a str subclass) instead of a string, and prints nothing until you print it. |
path column |
name column |
The attribute name, indented by depth. |
type column |
the (type) part of name (type) |
The module class. |
inputs column |
columns=["+input"] |
Shapes of the distinct tensors entering the row. |
outputs column |
output column |
Shapes only; the input dtype is in the header line. |
One column per variable type (Param, ...) with shapes, count and bytes |
params column (count per module path) and (%); bytes in the Params footer (size 848 B, report.totals.params_bytes) |
Per-tensor shapes are not a column: read model.named_parameters(). Tied weights are counted once and named. |
BatchStat column |
Not a column | BatchNorm running statistics are registered buffers in PyTorch, not parameters, so params does not count them; trace.buffers lists them (buffers). |
RngState column |
No counterpart | PyTorch modules hold no random-number state; dropout draws from the global generator. |
compute_flops=True (flops column) |
fwd flops column, in the default view; view="compute" adds macs and the evidence class |
Counted from the executed operations, not compiled cost analysis. |
compute_vjp_flops=True (vjp_flops column) |
Not a summary column | After a captured backward, tl.report.cost_tree(trace) reports executed backward FLOPs per module call (self_backward_flops; backward). |
depth=2 |
depth=2 |
depth="all" for the full tree. |
row_filter= |
where= (regex, selector or callable) |
Totals stay whole-model, and the header says what share the shown rows cover. |
method="encode" |
No counterpart | TorchLens runs the module's forward; wrap another method in a small module whose forward calls it. |
table_kwargs=, column_kwargs=, console_kwargs= (rich) |
report.print(), report.render("unicode"), report.to_markdown(), report.to_html() |
No rich dependency; str(report) is byte-stable ASCII. |
Total row and the Total Parameters: N (size) line |
Params footer line | report.total_params and report.totals hold the numbers as plain values. |
What TorchLens adds¶
- Executed FLOPs and true MACs per row, with an evidence class per row, and a Compute footer that names any operation it could not count instead of skipping it.
- Rows for functional operations that belong to no module, and parameters that never ran split out by name.
- The report as data:
report.to_pandas(),report.to_dict(), and the totals as plain ints. - A capture under the table:
tl.trace(model, x)keeps every operation's output for inspection, andtrace.summary()prints the same kind of table for it.
What flax tabulate does that TorchLens does not¶
- It summarizes Flax and JAX models. TorchLens summarizes PyTorch models; its JAX backend is
a preview that captures functions and Equinox and Flax NNX modules, without
nnx.tabulate's table (JAX backend), and replacingnnx.tabulateis not a goal (non-goals). - It shows every variable collection, including random-number state, as its own column.
- It estimates backward FLOPs in the same table.
Quantized models¶
The table above is for ordinary floating-point models. For a quantized model TorchLens
reports what the capture recorded, and quantized activation metadata is best-effort today
(the quantized_tensor row of the capability table in the repository's top-level LIMITATIONS.md). There is no
bits-per-weight line in the footer: that line needs quantized capture TorchLens does not yet provide.
Using both¶
Keep nnx.tabulate for the Flax model and use tl.summary for its PyTorch port. Comparing
Total Parameters with report.total_params is a quick check that a port has the same
parameters; the per-row counts show where a difference sits.
Semantic differences¶
- Flax's
Totalrow adds up every variable column the table shows, so batch statistics count toward it. TorchLens'sparamsandsizecount parameters only; a BatchNorm layer's running statistics are buffers and sit outside both. For the network above both tools report 212 parameters and 848 bytes. - TorchLens runs the model in eval mode with gradients off by default
(
execution_mode="eval") and restores its state afterwards; passexecution_mode="same"to keep the model's own flags. - Repeated modules fold into one row (
h.0..11 (GPT2Block x12)) unlessfold_repeats=False.