Skip to content
Runtime

How to train small machine learning models on CPU sandboxes

Build an image with scikit-learn or CPU-only PyTorch, train in a sandbox with every vCPU busy, and copy the model file out at the end.

On Runtime a 45-minute training run on 4 vCPU and 8 GiB costs 12 cents with all four cores busy, at the rates in effect on 26 October 2026. Billing stops the moment the run ends. Runtime runs on CPUs only, with no GPU sandboxes. It fits classical models such as gradient-boosted trees and linear models, and small neural networks, but not large deep learning models.

The short answer

Build the image once, upload the data, train, and download the model:

TypeScriptimport { readFile, writeFile } from "node:fs/promises";import { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "train", recipe: { pip: ["scikit-learn", "joblib"] } }); // onceawait using sbx = await runtime.sandboxes.create({  image: "train",  vcpu: 4,  memoryMiB: 8192,  network: { internet: false }, // training needs nothing from outside});await sbx.files.write("/workspace/data/train.csv", await readFile("train.csv"));await sbx.files.write(  "/workspace/train.py",  [    "import joblib, pandas as pd",    "from sklearn.ensemble import HistGradientBoostingClassifier",    "from sklearn.model_selection import train_test_split",    "df = pd.read_csv('data/train.csv')",    "X, y = df.drop(columns=['label']), df['label']",    "X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)",    "model = HistGradientBoostingClassifier(max_iter=300).fit(X_tr, y_tr)",    "print('accuracy', model.score(X_te, y_te))",    "joblib.dump(model, 'model.joblib')",  ].join("\n"),);const run = await sbx.exec("python3 train.py", { check: true, timeoutMs: 3_600_000 });console.log(run.stdout);await writeFile("model.joblib", await sbx.files.read("/workspace/model.joblib"));
Pythonfrom withruntime import RuntimeTRAIN = """import joblib, pandas as pdfrom sklearn.ensemble import HistGradientBoostingClassifierfrom sklearn.model_selection import train_test_splitdf = pd.read_csv('data/train.csv')X, y = df.drop(columns=['label']), df['label']X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)model = HistGradientBoostingClassifier(max_iter=300).fit(X_tr, y_tr)print('accuracy', model.score(X_te, y_te))joblib.dump(model, 'model.joblib')"""runtime = Runtime()runtime.images.build(name="train", recipe={"pip": ["scikit-learn", "joblib"]})  # oncewith runtime.sandboxes.create(image="train", vcpu=4, memory_mib=8192, network={"internet": False}) as sbx:    with open("train.csv", "rb") as file:        sbx.files.write("/workspace/data/train.csv", file.read())    sbx.files.write("/workspace/train.py", TRAIN)    print(sbx.exec("python3 train.py", check=True, timeout_ms=3_600_000).stdout)    with open("model.joblib", "wb") as file:        file.write(sbx.files.read("/workspace/model.joblib"))

pandas and NumPy are already in the default image, so the recipe adds only the packages that training needs. An exec can run for up to 24 hours. The sandbox has no time limit, so a long run needs no extra setup.

Small neural networks with PyTorch on CPU

PyTorch publishes CPU-only builds on its own package index. Use them on a machine with no GPU. A recipe's commands run that install while the image builds:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({  name: "torch-cpu",  recipe: {    commands: ["pip install torch --index-url https://download.pytorch.org/whl/cpu"],    pip: ["numpy", "pandas"],  },});await using sbx = await runtime.sandboxes.create({ image: "torch-cpu", vcpu: 4, memoryMiB: 8192 });const check = await sbx.exec(  "python3 -c 'import torch; print(torch.__version__, torch.get_num_threads())'",);console.log(check.stdout);

The check prints the number of threads PyTorch uses. Compare it with the sandbox's vcpu to confirm that training uses every core. Size the model to the machine. A multilayer perceptron on tabular data or a small convolutional network is a CPU workload. This page does not cover a model that needs a GPU to train in a reasonable time.

Search hyperparameters in parallel

Each trial runs in its own sandbox, so a search runs as wide as the account allows: up to 200 vCPUs at the same time on a paid account, initially. Prepare one sandbox with the data on disk, then fork it. Each copy starts with the files, installed packages and memory of the original, so no copy downloads the data again.

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await using base = await runtime.sandboxes.create({ image: "train", vcpu: 4, memoryMiB: 8192 });// train.py, which takes --learning-rate, and its data/ folder:await base.files.upload("./trainer", "/workspace/trainer");const rates = ["0.03", "0.1", "0.3"];const copies = await base.fork({ count: rates.length });const scores = await Promise.all(  copies.map(async (copy, i) => {    const run = await copy.exec(["python3", "train.py", "--learning-rate", rates[i]!], {      cwd: "/workspace/trainer",      timeoutMs: 3_600_000,    });    await copy.stop();    return [rates[i], run.stdout.trim()];  }),);console.log(scores);

Copies have the source's size and are billed as if each were created at that size. The snapshot that a fork takes for itself is deleted and is never charged (snapshots and forks).

Keep checkpoints and datasets

What Where to put it Cost
A dataset used by many runs A read-only volume copy, or your bucket mounted as /data Volume: 153 microdollars per GiB-hour
Checkpoints during a run A read-write volume; run sync after each save Charged on the volume's full size
The finished model files.read to your own storage No Runtime charge after the sandbox stops
The whole trained machine A snapshot, kept for as long as the account has credit $0.08 per GB per 30-day month

What CPU training needs

Need How Runtime covers it
ML libraries pip packages in a recipe image; NumPy and pandas in the default image
All cores working Shared CPU bursts up to vcpu; cpu: "reserved" guarantees every vCPU
Training data kept private network: { internet: false }, enforced on the host
Parallel trials Forks with memory and files; 100 sandboxes at the same time on a paid account
Runs longer than an hour exec up to 24 hours; no time limit
Watching the run sbx.metrics() for measured CPU and memory

What it costs

One run of 45 minutes on 4 vCPU and 8 GiB, with all four cores busy throughout:

CPU
0.75 h × 4 vCPU × $0.025
$0.075
Memory
0.75 h × 8 GiB × $0.0075
$0.045
Total
$0.12

Fifty such runs a month cost $6.00. A run that waits on data loading uses less measured CPU and costs less, with a floor of a twentieth of a vCPU. Runtime charges $0.025 per vCPU-hour of measured CPU and $0.0075 per GiB-hour of memory (pricing).

Start

Terminalnpx withruntime sandboxes run -- python3 -c 'import numpy, pandas; print(numpy.__version__, pandas.__version__)'

Approve the connection in your browser the first time you run it. Without credit, a sandbox can use up to 2 vCPU and 4 GiB. Add credit to use 4 vCPU or more.

Related: scientific computing, data analysis agent, RL environments, Python in a sandbox.

Sources

  • PyTorch: previous versions: CPU-only wheels installed with --index-url https://download.pytorch.org/whl/cpu, read 26 October 2026.

Facts on this page were checked on 26 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card