Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,15 @@ using scikit-learn and logs the results to W&B.
cd examples/examples/scikit/scikit-housing
python train.py
```

## 🌍 [terradev](https://github.com/wandb/examples/tree/master/examples/terradev)

### 🖥️ [terradev-wandb-example](https://github.com/wandb/examples/tree/master/examples/terradev)

Uses [Terradev](https://github.com/theoddden/terradev) to find the cheapest multi-cloud GPU for your training workload and logs infrastructure cost and training metrics to W&B.

```
cd examples/examples/terradev
pip install -r requirements.txt
python terradev_wandb_example.py
```
65 changes: 65 additions & 0 deletions examples/terradev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Terradev + Weights & Biases

This example shows how to combine [Terradev](https://github.com/theoddden/terradev)'s cross-cloud GPU cost optimization with Weights & Biases experiment tracking.

## What it does

1. **Find the cheapest GPU** for your workload using Terradev's multi-cloud quote engine.
2. **Log infrastructure metadata** (provider, region, cost per hour) to a W&B run via `wandb.config`.
3. **Track training metrics** (loss, accuracy, GPU utilization, cumulative cost) in W&B.

By default the script runs in **demo mode** with a sample quote, so you can try it without any cloud credentials. Pass `--live` to fetch real pricing from Terradev.

## Setup

```bash
cd examples/terradev
pip install -r requirements.txt
```

For live quotes you also need Terradev:

```bash
pip install terradev-cli
terradev configure --provider runpod # or any supported provider
```

Set your W&B credentials:

```bash
wandb login
# or
export WANDB_API_KEY=...
```

## Run

### Demo mode (no cloud credentials needed)

```bash
python terradev_wandb_example.py
```

### Live quote mode

```bash
python terradev_wandb_example.py --live --gpu-type H100
```

You will see output similar to:

```
Best live quote: runpod us-east-1 at $1.25/hr
W&B run started: https://wandb.ai/<entity>/terradev-wandb-example/runs/<run-id>
Run complete. View it in your W&B project.
```

## Files

- `terradev_wandb_example.py` — main example script.
- `requirements.txt` — Python dependencies.

## Next steps

- Provision the quoted instance with `terradev provision -g <gpu-type> --providers <provider>`.
- Use this script as a starting point for your own cost-aware training jobs.
3 changes: 3 additions & 0 deletions examples/terradev/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
wandb>=0.16.0
# terradev-cli is only required for live GPU quotes.
# Install it from PyPI or from https://github.com/theoddden/terradev.
169 changes: 169 additions & 0 deletions examples/terradev/terradev_wandb_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#!/usr/bin/env python3
"""
Terradev + Weights & Biases example integration.

This example shows how to use Terradev's cross-cloud GPU pricing to
choose the cheapest provider for a workload, then log that infrastructure
metadata and training metrics to a W&B run.

By default the script runs in demo mode with a sample quote. Set `--live` to
fetch a real quote from the Terradev CLI (requires a configured Terradev
installation and cloud credentials).

Usage:
python terradev_wandb_example.py
python terradev_wandb_example.py --live --gpu-type H100
"""

import argparse
import os
import re
import subprocess
from typing import Any, Dict, Optional

import wandb


SAMPLE_QUOTE = {
"provider": "runpod",
"region": "us-east-1",
"price": 1.99,
"gpu_type": "A100",
"instance_type": "a100-80gb",
"gpu_count": 1,
}


def get_terradev_quote(gpu_type: str) -> Optional[Dict[str, Any]]:
"""Call `terradev quote` and parse the best quote line.

Terradev's quote output includes a line like:

Best: $1.25/hr on runpod (us-east-1)

We extract the price, provider, and region from that line. If Terradev is
not installed or the command fails, we fall back to the sample quote.
"""
try:
result = subprocess.run(
["terradev", "quote", "-g", gpu_type],
capture_output=True,
text=True,
timeout=120,
check=False,
)
except FileNotFoundError:
print("Terradev CLI not found. Install it (`pip install terradev-cli`) to use --live.")
return None

if result.returncode != 0:
print("Terradev quote failed. Using sample quote for demo.")
return None

best_line = next(
(line for line in result.stdout.splitlines() if line.startswith("Best:")),
None,
)
if not best_line:
return None

best_match = re.search(
r"Best: \$([\d.]+)/hr on ([^(]+) \(([^)]+)\)", best_line
)
if not best_match:
return None

return {
"provider": best_match.group(2).strip(),
"region": best_match.group(3).strip(),
"price": float(best_match.group(1)),
"gpu_type": gpu_type,
}


def main():
parser = argparse.ArgumentParser(
description="Log Terradev GPU pricing and training metrics to W&B"
)
parser.add_argument(
"--gpu-type",
default="A100",
help="GPU type to quote with Terradev (default: A100)",
)
parser.add_argument(
"--project",
default="terradev-wandb-example",
help="W&B project name",
)
parser.add_argument(
"--live",
action="store_true",
help="Fetch a live quote from the Terradev CLI",
)
parser.add_argument(
"--steps",
type=int,
default=100,
help="Number of simulated training steps",
)
args = parser.parse_args()

quote = None
if args.live:
quote = get_terradev_quote(args.gpu_type)

if not quote:
quote = SAMPLE_QUOTE.copy()
quote["gpu_type"] = args.gpu_type
print(f"Using sample quote: {quote['provider']} {quote['region']} at ${quote['price']}/hr")
else:
print(
f"Best live quote: {quote['provider']} {quote['region']} at ${quote['price']}/hr"
)

# Enrich with sample instance details when they are missing.
quote.setdefault("instance_type", quote.get("gpu_type", args.gpu_type))
quote.setdefault("gpu_count", 1)

# Initialize a W&B run with the selected infrastructure as config.
run = wandb.init(
project=args.project,
config={
"gpu_type": quote["gpu_type"],
"provider": quote["provider"],
"region": quote["region"],
"cost_per_hour": quote["price"],
"instance_type": quote["instance_type"],
"gpu_count": quote["gpu_count"],
},
)

print(f"W&B run started: {run.url}")

# Simulated training loop. In a real workload this would be replaced by
# actual model training on the Terradev-provisioned instance.
for step in range(args.steps):
loss = 1.0 / (step + 1) ** 0.5
accuracy = 1.0 - loss
gpu_utilization = 70.0 + 20.0 * ((step % 10) / 10.0)

# Estimate cumulative cost assuming one step takes ~1 second.
cumulative_cost = quote["price"] * (step / 3600.0)

wandb.log(
{
"step": step,
"loss": loss,
"accuracy": accuracy,
"gpu_utilization": gpu_utilization,
"cost_per_hour": quote["price"],
"cumulative_cost": cumulative_cost,
}
)

wandb.finish()
print("Run complete. View it in your W&B project.")


if __name__ == "__main__":
main()
Loading