Downloads · 30 days
0
slappatuski/batterySwap
batterySwap is a machine learning model from slappatuski. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
This repository shows how to create a solution for the BatterySwapAI 2026 challenge.
Downloads · 30 days
0
Access
Public
Updated Aug 21, 2026
Repo size
98.1 MB
Likes
0
Public
Click a slice to open those files.
.parquet96.4 MB · 95%
From the Hugging Face model README
This repository shows how to create a solution for the BatterySwapAI 2026 challenge.
It contains working example code that can be submitted as-is, along with tools to check the solution before submitting.
You need to have the following installed
On Linux / Mac OS / Windows Subsystem for Linux (WSL)
python -m venv venv
source venv/bin/activate
Install dependencies
pip install -r requirements.txt -r requirements.dev.txt
Run the training
python batteryswap_example/train.py
Trained models or other output used by submission processing (script.py),
must be committed in the git repository.
An example is batteryswap_example/planners/best.pickle.
Using Docker allows to have exactly the same software versions as the submissions system.
This helps to ensure there are no errors when running in the submission environment.
NOTE: this requires around 20 GB+ of disk space.
Build Docker image
docker build -t batteryswapai-2026-example .
Make submissions and run evaluation (mount your local data folder to /tmp/data)
docker run --name batteryswapai -v ./BatterySwapAI-2026-Public:/tmp/data batteryswapai-2026-example bash -c "/app/env/bin/python3 script.py && /app/env/bin/python3 -m batteryswap_public.metric"
Copy submission.csv out of container
docker cp batteryswapai:/app/submission.csv ./submission.csv
NOTE: remember to commit and push your changes to the HuggingFace model repository.
Use New submission in the competition application to submit your current code for evaluation.
The committed batteryswap_example/planners/best.pickle is produced by:
BATTERYSWAP_DATASET_PATH=BatterySwapAI-2026-Public \
venv/bin/python3 batteryswap_example/train.py
Exact configuration used (all hardcoded defaults in batteryswap_example/train.py,
so no environment variables are required at submission time):
RUL model: final_model = 'survival' (lifelines Weibull AFT). Chosen by
lowest evaluate_plan total_cost summed over all scenarios, not by MAE
— MAE only scores observed (non-censored) devices and is blind to the survival
model's censoring-aware conservatism on long-lived devices.
Right-censoring bound: censor_horizon='true' (per-device). 82% of devices
(379/461) have a blank EOL, i.e. are right-censored, and an AFT likelihood
contributes S(C) for each of them — so C must be the time we actually know
the device survived to. The original code used a constant 120 days for every
censored device, although the data shows they were still alive at the dataset
cutoff (~334 days after s_0's start). Measured (sweep_censoring.py, day-caps
trimmed to 32,inf):
| censor_horizon | total | early_swap | late_swap |
|---|---|---|---|
| 'true' | 106,733 | 41,437 | 43,220 |
| 365.0 | 112,393 | 33,596 | 59,660 |
| 240.0 | 112,551 | 32,046 | 60,930 |
| 120.0 (old) | 112,641 | 21,724 | 70,780 |
The 240/365 arms are controls: 'true' beats equal-magnitude constants by
~5,700, so the win comes from the per-device variation, not merely from a
larger bound. Mechanism: a correct bound spreads predicted RUL out, so the
planner can prioritise genuinely-dying devices instead of treating the whole
fleet as due at once — late_swap falls 70,780 → 43,220. early_swap rises,
but that is a good trade at the evaluator's 20:1 late:early ratio.
Scheduling quantile: OrderedPlanner.SCHEDULE_QUANTILE = 'p10'
(PLANNER_SCHEDULE_QUANTILE default). Re-validated AFTER the censoring fix
(sweep_quantiles.py, trained with censor_horizon='true', day-caps 32,inf):
| q | total | early_swap | late_swap |
|---|---|---|---|
| p10 | 106,733 | 41,437 | 43,220 |
| p12 | 112,046 | 32,065 | 56,970 |
| p08 | 115,759 | 61,014 | 32,540 |
| p15 | 114,331 | 22,290 | 73,400 |
| p05 | 139,788 | 102,092 | 13,980 |
| p50 | 151,106 | 463 | 137,790 |
p10 is a clear, stable minimum (next-best p12 is +5,312). Note the empirical
optimum sits ABOVE the newsvendor anchor q* = early/(early+late) = 0.5/10.5 ≈ p05: perfect-calibration theory says p05, but the day-cap/batching congestion
penalises over-early swaps more than the raw 20:1 ratio implies, so p05 actually
scores 139,788 — trusting theory over measurement would cost ~33k. NOTE: this
default is what the grader uses, because the scheduling quantile is a class
attribute read at import and the grader sets no env var. final_quantiles
must include the chosen quantile or the planner silently falls back to p50.
Planner day-work caps: PLANNER_DAY_CAPS default 24,32,48,inf
(self-tuned per scenario by evaluate_plan against the predicted EOL).
Random seed: seed=0 (default in train_rul_model).
Training data: split='train', limit_scenarios=None (ALL 48 scenarios
feed RUL training; every scenario is the same physical fleet at a +7-day-shifted
start, so this exposes each device at many life-stages rather than duplicating
rows). Measured-best: survival + p10 + all-scenarios sums to 112,641
total_cost across all scenarios, ~16% better than the old limit_scenarios=1
(134,576). The gain is monotonic across 1,2,4,8,16,all (see
sweep_training_data.py), consistent with the RUL model being data-starved at
limit_scenarios=1 (only ~82 observed failures). NOTE: this local harness
evaluates on the same fleet it trains on, so treat the absolute number as
optimistic — the hidden competition devices are the real judge — but the
monotonic trend makes the direction trustworthy.
Runtime (copied into the competition Docker image via Dockerfile):
script.py — submission entrypoint (loads best.pickle, calls make_submissions).Dockerfile — build recipe (COPY batteryswap_example/, COPY script.py).requirements.txt — fixed by the competition (already includes lifelines,
scikit-learn, etc.).batteryswap_example/train.py — defines OrderedPlanner + RUL models
(must be importable for unpickling best.pickle).batteryswap_example/planners/best.pickle — the trained planner artifact.Repository / reproducibility:
README.md — this file (documents the exact reproduce command).LICENSE — MIT (edit the copyright holder).Not part of the grader run and kept out of the submission repo via .gitignore
(the Dockerfile only copies batteryswap_example/ and script.py; these are
local-only tuning/investigation tools that informed the hardcoded defaults in
train.py, plus generated outputs and the organizer-provided dataset):
compare_runs.py, inspect_data.py, investigate_*.py, sweep_*.py
(sweep_quantiles.py, sweep_training_data.py, sweep_censoring.py),
results/, submission.csv (generated), BatterySwapAI-2026-Public/ (dataset).
requirements.dev.txt is kept (referenced by the setup instructions above).