Library / SDK
xl0/lovely-tensors avatar
xl0/lovely-tensors

Lovely Tensors: Replacing PyTorch's Raw Tensor Dump with a One-Line Summary

Tensors, for human consumption

1,394 stars22 forksJupyter NotebookMIT

At a glance

What is it?
Lovely Tensors is a small MIT-licensed Python library that monkey-patches PyTorch tensors so that printing one shows shape, dtype, memory, range, a sparkline histogram and mean/std instead of a wall of numbers. It is a debugging convenience, not a numerical tool, and its cost is a global patch plus a dependency on experimental named-tensor APIs.
Who is it for?
Adopt Lovely Tensors if you spend notebook time squinting at truncated tensor dumps and you are willing to accept a global monkey patch and an experimental-feature warning in exchange for a compact repr. Do not adopt it if you need a stable, importable formatting API, if you cannot tolerate a library that mutates torch.Tensor's repr process-wide, or if your workflow depends on named tensors in production code.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 159 days ago.
What is it written in?
Mainly Jupyter Notebook, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: a tensor dump tells you nothing about the tensor

The README opens with the exact failure it targets. You dump a tensor into a notebook cell and get pages of floats, truncated with ellipses, wrapped across lines. The README asks the reader directly: "Was it really useful for you, as a human, to see all these numbers?" Then it lists what you actually wanted to know. What is the shape? The size? The statistics? Are any values nan or inf? Is it an image of a man holding a tench? Those four questions map one-to-one onto the library's features, which is a cleaner design statement than most READMEs manage. The audience is narrow and specific: people writing PyTorch code interactively, in Jupyter or IPython, who print tensors as a first-line debugging move. If you debug by attaching a profiler or a debugger, this library does not address your workflow. It addresses the print statement.

What the repr actually contains

After lt.monkey_patch(), a 3x196x196 float tensor prints as a single line: tensor[3, 196, 196] n=115248 (0.4 MiB) x∈[-2.118 |▂▅█▇▂▁▁▂▂▁| 2.640] μ=-0.388 σ=1.073. Read left to right, that is shape, element count, memory footprint, min and max, a nine-column sparkline of the value distribution, mean and standard deviation. The sparkline is the part that earns its place. A min/max pair cannot distinguish a tensor with two outliers from one with a smooth spread, and the sparkline makes that visible at a glance. Special values get flagged inline rather than buried: the README's deliberately corrupted tensor prints +Inf! -Inf! NaN! appended to the summary line. An all-zero tensor prints all_zeros instead of a range, which is a small touch that saves a real class of confusion, since a zero tensor and a tiny tensor look similar in raw output. Short tensors still print their values when there are few enough of them, as the six-element example shows. The library decides, not you, and that threshold is not documented in the material supplied.

The escape hatches: .v, .p, .deeper, .rgb, .plt

The patched repr is the default, not the only view. The README shows .p for the plain old way and .v for verbose, which prints the summary line followed by the full tensor. So the compact form never locks you out of the raw values, which matters because the summary is lossy by construction. .deeper walks one dimension down and prints a summary per slice, and it takes a depth argument: named_numbers.deeper(2) shows the top-level tensor, then each H=196, W=196 slice, then individual W=196 rows, stopping at ten and eliding the rest with an ellipsis. For a 3x196x196 image tensor that is the difference between knowing the overall mean and seeing that one channel is shifted. .rgb and .plt are the visualization paths, rendering a tensor as an image and as a plot respectively. The README shows the outputs as figures rather than describing them, so the exact rendering behavior for non-image shapes is something you would need to check yourself.

Gradients and named dimensions in the same repr

The gradient example is the most interesting design decision here. A tensor with requires_grad=True prints grad=None before backpropagation, grad (non-leaf) AddBackward0 for an intermediate node, and after .backward() the gradient is summarized inline as a nested block with its own range, sparkline, mean and standard deviation, plus an -Inf! flag when a gradient element is set to negative infinity. Calling .zero_() on the gradient flips that nested block to all_zeros. This collapses a two-step inspection (print the tensor, then print tensor.grad) into one line, and it surfaces the non-leaf case explicitly, which is a common source of confusion when someone tries to read .grad on an intermediate tensor and finds nothing there. Named dimensions also flow through: numbers.rename("C", "H", "W") produces tensor[C=3, H=196, W=196], and .deeper respects those names in the nested output. The cost is visible in the README itself. Renaming triggers a UserWarning from torch/_tensor.py stating that named tensors and their associated APIs are an experimental feature and subject to change. That warning is PyTorch's, not Lovely Tensors', but the library's named-dimension feature inherits it.

Install and the one call that changes everything

Installation is three documented options: pip install lovely-tensors, mamba install lovely-tensors, or conda install -c conda-forge lovely-tensors. Use is two lines: import lovely_tensors as lt, then lt.monkey_patch(). That second call is the whole integration, and it is also the whole risk. It mutates the repr behavior of torch.Tensor process-wide, so every tensor printed anywhere in that interpreter, including inside third-party libraries and test assertions, gets the new format. The README also shows a config(color=False) context manager in the gradient example, commented out, which suggests a configuration surface exists but is not documented in the material provided. If you need the summary only at specific call sites rather than globally, the README does not show a non-patching accessor for it. That absence is the main thing to check before adopting.

Where it is the wrong tool

The library is a display layer, and it behaves like one. Everything it prints is a summary computed at repr time, so on a large tensor you are paying a reduction pass over the data every time a cell echoes. In a notebook that is fine. In a loop that prints a tensor each iteration, or in a logging handler that formats tensors, that cost multiplies, and the README says nothing about it. The monkey patch is global and irreversible in the sense that the README shows no documented undo. If your test suite asserts on tensor string output, patching will break those assertions, and the fix is to not patch in that process rather than to configure around it. The named-dimension support rides on a PyTorch API that warns it is experimental and should not be used for anything important, which is a fair description of the risk: the feature works, but its stability is PyTorch's to decide. And the library only knows about PyTorch. The README points to sibling projects for NumPy, JAX and TinyGrad, which means a mixed-framework codebase needs several patches, each with its own behavior.

The alternative you probably already have

The realistic alternative is not another library. It is writing the three lines yourself: print(t.shape, t.dtype, t.min(), t.max(), t.mean(), t.std()), or wrapping that in a helper function in your project. That approach is explicit, scoped to the call sites you choose, testable, and carries no dependency. What it does not give you is the sparkline histogram, the automatic NaN and Inf flags, the all_zeros detection, the nested gradient summary, the named-dimension passthrough, or the .deeper slice walk. Those are the parts that are tedious to reimplement well, and the sparkline in particular is the kind of thing you write once and then stop maintaining. So the honest comparison is: a helper function covers the shape and statistics case in about five lines, and Lovely Tensors covers that case plus the four features above, at the price of a global patch and a dependency. If your debugging is mostly shape and range checks, the helper wins. If you regularly stare at distributions, gradients, or per-channel statistics, the library is doing real work.

Licence, maintenance and what to check before you commit

The licence is MIT, which permits commercial and closed-source use and requires only that the copyright notice and permission notice be preserved. That is a permissive, low-friction choice, and it is the same licence family as PyTorch itself, so there is no compatibility question to resolve. The repository is not archived and the last push is dated 2026-04-09, so the project is active as of that date; no releases were retrieved in the material supplied, which means the install path is the package index rather than a pinned version list. The README is autogenerated, as its own header warning states, and the documentation lives at xl0.github.io/lovely-tensors rather than in the repository file, so the README is a summary of a larger doc set you should read before relying on any specific behavior. The maintenance cost for an adopter is close to zero: two lines, no configuration file, no service. The upgrade risk is the monkey patch itself. A PyTorch change to the tensor repr machinery, or to the named-tensor API the library builds on, is the failure surface, and the experimental warning quoted above is the concrete sign of it. Pin your PyTorch version in CI if you patch there, and check that your test suite does not assert on raw tensor strings.

Editorial conclusion

Adopt Lovely Tensors if you spend notebook time squinting at truncated tensor dumps and you are willing to accept a global monkey patch and an experimental-feature warning in exchange for a compact repr. Do not adopt it if you need a stable, importable formatting API, if you cannot tolerate a library that mutates torch.Tensor's repr process-wide, or if your workflow depends on named tensors in production code. Before committing, verify three things in your own environment: that lt.monkey_patch() does not break any repr you rely on in tests, that numbers.rgb and numbers.plt render correctly for your tensor shapes, and that the named-dimension path does not emit the PyTorch experimental-feature warning into logs you parse.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. xl0/lovely-tensors on GitHub
Community notes

Community notes