Skip to main content

A lightweight library to manage reproducible experiments.

Project description

expyro ๐Ÿงชโœจ

A lightweight Python library to stop your experiments from being a hot mess. Because "it worked on my machine" is not a valid scientific publication.

expyro is your new lab assistant ๐Ÿง‘โ€๐Ÿ”ฌ that automatically organizes your chaos: configurations, results, plots, and even that random log file you swear you'll look at later.

Features at a Glance ๐Ÿ‘€

  • ๐Ÿ—‚๏ธ Structured Experiment Tracking: No more final_final_v2_test.py files. Each run gets its own fancy, timestamped folder. Look organized, even if you're not.
  • ๐ŸŽฏ Type Safety: Your config isn't just a bunch of random numbers. It's a well-defined bunch of random numbers! Thanks, type hints!
  • โ™ป๏ธ Reproducibility: Relive the magic (or the horror) of any past run. Perfect for when your advisor asks "can we get the results from last Tuesday?".
  • ๐Ÿ“Š Artifact Generation: Automatically save your beautiful plots and tables. Make your future thesis-writing self cry tears of joy.
  • ๐Ÿ’พ Data Capture: Easily dump any other file (models, logs, a screenshot of your error) right into the experiment's folder.

Installation ๐Ÿ’ป

Get the core package and become 10x more organized instantly:

pip install expyro

Want More? We Got More! ๐ŸŸ

Level up your experiment-fu with optional extras:

# For making pretty, pretty plots (matplotlib)
pip install "expyro[matplotlib]"

# For turning results into sweet, sweet tables (pandas)
pip install "expyro[pandas]"

# I want it ALL! ๐Ÿค‘
pip install "expyro[all]"

Quickstart: From Chaos to Clarity in 60 Seconds โฑ๏ธ

1. Define Your Experiment ๐Ÿงช

Decorate your experiment function. It's like putting a lab coat on it.

from dataclasses import dataclass
from pathlib import Path
import expyro

# Step 1: Define your config. This is your recipe.
@dataclass
class TrainConfig:
    learning_rate: float = 0.01 # The spice of life
    batch_size: int = 32        # The bigger, the better (until it crashes)
    epochs: int = 10            # The "are we there yet?" parameter

# Step 2: Declare your experiment. Give it a home ("runs/") and a name.
# Your experiment must take exactly one argument as a config.
# The input and output must be typed. 
@expyro.experiment(root=Path("runs"), name="my_awesome_experiment")
def train_model(config: TrainConfig) -> dict[str, float]:
    # Your brilliant (or "it should work") experiment logic goes here.
    final_loss = 0.1 * config.learning_rate
    final_accuracy = 0.9

    # Return whatever you want to remember
    return {"final_loss": final_loss, "final_accuracy": final_accuracy}

2. Run It! ๐Ÿƒโ€โ™‚๏ธ

Call your experiment. Watch the magic happen.

if __name__ == "__main__":
    cfg = TrainConfig(learning_rate=0.01, batch_size=32, epochs=10)
    run = train_model(cfg) # This saves everything! You're welcome.
    print(f"Run completed! Data is chilling in: {run.path}")

3. Make It Fancy! ๐ŸŽจ

Automatically save plots and tables. Impress everyone.

import matplotlib.pyplot as plt
import pandas as pd

# Artist function: Takes config & result, returns a masterpiece (figure) or even a nested string dict of masterpieces
def create_plot(config: TrainConfig, result: dict) -> plt.Figure:
    fig, ax = plt.subplots()
    ax.bar(["Loss", "Accuracy"], [result["final_loss"], result["final_accuracy"]])
    ax.set_title("How Did We Do?")
    return fig

# Analyst function: Takes config & result, returns a sweet, sweet table (or a nested string dict of tables)
def create_table(config: TrainConfig, result: dict) -> pd.DataFrame:
    return pd.DataFrame([{"metric": k, "value": v} for k, v in result.items()])

# Stack decorators like a pro! The order is bottom-up.
@expyro.plot(create_plot, file_format="pdf") # Save a high-res PDF
@expyro.table(create_table)                  # Save a CSV table
@expyro.experiment(root=Path("runs"), name="fancy_experiment")
def train_and_analyze(config: TrainConfig) -> dict:
    # ... your code ...
    return {"final_loss": 0.1, "final_accuracy": 0.9}

4. Pre-Bake Configs ๐Ÿฑ

Got favorite settings you keep typing over and over? Stash them as defaults and summon them later from the command line (see below).

@expyro.defaults({
    "config-1": TrainConfig(learning_rate=0.1, batch_size=32, epochs=5),
    "config-2": TrainConfig(learning_rate=0.001, batch_size=64, epochs=20),
})
@expyro.experiment(root=Path("runs"), name="experiment_with_defaults")
def train_with_defaults(config: TrainConfig) -> dict:
    # ... your code ...
    return {"final_loss": 0.1}

5. Save ALL THE THINGS! ๐Ÿ’พ

Use hook to save anything else right into the experiment's folder.

@expyro.experiment(root=Path("runs"), name="experiment_with_everything")
def train_with_logging(config: TrainConfig) -> dict:
    # Save a log file
    with expyro.hook("logs/training_log.txt", "w") as f:
        f.write(f"Let's hope this LR {config.learning_rate} works...\n")
        f.write("Epoch 1: Loss=0.5 ๐Ÿ˜ฌ\n")
        f.write("Epoch 2: Loss=0.2 ๐Ÿ˜Š\n")

    # Save a model file (pytorch example)
    # with expyro.hook("best_model.pt", "wb") as f:
    #    torch.save(model.state_dict(), f)

    return {"final_loss": 0.1}

5. Analyze Your Glory (or Mistakes) ๐Ÿ”

Iterate over past runs like a data archaeologist.

# Your experiment is now also a container for all its runs!
my_experiment = train_model # This is your decorated function

print("Behold, all my past runs:")
for run in my_experiment: # ๐Ÿš€ Iterate over everything!
    print(f"Run {run.path.name}: Config={run.config}, Result={run.result}")

# Load a specific run from its path
that_one_run = my_experiment["2024-05-27/12:30:45.123 abcdef00"]
print(f"Ah yes, the run where loss was: {that_one_run.result['final_loss']}")

What's In The Box? ๐Ÿ“ฆ (The Project Structure)

Hereโ€™s how expyro organizes your brilliance:

runs/
โ””โ”€โ”€ my_awesome_experiment/    # Your experiment name
    โ””โ”€โ”€ 2024-05-27/           # The date (so you know when you did the work)
        โ”œโ”€โ”€ 12:30:45.123 abcdef00/        # Time & unique ID (so you can find it)
        โ”‚   โ”œโ”€โ”€ config.pickle             # ๐Ÿ—ƒ๏ธ Your configuration, pickled.
        โ”‚   โ”œโ”€โ”€ result.pickle             # ๐Ÿ“Š Your results, also pickled.
        โ”‚   โ”œโ”€โ”€ artifacts/
        โ”‚   โ”‚   โ”œโ”€โ”€ plots/                # ๐ŸŽจ Home for your beautiful graphs
        โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ create_plot.pdf
        โ”‚   โ”‚   โ””โ”€โ”€ tables/               # ๐Ÿ“‹ Home for your elegant tables
        โ”‚   โ”‚       โ””โ”€โ”€ create_table.csv
        โ”‚   โ””โ”€โ”€ data/                     # ๐Ÿ’พ Your custom files live here (from `hook`)
        โ”‚       โ””โ”€โ”€ logs/
        โ”‚           โ””โ”€โ”€ training_log.txt
        โ””โ”€โ”€ 14:22:10.456 1a2b3c4d/        # Another run! You've been busy!
            โ”œโ”€โ”€ config.pickle
            โ””โ”€โ”€ result.pickle

CLI Time Travel Machine โณ๐Ÿ’ป

Prefer the command line life? expyro scans your project for decorated experiments and hands each one its own subcommand. It's like giving every lab rat a keyboard. ๐Ÿ€

# Run a fresh experiment
expyro my_awesome_experiment run --learning-rate 0.01 --batch-size 32

# Kick off a run using a pre-baked config
expyro my_awesome_experiment default config-1

# Reproduce an old run with the exact same config
expyro my_awesome_experiment reproduce "2024-05-27/12:30:45.123 abcdef00"

# Redo an artifact when you forgot to save that plot ๐ŸŽจ
expyro my_awesome_experiment redo plots "2024-05-27/12:30:45.123 abcdef00"

Why so many verbs? Because reproducibility is king ๐Ÿ‘‘:

  • run starts a brand-new adventure and saves everything.
  • default grabs a config registered with @expyro.defaults and runs it - no flags needed.
  • reproduce reruns an experiment with the original config, giving you a carbon-copy run for free.
  • redo regenerates plots or tables for an existing run, so you can tweak your visuals without touching the science.

All from the shell, all consistent, all reproducible. ๐Ÿ”

For detailed information for your specific setup, run

expyro --help

from the root directory of your project.

License ๐Ÿ“„

MIT License. Go forth and experiment! Just maybe use this library first.


Now go forth and reproduce! ๐Ÿš€

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

expyro-0.0.0.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

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

expyro-0.0.0-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file expyro-0.0.0.tar.gz.

File metadata

  • Download URL: expyro-0.0.0.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for expyro-0.0.0.tar.gz
Algorithm Hash digest
SHA256 f7a4867c2b048569cd4f917b63fc2098c1b80e0c65285d55c75a41a773685e93
MD5 445cba146693daf141b2d9b89a07d647
BLAKE2b-256 20c2ef3261d8d1cb2c24823147b4f7212d23e08b2cff160d2933bf2ca1a58aa2

See more details on using hashes here.

Provenance

The following attestation bundles were made for expyro-0.0.0.tar.gz:

Publisher: pypi-release.yml on lukashaverbeck/expyro

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

File details

Details for the file expyro-0.0.0-py3-none-any.whl.

File metadata

  • Download URL: expyro-0.0.0-py3-none-any.whl
  • Upload date:
  • Size: 13.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for expyro-0.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8bc157a7df325ca5fd3a1ec652270dc3cc092cb318c2ee22f3f8359b7a9cd1c2
MD5 d4b3776686bebbc7af8bfcbf1c948fc2
BLAKE2b-256 688c70a336f0d4d3792663597d06de7580d80b6640e8a0f8e6f679562005e6f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for expyro-0.0.0-py3-none-any.whl:

Publisher: pypi-release.yml on lukashaverbeck/expyro

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 Pingdom Monitoring Sentry Error logging StatusPage Status page