Skip to main content

Simple experiment logging library

Project description

expt_logger

Simple experiment tracking for RL training with a W&B-style API.

Quick Start

Install:

uv add expt-logger
# or
pip install expt-logger

Set your API key:

export EXPT_LOGGER_API_KEY=your_api_key

Start logging:

import expt_logger

# Initialize run with config
run = expt_logger.init(
    name="grpo-math",
    config={"lr": 3e-6, "batch_size": 8}
)

# Get experiment URLs
print(f"View experiment: {run.experiment_url}")
print(f"Base URL: {run.base_url}")

# Log RL rollouts with rewards
expt_logger.log_rollout(
    prompt="What is 2+2?",
    messages=[{"role": "assistant", "content": "The answer is 4."}],
    rewards={"correctness": 1.0, "format": 0.9},
    mode="train",
    commit=True  # Commit immediately and increment step
)

# Log scalar metrics
expt_logger.log({
    "train/loss": 0.45,
    "train/kl": 0.02,
    "train/reward": 0.85
}, commit=True)  # Commit and increment step

expt_logger.end()

Core Features

Scalar Metrics

Log training metrics with automatic step tracking:

# Batch multiple metrics at the same step (default behavior)
expt_logger.log({"loss": 0.5})
expt_logger.log({"accuracy": 0.9})
expt_logger.commit()  # Commits both at step 1, then increments to step 2

# Or commit immediately with commit=True
expt_logger.log({"loss": 0.4}, commit=True)  # Commits at step 2, increments to 3

# Use slash prefixes for train/eval modes
expt_logger.log({
    "train/loss": 0.5,
    "eval/loss": 0.6
}, step=10, commit=True)

# Or set mode explicitly
expt_logger.log({"loss": 0.5}, mode="eval", commit=True)

Note: Metrics default to "train" mode when no mode is specified and keys don't have slash prefixes.

Note: commit=False is now the default. Call expt_logger.commit() to batch multiple logs at the same step, or use commit=True for immediate commits.

Rollouts (RL-specific)

Log conversation rollouts with multiple reward functions:

# Batch multiple rollouts at the same step
expt_logger.log_rollout(
    prompt="Solve: x^2 - 5x + 6 = 0",
    messages=[
        {"role": "assistant", "content": "Let me factor this..."},
        {"role": "user", "content": "Can you verify?"},
        {"role": "assistant", "content": "Sure! (x-2)(x-3) = 0..."}
    ],
    rewards={
        "correctness": 1.0,
        "format": 0.9,
        "helpfulness": 0.85
    },
    mode="train"  # commit=False by default
)

expt_logger.log_rollout(
    prompt="Another problem...",
    messages=[{"role": "assistant", "content": "Solution..."}],
    rewards={"correctness": 0.8},
    mode="train"
)

expt_logger.commit()  # Commits both rollouts at the same step

# Or commit immediately with commit=True
expt_logger.log_rollout(
    prompt="Yet another...",
    messages=[{"role": "assistant", "content": "Answer..."}],
    rewards={"correctness": 1.0},
    step=5,
    mode="train",
    commit=True
)
  • Messages format: List of dicts with "role" and "content" keys
  • Rewards format: Dict of reward names to float values
  • Mode: "train" or "eval" (default: "train")
  • Commit: False (default) to batch, True to commit immediately

Configuration

Track hyperparameters and update them dynamically:

run = expt_logger.init(config={"lr": 0.001, "batch_size": 32})

# Update config during training
run.config.lr = 0.0005              # attribute style
run.config["epochs"] = 100          # dict style
run.config.update({"model": "gpt2"}) # bulk update

API Key & Server Configuration

API Key (required):

export EXPT_LOGGER_API_KEY=your_api_key

Or pass directly:

expt_logger.init(api_key="your_key")

Custom server URL (optional, for self-hosting):

export EXPT_LOGGER_BASE_URL=https://your-server.com

Or:

expt_logger.init(base_url="https://your-server.com")

Accessing Experiment URLs

Get the experiment URL and base URL from the run object:

run = expt_logger.init(name="my-experiment")

# Get the full experiment URL to view in browser
print(run.experiment_url)
# https://expt-platform.vercel.app/experiments/ccf1f879-50a6-492b-9072-fed6effac731

# Get the base URL of the tracking server
print(run.base_url)
# https://expt-platform.vercel.app

API Reference

expt_logger.init()

init(
    name: str | None = None,
    config: dict[str, Any] | None = None,
    api_key: str | None = None,
    base_url: str | None = None,
    auto_flush_interval: float = 10.0,
    auto_flush_buffer_size: int = 100
) -> Run
  • name: Experiment name (auto-generated if not provided)
  • config: Initial hyperparameters
  • api_key: API key (or set EXPT_LOGGER_API_KEY)
  • base_url: Custom server URL (or set EXPT_LOGGER_BASE_URL)
  • auto_flush_interval: Seconds to wait before auto-flushing (default: 10.0)
  • auto_flush_buffer_size: Number of items that trigger immediate flush (default: 100)

expt_logger.log()

log(
    metrics: dict[str, float],
    step: int | None = None,
    mode: str | None = None,
    commit: bool = False
)
  • metrics: Dict of metric names to values
  • step: Step number (auto-increments if not provided)
  • mode: Default mode for keys without slashes (default: "train")
  • commit: If False (default), buffer metrics until commit() is called. If True, commit immediately and increment step.

expt_logger.log_rollout()

log_rollout(
    prompt: str,
    messages: list[dict[str, str]],
    rewards: dict[str, float],
    step: int | None = None,
    mode: str = "train",
    commit: bool = False
)
  • prompt: The prompt text
  • messages: List of {"role": ..., "content": ...} dicts
  • rewards: Dict of reward names to values
  • step: Step number (uses current step if not provided)
  • mode: "train" or "eval"
  • commit: If False (default), buffer rollout until commit() is called. If True, commit immediately and increment step.

expt_logger.commit()

commit()

Commit all pending metrics and rollouts to the buffer and increment the step counter. This allows you to batch multiple log() and log_rollout() calls at the same step.

expt_logger.flush() / expt_logger.end()

  • flush(): Manually send buffered data to server
  • end(): Finish the run (called automatically on exit)

Note: Data is automatically flushed to the server using a debouncing mechanism:

  • Every auto_flush_interval seconds after new data is logged (default: 10 seconds)
  • Immediately when the buffer reaches auto_flush_buffer_size items (default: 100 items)
  • On program exit or when end() is called

Advanced

Context Manager

Ensures automatic cleanup:

with expt_logger.init(name="my-run") as run:
    expt_logger.log({"loss": 0.5})
    expt_logger.commit()
# end() called automatically

Graceful Shutdown

The library handles cleanup on:

  • Normal exit (atexit)
  • Ctrl+C (SIGINT)
  • SIGTERM

All buffered data is flushed before exit.

Development

For local development, see DEVELOPMENT.md.

Run the demo:

python demo.py          # GRPO-style training simulation
python demo.py commit   # Batching demo
python demo.py messages # Structured messages demo

Project details


Download files

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

Source Distribution

expt_logger-0.1.0.dev5.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

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

expt_logger-0.1.0.dev5-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file expt_logger-0.1.0.dev5.tar.gz.

File metadata

  • Download URL: expt_logger-0.1.0.dev5.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.13

File hashes

Hashes for expt_logger-0.1.0.dev5.tar.gz
Algorithm Hash digest
SHA256 862961a4ba64a62b25109e286f3946f6905ee9bc58daa8ef7bc0112b7582187d
MD5 d55e2818a66d57b307cedebdecc58ec6
BLAKE2b-256 e180310afa48a5815ad86f9408b606c10f87cc358e923699150bc31ba337d2bb

See more details on using hashes here.

File details

Details for the file expt_logger-0.1.0.dev5-py3-none-any.whl.

File metadata

File hashes

Hashes for expt_logger-0.1.0.dev5-py3-none-any.whl
Algorithm Hash digest
SHA256 5417e9b37ce7be4f9a59d6c71c2879cea0292b47b087861a3f102e5c8467ba3f
MD5 1a8506683b9b05d68c90db8d6126ac38
BLAKE2b-256 b51c02596002b511c393e1eb5f96df0cfea2c99ae2dc787009cc421f30dd0b4f

See more details on using hashes here.

Supported by

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