One record, one line, one voice: TorchLens value displays¶
Every user-facing object answers a REPL in one voice (the names are experimental and may change in any release):
- Value-record
repr(x)is one nestable line, up to 100 columns: kind, stored short key, dtype, shape, device, and available value words. - Value-record
str(x)is a bounded card with at most 10 rows below the first line. Its first line is the repr, and itsmorerow names the exits. - Record HTML cards contain those same rows, with no automatic value grid.
- A Trace
str(x)is a bounded card with at most twelve rows below the first line, which is the repr; the module tree stays in.summary(). - Containers point, records show: collection reprs are one-line
composition cards (
LayerAccessor: 553 layers (539 ops, 14 buffers)), with at most five members and.head(),.search()and.to_pandas()exits instr().
The explicit glance core line¶
Generated by the shipped formatter (every specimen in this page is real formatter output, never hand-written):
A: f32[1,64,112,112]@cpu n=803k (3.06 MiB) [-6.000 %%#%###### 7.714] mean=0.8569 sd=4.000 zero=1.03%
U: f32[1,64,112,112]@cpu n=803k (3.06 MiB) [-6.000 <unicode ramp> 7.714] mean=0.8569 sd=4.000 zero=1.03%
ASCII is canonical; the unicode upgrade differs only through the declared
nine-glyph ramp, and ascii == degrade(unicode) is a byte-checked CI
contract. Extremes, the NaN/Inf census, and zero counts are EXACT at
every size; only the sd and histogram may sample above declared gates,
and a sampled family carries the ~ mark with disclosed precision.
Value records¶
A captured op renders:
The card behind it (print(op)) adds position, module, output,
values, graph, function, source, and code rows, then the more exits.
The source row is a captured location. The code row reads fingerprint-checked
source text, or names a changed or missing source file.
Counts in card rows are exact and byte quantities use IEC units (60.0 KiB).
Durations use compact units (4.02 ms); Flops and Macs keep their spelling.
The value words use four significant digits, including trailing zeros.
If the line exceeds 100 columns, it drops mean and sd first, then min
and max in favor of values in print(). Geometry and honesty stay visible.
The explicit tl.stats.glance form retains its sparkline and its ASCII
and Unicode equivalence contract.
Honesty vocabulary (never laundered)¶
(not saved) distinguishes an absent capture from saved-and-boring;
(freed), (disk-backed: metadata only until read),
(preview backend: shape/dtype only), and (edited) retain their meanings.
Value words preserve nonfinite counts, magnitude-based complex statistics,
and (~sampled) even when sampled moments no longer fit.
A saved CPU activation below the existing sampling gate is summarized once
and cached by tensor version. Live parameters, device tensors, and larger
activations show values not computed unless valid cached evidence
already exists. Parameter cards disclose the live basis and version.
Buffers disclose their capture-snapshot basis. Displays never load a lazy
payload to produce a summary.
Multi-pass layers identify their pass count without a pooled statistic;
the card shows up to three per-pass summaries. An individual operation
uses its stored short key and pass suffix, such as tanh_1:2.
What no repr library can say (the forensics exhibit)¶
Real output from a poisoned capture (a 0/0 minted mid-network):
>>> log[bad]
Op truediv_1: float32 [1, 8] on cpu NaN 3, +Inf 5, no finite values
>>> log.first_nonfinite()
First non-finite saved out is in layer truediv_1_4 (op __truediv__, ...), shape=(1, 8),
dtype=torch.float32, parents=relu_1_2, sub_1_3, source=<file>:14.
>>> _ = log.health_facts
>>> log
Trace _poisoned_1: _Poisoned, 7 layers, 5 ops, NaN/Inf found (see .nonfinite_ops)
The flag says there was a crime; TorchLens hands you the crime scene --
in the same one-line language as the health report. Trace rendering reads
cached health evidence and never scans tensors. Until health has been
checked it says NaN/Inf not checked. A clean, fully
checked capture carries the per-trace proof
no NaN/Inf (exact).
The graph-scale table¶
trace.summary(view="stats") renders every retained site through the same
kernel: graph-ordered rows, typed row states (ok / unsaved /
disk_backed / unsupported / unscanned), = parent marks backed by
a capture-path-stable distribution verdict (function semantics +
geometry; payload-pointer comparison is banned), a max_scan_elements= element
budget echoed in the header, and disclosed sampled-column sorts.
"Sortable, exact where it says exact."
The function form¶
torchlens.stats.glance(t) renders the core line for ANY tensor -- the
function, never a monkey-patch (lovely-tensors remains installable
alongside TorchLens). A glanced line is a documented strict subset: no
envelope, no deviation marks, no graph-proven role, and geometry-seeded
sampling. torchlens.stats.narrate(site, sink=print) mounts the same line
as a live per-firing stream on the capture hook surface;
summary_cell / treescope_card_fields are the seam adapters the
summary panel and HTML cards consume, so a number can never exist only
in HTML.
The same stance holds for pictures: tl.viz.rgb(t) and tl.viz.chans(t)
draw a bare tensor as an RGB image or a channel grid, as functions rather
than tensor attributes (Look at a tensor as an
image).
Selections, edits, options and reports¶
Selections report sites and values separately and name the selector that produced them. For a five-token GPT-2 small capture:
print(selection) puts the first three site names and the number omitted
on one sites row, followed by the attributes for further inspection. A dense mask says values not computed
rather than scanning its elements while printing.
Selectors retain parentheses so their constructor spelling rebuilds the same boolean expression. Edits retain their public constructor spelling; tensor arguments use shape, dtype and device without printing elements:
tl.scale(2.0)
tl.project_out(<tensor float32 [4] on cpu>)
tl.when(tl.func('relu'), tl.zero_ablate())
Recipe: 2 rules
A recipe uses tl.when(...) only when that spelling rebuilds it exactly.
Otherwise its repr reports the number of rules; print(recipe) lists at
most five rules. Captured arguments and frozen intervention specs also
show metadata and counts rather than tensor contents or callback dumps.
Captured argument cards show parent display keys and scalar literals,
including literals nested in tuples or lists.
Options show non-default fields in repr. Printing an options object lists
its public fields with non-None values, including defaults. Boolean card values use
words, rows align to the longest field name, and a closing more row points to details:
Doctor, health and compute report reprs show their type, scope and row or finding counts. Summary tables retain their headers and totals, use plain numeric percentages, and explain every displayed marker in one legend. Lookup errors keep the problem first and offer at most five display keys, closest by edit distance first:
Layer 'tanhh_6' not found.
candidates 'tanh_6', 'tanh_1', 'tanh_2', 'tanh_9', 'tanh_11'; and 5 more
remedy pass an in-range integer, a layer label, or a module address
Credits¶
The philosophy this surface mines and extends:
- lovely-tensors (xl0) -- a tensor's default view should be a human
summary, not a wall of digits: the inline sparkline, extremes
bracketing the distribution, count and memory on the line,
all_zeros/emptyspecial cases, omitting the ordinary, dot-verb ergonomics, and repr-as-hot-path cost discipline. - torchsnooper (zasdfgbnm) -- the compact fixed-order form that stays scannable when repeated; dtype and device as the bug-catching fields.
- penzai / treescope -- repr-is-the-product; NaN-as-pattern; collapsed-first rendering.
- flax
tabulate(totals conservation), Keras 3 (footer authority), pysnoopernormalize=True(diffable summaries).
Trace and owned record collections¶
print(trace) shows at most twelve rows below its identity line. The card
contains stored model, capture, graph and save metadata; trace.summary()
provides the module hierarchy. Default pristine state is omitted.
ATen and event tuples keep tuple iteration, equality, hashing and slicing.
Their reprs show only counts, for example AtenOps: 500 calls. Printing
adds at most five identified members, the number omitted, and a closing
more row. An ATen card puts each of its first three tensor inputs on a
separate row, followed by the number omitted. Portable saves encode these sequences as ordinary
tuples, so their display type does not change the artifact format.