Skip to main content

TrainLens

Understand a fine-tuning run, see where it is failing, and decide what to try next — from the notebook.

TrainLens reads training, validation, and held-out test results; understands common fine-tuning evidence from Hugging Face, PEFT/LoRA, Keras, Lightning, and PyTorch-style workflows; plots learning curves; compares runs; and can optionally ask an OpenAI-compatible LLM to turn the local evidence into an improvement plan.

CI PyPI 0.14.2 Python License: Apache-2.0

Try the full notebook workflow

Open In Colab

Install TrainLens with plotting support:

%pip install -q "trainlens[plots]"

Imagine these are the results from a small LoRA/PEFT fine-tuning run. TrainLens accepts normal notebook variables, so you do not need an experiment tracker just to inspect them:

history = {
    "train_loss":     [1.31, 0.93, 0.66, 0.47, 0.34, 0.25],
    "val_loss":       [1.28, 0.91, 0.70, 0.58, 0.55, 0.57],
    "train_accuracy": [0.55, 0.68, 0.79, 0.87, 0.92, 0.95],
    "val_accuracy":   [0.54, 0.66, 0.75, 0.80, 0.82, 0.81],
}

test_metrics = {
    "loss": 0.64,
    "accuracy": 0.75,
    "f1": 0.74,
    "precision": 0.77,
    "recall": 0.72,
}

Analyze the run and plot the curves:

from trainlens import analyze, plot_training_curves, render_report

analysis = analyze(globals())
plot_training_curves(globals())
print(render_report(analysis))

TrainLens keeps the split semantics instead of flattening everything into one metric bag: train_*, validation_*, and test_* remain distinct. It can flag a train/validation generalization gap, notice when the held-out test split is materially worse than validation, and keep F1/precision/recall/perplexity-style final metrics in the structured report.

When a real fine-tuning model/trainer is present, TrainLens can also inspect evidence such as trainable vs. frozen parameters, PEFT adapters, LoRA rank/alpha/targets, quantization, base/projector/vision learning rates, and common VLM fine-tuning strategies.

Ask an LLM what happened and what to try next

The LLM is optional. TrainLens does the deterministic analysis locally first. The model gets a bounded, redacted summary of that evidence and is asked to explain and prioritize it.

1. Load your model without putting the API key in the notebook

from getpass import getpass
from trainlens import OpenAICompatibleProvider

llm = OpenAICompatibleProvider.from_values(
    base_url="https://your-provider.example/v1",
    model="your-model",
    api_key=getpass("LLM API key: "),
)

For a local OpenAI-compatible server such as Ollama, LM Studio, vLLM, or llama.cpp, the same API works and an API key is usually unnecessary:

llm = OpenAICompatibleProvider.from_values(
    base_url="http://localhost:11434/v1",
    model="your-local-model",
)

2. Tell the LLM exactly what kind of training analysis you want

from trainlens import improvement_plan_prompt, prompt_text

prompt = improvement_plan_prompt(
    objective=prompt_text("""
        Explain what happened during this fine-tuning run and propose the three
        highest-value next experiments.

        Use the test split only as final generalization evidence; do not tune to it.
        Prefer controlled, low-cost changes first.
    """),
    model_family="LLM fine-tuning with PEFT/LoRA",
    focus_areas=(
        "train/validation generalization gap",
        "validation-to-test degradation",
        "checkpoint selection and early stopping",
        "learning-rate schedule",
        "regularization and adapter capacity",
    ),
)

prompt_text() is a small convenience for long notebook instructions: write normal triple-quoted multiline text, keep it indented with the surrounding Python, and TrainLens removes the common indentation and outer blank space before the prompt is used. This avoids repeating quotes and implicit string concatenation on every line.

For prompts that are longer, reused across notebooks, or easier to review separately, keep them in UTF-8 .md files and load them directly:

# prompts/improvement_plan.md

Explain what happened during this fine-tuning run and propose the three highest-value next experiments.

Use the test split only as final generalization evidence; do not tune to it.

Prefer:
- controlled experiments
- low-cost changes first
- measurable hypotheses and success criteria
from trainlens import load_prompt

prompt = improvement_plan_prompt(
    objective=load_prompt("prompts/improvement_plan.md"),
    model_family="LLM fine-tuning with PEFT/LoRA",
)

load_prompt() preserves Markdown structure and relative indentation, strips only outer whitespace, and rejects non-.md paths so prompt files stay explicit and easy to version. The repository also includes examples/prompts/improvement_plan.md as a ready-to-copy example.

The improvement recipe asks for the evidence behind every idea, the proposed change, expected effect, cost/risk, confidence, a measurable success criterion, and one concrete next run. Missing hyperparameters must be reported as missing rather than invented.

3. Inspect exactly what will be sent

from trainlens import preview_llm_request

preview = preview_llm_request(
    globals(),
    mode="improvement_ideas",
    provider=llm,
    prompt_options=prompt,
)

print(preview.system_prompt)  # trusted TrainLens instructions
print(preview.user_prompt)    # sanitized notebook evidence

preview_llm_request() makes no network request. It uses the same request-building path as the real provider call, excluding the API key.

4. Generate the explanation and next-step report

from trainlens import build_improvement_ideas

report = build_improvement_ideas(
    globals(),
    provider=llm,
    prompt_options=prompt,
)

report  # native Markdown display in Jupyter

A useful report should explain the observed train/validation/test behavior, distinguish observations from hypotheses, rank improvement ideas, and finish with controlled experiments and measurable success criteria.

Compare two runs too

For a quick baseline-vs-experiment comparison, no LLM or plotting dependency is required:

from trainlens import compare_runs

comparison = compare_runs(
    {"loss": 0.52, "accuracy": 0.84},
    {"loss": 0.41, "accuracy": 0.89},
    baseline_name="baseline",
    experiment_name="new run",
)

comparison  # renders as Markdown in Jupyter

Keep the structured result or export it elsewhere:

from trainlens import render_report

comparison.improvements
comparison.regressions
html = render_report(comparison, format="html")
json_text = render_report(comparison, format="json")

TrainLens also understands richer TrainingRun objects with metric trajectories and configuration changes.

What else can TrainLens do?

  • Analyze train / validation / test results without collapsing their roles.
  • Inspect fine-tuning configuration including PEFT/LoRA, trainable parameters, quantization, frozen components, and common multimodal settings.
  • Plot learning curves with plot_training_curves() via the optional plots extra.
  • Compare runs with metric-aware improvement/regression semantics.
  • Monitor training with built-in and extensible alert detectors.
  • Plan controlled next experiments with objectives, constraints, and Pareto-aware helpers.
  • Author prompts inline or in Markdown files with prompt_text() and load_prompt().
  • Save and load portable runs for repeatable comparisons.
  • Export reports to Markdown, JSON, HTML, and optional PDF.
  • Use an optional LLM to explain deterministic findings and propose evidence-backed next steps through any OpenAI-compatible endpoint.

Local analysis is deterministic and does not make an LLM request.

Deeper API

Privacy

LLM support is optional. When enabled, TrainLens minimizes and bounds notebook evidence, redacts secrets, and keeps notebook-derived evidence separate from trusted system instructions. Treat generated explanations as assistance and verify them against the underlying training evidence.

Scope

TrainLens is a lightweight notebook reporting and experiment-understanding layer, not a full MLOps platform. It is designed for research and small-to-medium workflows where the important training context already lives in Python and Jupyter.

Contributing and license

See CONTRIBUTING.md to contribute and SECURITY.md to report vulnerabilities.

TrainLens is licensed under the Apache License 2.0.

Metadata

Release files for trainlens 0.14.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trainlens 0.14.2
File Size Uploaded
trainlens-0.14.2.tar.gz 140.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trainlens 0.14.2
File Interpreter ABI Platform
trainlens-0.14.2-py3-none-any.whl Python 3 none any Details

Total release size: 239.8 kB

Release files / trainlens-0.14.2.tar.gz

Download URL trainlens-0.14.2.tar.gz
Size 140.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5550eb8b96d4ded22e5f3cf12ad76f7f529c519857aeb9e216d7d28430656509
BLAKE2b-256 checksum
How to use checksums
e743696b57c5c7831727667346c50ac422f7a8037c2acdcb1e25a11b9dcd6fde
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / trainlens-0.14.2-py3-none-any.whl

Download URL trainlens-0.14.2-py3-none-any.whl
Size 99.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1ea9e40818c78402250b96d46671217f7140549eaa08ce80a436d4eb69432fc0
BLAKE2b-256 checksum
How to use checksums
2559390ae8d5b2ca0f0c02d167b35d0e0156d7872737b00f03fc85f996467949
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page