Card

The model card an artifact carries, and what it is not allowed to say

Overview

The reference is named on the card, so meta['reference'] carries a name, the k/n it was measured on, and the same criteria as a row (bytes, params, macs, peak_activation_bytes); without the first three render_card raises rather than compare to something anonymous.

A row carries the k and n its top-1 was measured on and, when the producer measured one, the wilson interval around it, as the pair of fractions the harness returns. Anything else a row carries — a delta against the reference, its bounds, a target the variant aimed for — is ignored: the card reports the top-1 the artifact reaches, not a gap on it, and it names no objective. meta['ladder'] lists the sibling variants of the same source model so a reader can pick the point that suits them; the top-1 it shows is the worst published form of each repository, which is what the header says, and a variant without a count reads n/a. A row may also carry notes, each sentence rendered as its own paragraph under the row’s table.

The front matter carries a license: key only once a person has validated it: with license={'id': ..., 'validated_by': ''} the key is left out and the provenance block says the license is not yet validated, so the Hub never shows a license nobody checked. base_model: follows the same rule for a different reason — the Hub only accepts one of its own model ids there, so a source named by its factory (torchvision.models.resnet18 (IMAGENET1K_V1)) is written as Source model in the provenance block instead, where it says as much and breaks nothing.

The card carries four criteria and nothing else: top-1, size (on disk and in weights), memory (peak live activations for one image) and MACs. The top-1 is absolute — the accuracy this artifact reaches, with its 95 % interval in brackets and the number of images it was measured on, above the table and never against a reference. The other three are shown three times — the reference, this artifact, and the gap between them — so a number is never read alone. Sizes are megabytes, counts are millions. The gap is a signed percentage, never an N× ratio: a model that is 74 % smaller is not a model that runs four times faster.

recipe is optional — what produced the weights belongs on the card only when it helps the reader — and so is gate: pass the rows run_gate returned and the card carries one line, Publication checks: 10/10 structural checks passed., without their evidence, which belongs in the run log. The line names what it counts: the conditions are structural — no accuracy verdict hides behind the count.

render_card writes the card from measured values only: every number in it comes from meta, there is no default that could be mistaken for a measurement. A reference value the producer did not measure renders n/a, and a latency that was not measured is written not measured, never 0.

check_card reads a card back and returns what a reader should not have to trust: the phrases in FORBIDDEN, and any speedup claim on a line that does not name both a device and a runtime — 2.3x faster says nothing, and so does 2.3x on CPU; 2.3x on CPU with onnxruntime says where it was measured.


source

render_card

def render_card(
    meta:dict, # name, base_model, license (a string, or id and validated_by), datasets, tags, scope_line, input_shape, rows, latency, provenance, optional recipe, ladder and gate, and reference: name, k, n, bytes, params, macs, peak_activation_bytes
)->str:

Render the model card: front matter, scope, the absolute top-1, the three criteria against the reference, latency and provenance


source

check_card

def check_card(
    text:str, # the card to read back
)->list[str]:

Every forbidden phrase and every speedup claim without both a device and a runtime on its line; empty when the card is clean


Usage

from fastermodels import render_card, check_card

meta = {
    'name': 'resnet18-pruned', 'base_model': 'torchvision/resnet18', 'license': 'bsd-3-clause',
    'datasets': ['frgfm/imagenette'], 'tags': ['fasterai', 'pruning'],
    'scope_line': 'Imagenette, n=3925; pipeline evidence, not a published claim.',
    'input_shape': '3x160x160',
    'reference': {'name': 'resnet18 fine-tuned on Imagenette', 'k': 3700, 'n': 3925,
                  'bytes': 44_726_568, 'params': 11_181_642, 'macs': 1_824_000_000,
                  'peak_activation_bytes': 3_211_264},
    'rows': [{'artifact': 'pruned FP32', 'file': 'model.safetensors', 'params': 8_900_000, 'bytes': 35_600_000,
              'macs': 1_368_000_000, 'peak_activation_bytes': 2_408_448,
              'k': 3680, 'n': 3925, 'wilson': (0.9296, 0.9447)}],
    'latency': None,
    'provenance': {'fasterai': '0.4.0', 'fastermodels': '0.1.0', 'torch': '2.9.1', 'measured_on': '2026-09-11'},
}

card = render_card(meta)
check_card(card)   # [] — nothing a reader has to take on trust
Top-1: 93.8 % [93.0, 94.5] on 3925 images

| criterion | reference | this artifact | gap |
|---|---|---|---|
| size | 44.7 MB, 11.2 M params | 35.6 MB, 8.9 M params | -20.4 % |
| memory | 3.2 MB | 2.4 MB | -25.0 % |
| MACs | 1.82 G | 1.37 G | -25.0 % |

Every value in rows and in reference is measured by the producer: the top-1 counts and the interval around them come from the harness, params, macs and peak_activation_bytes from the functions of the same name, and bytes is the size of the file on disk. Keys the card does not show are ignored. The card is written to README.md in the artifact directory, which is also what the Hub shows.


See Also

  • Eval - where k, n, the delta and the agreement come from
  • Gate - condition 7 refuses to publish a card check_card flags
  • Model - the artifact the card describes
  • Measurement - the on-device measurement rows a latency comes from

Tests live in nbs/tests/test_card.ipynb.