Skip to main content

riftco-transformer Python distribution

This package is the typed, runtime-dependency-free ctypes interface to libtransformer_lab_c, plus explicit data preparation, pretraining, post-training, experiment, artifact, generation, and local-serving modules. A platform wheel carries both the Python modules and its native C ABI library; users do not install the native framework separately.

Install

After a release has been published to PyPI:

python3 -m pip install riftco-transformer
python3 -c "from transformer_lab import Context; print(Context().backend)"

riftco-transformer is the installable distribution name; Python code imports the stable transformer_lab package.

The wheel stores libtransformer_lab_c.so, libtransformer_lab_c.dylib, or transformer_lab_c.dll under transformer_lab/.libs. It has no third-party runtime dependencies and needs no compiler or environment variable after installation. Initial binary wheels cover Linux x86_64 and aarch64 for both glibc (manylinux) and musl (musllinux), macOS x86_64 and arm64, and Windows AMD64. CPU is available on every supported platform; the macOS wheels also include Metal.

From a source checkout, install at the repository root with:

python3 -m pip install .

That source build compiles the C++20 implementation, so it needs a supported native compiler and platform SDK. TRANSFORMER_LAB_LIBRARY remains an advanced development override for selecting a particular local native build; released wheels do not require it.

The Python package follows the framework release version (0.1.0 here), while the native C ABI has its own compatibility version (1.8). The client accepts the same ABI major and an equal or newer additive minor, and rejects older or breaking ABIs before use.

Release automation

.github/workflows/release.yml builds and verifies the source distribution and self-contained platform wheels. workflow_dispatch is verification-only. Pushing a v<version> tag creates a GitHub Release after the artifacts pass. It also publishes to PyPI only when the repository variable PUBLISH_TO_PYPI is true.

PyPI publication uses Trusted Publishing rather than a stored API token. The publisher configuration is project riftco-transformer, owner quangng2000, repository transformer-lab, workflow release.yml, and environment pypi. The project is licensed under Apache-2.0. Do not enable publication until the Trusted Publisher is configured.

Selectable tokenizers

Tokenizer offers interchangeable byte and byte-pair-encoding strategies:

from transformer_lab import Tokenizer

with Tokenizer(
    "Hello, café 🙂 Hello again.",
    method="bpe",
    vocabulary_size=272,
    minimum_pair_frequency=2,
) as tokenizer:
    token_ids = tokenizer.encode("café 🙂")
    assert tokenizer.decode(token_ids) == "café 🙂"
    print(tokenizer.method, tokenizer.vocab_size)
    print(tokenizer.vocabulary)

The BPE vocabulary begins with all 256 single-byte tokens and appends learned pair pieces, so unseen bytes remain encodable. vocabulary_size is a maximum: learning can stop earlier when no pair reaches minimum_pair_frequency. Repeated pair counts are resolved deterministically.

For backward compatibility, Tokenizer(corpus) selects the corpus-derived byte method. It assigns IDs by sorted unsigned byte value:

with Tokenizer(b"cab\ncab") as tokenizer:
    assert tokenizer.method == "byte"
    assert tokenizer.vocabulary_bytes == b"\nabc"

Tokenizer accepts a str corpus, encoded as UTF-8, or a bytes/bytearray/memoryview corpus. encode() and decode() are strict UTF-8 conveniences. Use encode_bytes() and decode_bytes() for arbitrary binary data, including embedded NUL bytes. vocabulary returns a tuple of byte pieces for either method; vocabulary_bytes is the byte-only compatibility property.

End-to-end training

An end-to-end BPE training step uses only public Python objects:

from transformer_lab import (
    Adam,
    DecoderOnlyTransformer,
    Tokenizer,
    TransformerConfig,
    cross_entropy,
)

corpus = "hello hello hello"
with Tokenizer(
    corpus,
    method="bpe",
    vocabulary_size=272,
) as tokenizer:
    encoded = tokenizer.encode(corpus)
    tokens = [encoded[:-1]]
    targets = [encoded[1:]]

    config = TransformerConfig(
        vocabulary_size=tokenizer.vocab_size,
        maximum_context=len(tokens[0]),
        model_width=16,
        head_count=4,
        block_count=1,
        feed_forward_width=32,
    )
    with DecoderOnlyTransformer(
        config,
        attention="flash",
        activation_checkpointing="block",
    ).to("cpu") as model:
        with model.parameters() as parameters:
            with Adam(parameters) as optimizer:
                with cross_entropy(model(tokens), targets) as loss:
                    loss_value = loss.item()
                    loss.backward()
                    stats = optimizer.step()
                print(loss_value, stats.gradient_norm)

Change .to("cpu") to .to("metal") on systems with the Metal backend. Computation graphs are single-use: build a fresh forward/loss graph for each training step. attention="flash" selects the dependency-free exact tile-8 full-sequence forward/backward implementation; omit it to keep the "materialized" default. The Flash path saves [batch, heads, time] row maxima and exponential sums and reconstructs probabilities during backward, rather than saving [batch, heads, time, time] probabilities. The explicit probability-returning diagnostic remains materialized. This selector does not change incremental serving, and no speedup is assumed without measuring the target workload.

activation_checkpointing="block" retains only transformer-block boundaries and replays each block during backward. Omit it for the "disabled" default. This reduces retained activation graph state at the cost of another block forward calculation during backward. It composes with FlashAttention and LoRA, but does not affect model artifacts or incremental decode.

On Metal, Flash working storage is proportional to the per-head width and must fit the device's threadgroup-memory limit. The native runtime preflights the complete forward/backward path before starting the forward pass. If the device rejects a very wide head, use more heads or select attention="materialized".

Hugging Face data and rank experiments

The transformer_lab.data package is also dependency-free. Its default transport uses urllib to read bounded pages from the official Hugging Face Dataset Viewer API, while adapters convert TinyStories, Dolly 15K, and HH-RLHF into stage-specific files. Preparation removes exact duplicates, assigns records to deterministic content-hash splits, and writes an atomic directory with a provenance manifest and SHA-256 file digests.

From the framework directory:

PYTHONPATH="$PWD/python" \
python3 examples/python/prepare_huggingface_data.py \
  --preset dolly \
  --output data/external/huggingface/dolly-lora-v1 \
  --limit 2000 \
  --seed lora-v1

HF_TOKEN is an optional environment variable, never a CLI argument. Prepared downloads under data/external/ are ignored by Git. The Dolly adapter maps instruction plus optional context into prompt, preserves response, and retains category. TinyStories becomes plain text. HH-RLHF remains chosen/rejected preference data and is not accepted by the current SFT pipeline.

The transformer_lab.experiments package compares LoRA ranks from the same immutable base:

from transformer_lab.artifacts import ModelBundle
from transformer_lab.experiments import (
    LoraRankExperimentConfig,
    compare_lora_ranks,
    load_prepared_instruction_splits,
)

base = ModelBundle.load("results/stages/tinystories_pretrained.tlab")
splits = load_prepared_instruction_splits(
    "data/external/huggingface/dolly-lora-v1"
)
comparison = compare_lora_ranks(
    base,
    splits,
    LoraRankExperimentConfig(
        ranks=(1, 2, 4, 8),
        alpha_over_rank=2.0,
        steps=20,
        backend="cpu",
    ),
)
print(comparison.best_rank, comparison.selected_test.loss)

Every rank shares data fingerprints, seeds, sampler, optimizer controls, LoRA targets, and alpha / rank. Validation selects the winner; held-out test evaluation begins only after selection. The objective is still full-sequence causal SFT, not response-only loss. All adapters are merged before persistence, so ranks have the same serving topology and inference timings are only smoke measurements. The CLI atomically publishes a new, complete output directory and embeds the verified prepared-data manifest plus its SHA-256 in comparison.json.

See docs/DATASETS_AND_LORA_EXPERIMENTS.md in the framework repository for license links, exact TinyStories train/validation commands, sample-size guidance, provenance details, and the CLI rank workflow.

Staged pipeline

The high-level modules make the stage boundaries explicit:

from transformer_lab.artifacts import ModelBundle
from transformer_lab import LoraConfig
from transformer_lab.post_training import (
    PostTrainingConfig,
    post_train_jsonl,
)
from transformer_lab.pretraining import PretrainingConfig, pretrain_file
from transformer_lab.serving import ServingConfig, serve_model

base = pretrain_file(
    "data/pretraining/tiny_corpus.txt",
    PretrainingConfig(
        steps=20,
        backend="cpu",
        attention="flash",
        activation_checkpointing="block",
    ),
)
base.bundle.save("results/stages/tiny_pretrained.tlab")

restored = ModelBundle.load("results/stages/tiny_pretrained.tlab")
assistant = post_train_jsonl(
    restored,
    "data/post_training/tiny_instructions.jsonl",
    PostTrainingConfig(
        steps=10,
        backend="cpu",
        attention="flash",
        activation_checkpointing="block",
        fine_tuning_method="lora",
        lora=LoraConfig(rank=4, alpha=8.0),
    ),
)
assistant.bundle.save("results/stages/tiny_post_trained.tlab")

serve_model(
    "results/stages/tiny_post_trained.tlab",
    host="127.0.0.1",
    port=8000,
    config=ServingConfig(
        backend="cpu",
        kv_cache="paged",
        kv_cache_block_size=16,
    ),
)

The HTTP adapter serves a dependency-free browser chat at / and keeps POST /v1/generate as the stable JSON generation endpoint. Each chat message is formatted with PlainChatFormatter as one independent single-turn SFT prompt; the visual transcript is not added to the model context. Custom formatter templates are not persisted in the current artifact format. GET /health reports the selected backend, context and vocabulary sizes, and active KV-cache strategy.

ModelBundle persists the exact byte/BPE tokenizer definition, model configuration, named parameter shapes, float32 weights, checksums, stage metadata, and parent artifact ID. It is an immutable inference or warm-start artifact, not a resumable training checkpoint: Adam moments, optimizer step, data position, and random-generator state are deliberately not included yet. LoRA post-training optimizes only adapter factors, then merges them before capturing this ordinary serving-ready bundle. Full-parameter post-training remains the default; adapter-only persistence is not part of ModelBundle.

The first post-training objective is explicitly full_sequence_causal_sft: it applies causal cross-entropy to the complete formatted prompt/response sequence. Response-only loss masking is a future extension.

Incremental generation

Native models use the current ABI 1.8 DecodeSession surface (introduced in ABI 1.6) instead of rerunning the full-sequence training forward for every generated token. TextGenerator creates a request-local session, prefills the prompt one token at a time, and then performs one-token decode:

from transformer_lab.artifacts import ModelBundle
from transformer_lab.serving import TextGenerator

bundle = ModelBundle.load("results/stages/tiny_post_trained.tlab")
with bundle.instantiate("cpu") as runtime:
    result = TextGenerator(
        runtime.model,
        runtime.tokenizer,
        kv_cache="paged",
        kv_cache_block_size=16,
    ).generate("Tensor:", max_new_tokens=32)
    print(result.text)

Paged caching is the default; use kv_cache="contiguous" for the reference strategy. Both run direct CPU or Metal paged decode attention. When the learned absolute-position context fills, TextGenerator resets the cache and replays the retained suffix from position zero. A raw session exposes the lower-level step/reset contract:

with bundle.instantiate("cpu") as runtime:
    with runtime.model.decode_session(
        cache="paged",
        block_size=16,
    ) as session:
        for token in runtime.tokenizer.encode("Tensor:"):
            logits = session.step(token)

The raw session does not tokenize, sample, or implement rollover. Paged storage also does not yet imply continuous batching, a request scheduler, or prefix sharing. Full-sequence attention="flash" does not alter this path: serving prefill is still token-at-a-time and decode remains paged.

See docs/PIPELINE.md, docs/SERVING.md, docs/TOKENIZATION.md, and docs/BACKENDS_AND_PYTHON.md in the framework repository for the complete workflow, lifecycle, backend, and error-handling contracts.

Package layout

The physical package mirrors the runtime boundaries:

transformer_lab/
├── native/          # stable C ABI bindings
├── artifacts/       # ModelBundle persistence
├── data/            # external dataset adapters and preparation
├── experiments/     # controlled LoRA-rank comparisons
├── training/        # shared batches, metrics, and trainer
├── pretraining/     # next-token pretraining stage
├── post_training/   # supervised continuation stage
└── serving/         # generation, model service, and HTTP

The package root still re-exports the original low-level API. transformer_lab.artifact and transformer_lab.generation remain compatibility facades; new code should prefer transformer_lab.artifacts and transformer_lab.serving.

License

Copyright 2026 Quang T Nguyen. Licensed under the Apache License 2.0. The full license text is included in the source distribution and every wheel.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

riftco_transformer-0.1.0.tar.gz (461.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

riftco_transformer-0.1.0-py3-none-win_amd64.whl (249.6 kB view details)

Uploaded Python 3Windows x86-64

riftco_transformer-0.1.0-py3-none-musllinux_1_2_x86_64.whl (1.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

riftco_transformer-0.1.0-py3-none-musllinux_1_2_aarch64.whl (1.3 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

riftco_transformer-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (424.0 kB view details)

Uploaded Python 3manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

riftco_transformer-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (378.8 kB view details)

Uploaded Python 3manylinux: glibc 2.27+ ARM64manylinux: glibc 2.28+ ARM64

riftco_transformer-0.1.0-py3-none-macosx_13_0_x86_64.whl (329.8 kB view details)

Uploaded Python 3macOS 13.0+ x86-64

riftco_transformer-0.1.0-py3-none-macosx_13_0_arm64.whl (309.6 kB view details)

Uploaded Python 3macOS 13.0+ ARM64

File details

Details for the file riftco_transformer-0.1.0.tar.gz.

File metadata

  • Download URL: riftco_transformer-0.1.0.tar.gz
  • Upload date:
  • Size: 461.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for riftco_transformer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bc93ca32680183a34c719c1767b6e2f159e1a95e78dadd500477d76b688ad420
MD5 3b0a21bfa8d1247ef1baa2c7bf9e2dd9
BLAKE2b-256 4566309fc9bb659e0a8094b66c325c980d411894fb8fad981cb13c59fde1846e

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0.tar.gz:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 167a6cf8c2a3d0a304953f52e5e70774be7632a69c4e7fb0f3f4666913e7cc67
MD5 f31d1b371d1a45a4c597069c078fbf23
BLAKE2b-256 13351191e369da33ea441713738b22f7f3bbfd33ab879cfec5ee64cd899bcd94

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-win_amd64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 88cfc3e0a3114d785a3241db20c76c482ad9eed1f9961b66b23567c6f16d3005
MD5 f55840d7d33f0087bd596abb049a4b01
BLAKE2b-256 ca938121f4adf170421db50c362919f3e4606a69788fa64063674514ce4fc764

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-musllinux_1_2_x86_64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 99db6135549b6dccb444d40c43406199a726806b16bad68303e12f9c3efd9ec5
MD5 952c7cea0f33107ebff94df213bfaa1c
BLAKE2b-256 a3eeb1ee09d9e3c9799a84f6d20f396558f91af22acf869ac7e7de6fade9fa05

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-musllinux_1_2_aarch64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c1e28662edbeab58301093a204b70ca8e18af6064331d886e888166119ed7ec5
MD5 1dc1fd9a2425f556edc6784c43daa0f7
BLAKE2b-256 2b475612b15e682ad0f8511b24c83d7f3b12892a1bddf9528ee1d0f95448d379

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 c5044fd1280af9749ab17261c5b7d33a889f2d1568dea54a3f808e4d3882ec9f
MD5 342bc01f2320b06147fc653f7289dbd8
BLAKE2b-256 59b879d74b56dffaa4b1a84fe6aa1d61934176709edde6504851df534301bc01

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 21fac0e3f16ad7471c868f37e48dc9bc16c556ba45acecb99facfc3f30eaaade
MD5 24aa2763bfbf9b4ea095c74b256c4ffa
BLAKE2b-256 249b75545e380d1b81de90acbabd1b8adbe193bd6375d413ed3e25d14158094e

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-macosx_13_0_x86_64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file riftco_transformer-0.1.0-py3-none-macosx_13_0_arm64.whl.

File metadata

File hashes

Hashes for riftco_transformer-0.1.0-py3-none-macosx_13_0_arm64.whl
Algorithm Hash digest
SHA256 56fd037214f04f1ec240ba2c57f6570f0fc5b62db65718a65888704b45ddcd27
MD5 1a9f8a59c1df0c722d8d5428f549c9d5
BLAKE2b-256 07e6e89a65958d20f639f04c85f5947f4a71c2f5c54c34148d4b2c566681bdee

See more details on using hashes here.

Provenance

The following attestation bundles were made for riftco_transformer-0.1.0-py3-none-macosx_13_0_arm64.whl:

Publisher: release.yml on quangng2000/transformer-lab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page