Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Files, caches and pretrained models

This chapter covers how a name such as tiny or hf:openai/whisper-tiny becomes a loaded model: what a name means, who answers it, where the files land, and why bunsen trusts them once they are there. The reference is bunsen::data, whose lifecycle diagram links every step, and bunsen::data::pretrained.

The kits show three sizes of the same machinery. default_resnet_factory is the simple case: one compiled-in table of torchvision and timm checkpoints. default_whisper_factory is the full one: a compiled-in table, a bundled row, and Hugging Face repos. default_silero_factory is the smallest: one compiled-in row, upstream’s 16 kHz checkpoint.

The pathway

spec ("tiny", "hf:org/repo")
  │  the kit's factory asks its providers
  ▼
row: a name over a map of pinned resources
  │  paired with the kit's hook, optionally overlaid
  ▼
deferred model
  │  plan, bring the files local through the cache, construct
  ▼
loaded model, behind an Arc

A PretrainedFactory is the one object a caller holds for a kit, and its load runs the whole pathway. A file on disk does not go through the factory at all: it is a given map (ResourceMap::given), loaded the same way from the deferred step on.

Prefabs, rows and resources

Three things are kept apart, because they vary independently:

  • A prefab is a geometry by name, with no weights, so a name means a shape before anything is fetched. A kit keeps its prefabs in a StaticPreFabMap.
  • A row, a Pretrained, is a name in a provider, with its aliases, the prefab it instantiates, and the resource maps it is made of.
  • A resource, a Resource, is one file: the key the kit reads it by, the SHA-256 that pins it, a kind label, and the places it can be had from, in order.

One prefab has many rows, in many providers. One file can serve many rows: Whisper’s two vocabulary files serve its twelve checkpoints, each as a resource map of its own that the rows reference. Rows, maps and resources know nothing about how a model is built: that is the kit’s business. They are plain serde data, so a manifest can carry them (prefabs, rows and resources).

Providers

A PretrainedProvider is a namespace of rows: the provider in provider:ref. Three are in use. well-known: holds the compiled-in rows. bundled: holds the rows a build ships with, registered under a kit’s *-weights feature. hf:, an HfProvider, is a Hugging Face repo, by org/repo.

A factory holds a kit’s providers in search order. A spec whose prefix names a registered provider goes to that provider, and nowhere else. Any other spec is offered whole to each provider that answers bare names, in order, and the first row wins. A hub never answers a bare name, so hf: is only reached when the spec names it. The two kinds of “no” are kept distinct. A provider that doesn’t have the row says so (Ok(None)), and the search moves on. A provider that fails returns an error, and the error aborts the lookup, because a hub that cannot be reached is not the same as a hub that has no such row (dispatch).

There is no process-wide registry. Each kit ships a default_{kit}_factory(), and a caller that wants another provider adds it to that factory (no registry).

The cache and its trust model

A PretrainedCache keeps each pinned file at <cache>/pretrained/<kit>/<namespace>/<sha256>/<file>. The digest in the path is the pin. A file there was verified when it was written, so later runs trust it without re-hashing gigabytes, and a model whose pin changes can never collide with a stale copy. The cache trusts the path whoever wrote it: a download, bundled bytes, or a build script or a deployment that laid the directory out ahead of time (trust model).

The cache looks at that path first, then at a resource’s local sources, and only then at its URLs (source order). A local directory, such as openai-whisper’s own cache, is a “trust me” source: its file is used in place and hashed only when the cache’s options ask for verification. Nothing is linked or copied into the cache, and only a download or bundled bytes write there. Downloads need the fetch feature. Without it, or on an offline cache, a file that only a URL can supply is reported as not found (features).

Bundling is a populated cache directory

Because the cache trusts its layout, shipping a model with a build does not need a special kind of source. It needs a cache directory that is already full. bunsen_bundled_whisper fetches Whisper’s base files at build time into its build directory, laid out as a cache, and a PretrainedCache rooted there finds them without knowing they were bundled. An offline deployment does the same thing at install time: fill a cache directory ahead of time, and point the cache at it.

The other form links the bytes into the binary: a Source::Bundled, checked against its digest and written into the cache on first use. Both forms are described under the cache and bundles.

Deferred models and the kit’s hook

What a name resolves to is a Deferred model: the row’s map, plus the kit’s Construct hook. The hook is chosen for the map by for_map, from the resources’ kinds, because rows from different providers can need different readers: an OpenAI .pt checkpoint and a Hugging Face safetensors repo are both Whisper, read two ways.

Loading runs three steps. The hook’s plan completes the map and checks what the row promises, such as its prefab, before any bytes are fetched. The cache then brings the files local. Finally the hook’s construct builds the model from them. Before loading, a caller can lay its own resources over the row’s with with_overlay, where the caller’s resource wins by key. bunsen-asr whisper’s --vocab flag works this way.

PyTorch checkpoints

An OpenAI .pt checkpoint is read through burn-store’s PyTorch reader, behind the store_pytorch feature, and a Hugging Face safetensors repo through its safetensors reader, behind store_safetensors (features). The PyTorch reader honours each tensor’s strides, so a weight that PyTorch saved as a transposed view of another tensor loads as the weight it is.

The operational view

bunsen-asr shows the machinery from the outside. Each family’s list shows its rows and where each one’s files stand, and its fetch brings a model’s resources local; bunsen-asr whisper inspect checks a checkpoint against its prefab, and bunsen-asr whisper prefabs lists the geometries; bunsen-asr cache lists and clears what the cache holds. Its README explains Whisper’s index.