AsianPlayer/TriDrive / code /aide /eval /report_formulation_abs.py
AsianPlayer's picture
download
raw
22.7 kB
"""cwm3/aide/eval/report_formulation_abs.py — Formulation ablation (docs/decisions.md 2026-09-15 "PRE-REGISTRATION (2026-09-15T02:19:20Z) —
Formulation ablation", EXPLANATORY, not for adoption) -> aide/results/tables/formulation_abs.md (+ .json).
Question: the published Driver-WM Table-1 MotionBERT row (All 73.51) is worse than copying the last pose (published ZV 52.89), whereas the same
architecture on our keypoint protocol with the CockpitWM formulation (residual to the last pose, zero-init read-out) reaches 48.46 ± 0.15. The two
arms re-train the SAME architectures with an ABSOLUTE-coordinate read-out (pred = out ⊙ (W, H) px, PyTorch default init, no residual, no anchors),
everything else identical (tokens, recipe, loss): motionbert_kp_abs_s<k>_v2 (--model motionbert_kp --formulation abs, --loss euc) and
cwm3d_kp_abs_s<k>_v2 (--model cwm3d --formulation abs, K's loss defaults euc + 0.1 NLL + 0.05 bone + 0.01 jerk), seeds 42 / 123 / 456.
Reads ONLY run outputs: metrics_test.json (level values + 10k clip-bootstrap CIs written once per run by the harness), run json (best epoch / epochs /
stop / GPU minutes / params / config / t_start_utc), pred_test.npz (paired per-clip Δ abs − seed-matched residual run, aide/eval/metrics.paired_diff,
10k resamples, seed 0, exactly as arch_attribution.md). Published rows come verbatim from aide/eval/paper_rows.py. Nothing is typed by hand.
Pre-stated reading (decisions row), applied to the seed-mean test All-MPJPE of EACH abs arm separately:
(i) 60 <= mean <= 80 px -> the published MotionBERT gap is explained by the output formulation;
(ii) mean <= 52.89 px -> the formulation is NOT the explanation (the difference lies elsewhere) — reported as such;
(iii) anything else -> the formulation accounts for part of / more than the gap; descriptive, no binary conclusion.
Naming (coordinator 2026-09-15): our model = "CockpitWM" (no -K suffix); our residual MotionBERT-kp = "MotionBERT architecture, CockpitWM formulation".
python aide/eval/report_formulation_abs.py [--n-boot 10000] [--out aide/results/tables/formulation_abs.md]
Output policy: if --out already exists the new content is APPENDED as a dated block (append-only tables); existing sections are never edited.
"""
from __future__ import annotations
import argparse
import glob
import json
import sys
import time
from pathlib import Path
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from aide.data import protocol as P # noqa: E402
from aide.eval import metrics as M # noqa: E402
from aide.eval.harness import align, load_split # noqa: E402
from aide.eval.paper_rows import PAPER_ROWS # noqa: E402
from common.runmeta import write_run_json # noqa: E402
RUNS = P.RESULTS / "runs"
OUT = P.RESULTS / "tables" / "formulation_abs.md"
S0_UTC = "2026-09-15T02:19:20Z" # pre-registration UTC (decisions row)
SEEDS3, SEEDS5 = (42, 123, 456), (42, 123, 456, 789, 1011)
COLS = [("mpjpe_all", "All", 2), ("dn_mpjpe", "d-n", 3), ("mpjpe_hm", "HM", 2), ("dn_mpjpe_hm", "HM d-n", 3), ("pck05", "PCK@0.05", 2)]
CELLS = ("All-MPJPE", "d-n", "HM-MPJPE", "HM d-n", "PCK@0.05")
QUOTED = {"motionbert_kp": (48.46, 0.15), "cwm3d_kp": (48.60, 0.12)} # arch_attribution.md §3.1 (5 seeds) — consistency check only
ARMS = [ # (abs run stem, residual run stem, abs label, residual label)
("motionbert_kp_abs", "motionbert_kp", "MotionBERT architecture, ABSOLUTE formulation (`motionbert_kp_abs`)",
"MotionBERT architecture, CockpitWM formulation (`motionbert_kp`, residual)"),
("cwm3d_kp_abs", "cwm3d_kp", "CockpitWM architecture, ABSOLUTE formulation (`cwm3d_kp_abs`)", "CockpitWM (`cwm3d_kp`, residual + anchors)"),
]
PAPER = [("MotionBERT (published, Driver-WM arXiv 2605.05092v2 Table 1)", "MotionBERT"),
("Driver-WM main (published)", "Driver-WM main"),
("Zero-Velocity (published)", "Zero-Velocity")]
# ----------------------------------------------------------------------------- io
def run_json(name):
fs = sorted(glob.glob(str(RUNS / name / f"run_{name}_2*.json")))
return json.load(open(fs[-1])) if fs else None
def metrics_test(name):
p = RUNS / name / "metrics_test.json"
return json.load(open(p))["metrics"] if p.exists() else None
def load_pred(name, d):
p = RUNS / name / "pred_test.npz"
if not p.exists():
return None
z = np.load(p, allow_pickle=False)
return np.asarray(z["pred"], dtype=np.float64)[align(z, d["clip_id"])]
def per_clip_cells(pred, gt, hm):
err = M.joint_errors(pred, gt)
clip = err.mean((1, 2))
hmc = err[hm].mean((1, 2))
cells = {"All-MPJPE": (clip, False), "d-n": (100.0 * clip / P.DIAG, False), "HM-MPJPE": (hmc, False), "HM d-n": (100.0 * hmc / P.DIAG, False),
"PCK@0.05": (100.0 * (err <= P.pck_threshold_px(0.05)).mean((1, 2)), True)}
for h in range(P.T_PRED):
cells[f"All h={h + 1}"] = (err[:, h].mean(1), False)
return cells
def paired(a_name, b_name, d, gt, hm, n_boot):
pa, pb = load_pred(a_name, d), load_pred(b_name, d)
if pa is None or pb is None:
return None
ca, cb = per_clip_cells(pa, gt, hm), per_clip_cells(pb, gt, hm)
return {c: {"a": float(ca[c][0].mean()), "b": float(cb[c][0].mean()), **M.paired_diff(ca[c][0], cb[c][0], n_boot, 0), "higher_better": ca[c][1]} for c in ca}
def fmt_ci(r, nd=2):
return f"{r['mean']:+.{nd}f} [{r['ci_lo']:+.{nd}f},{r['ci_hi']:+.{nd}f}]"
def ms(vals, nd):
v = np.asarray([x for x in vals if x is not None], float)
if not len(v):
return "—"
return f"{v.mean():.{nd}f} ± {v.std(ddof=1):.{nd}f}" if len(v) > 1 else f"{v[0]:.{nd}f}"
def level_cells(name, ci=True):
m = metrics_test(name)
if m is None:
return None
if ci:
return [f"{m[c]['value']:.{nd}f} [{m[c]['ci_lo']:.{nd}f}, {m[c]['ci_hi']:.{nd}f}]" for c, _, nd in COLS]
return [f"{m[c]['value']:.{nd}f}" for c, _, nd in COLS]
def mean_cells(names):
ms_ = [metrics_test(n) for n in names]
ms_ = [m for m in ms_ if m is not None]
return [ms([m[c]["value"] for m in ms_], nd) for c, _, nd in COLS], len(ms_)
def run_meta(name):
r = run_json(name) or {}
return r.get("best_epoch", "—"), r.get("epochs_run", "—"), r.get("stop_reason", "—"), r.get("gpu_minutes"), r.get("n_params"), r.get("best_val_mpjpe_all"), r.get("t_start_utc"), (r.get("config") or {}).get("formulation")
def reading(mean_all):
if mean_all is None:
return "PENDING", "no finished run"
if 60.0 <= mean_all <= 80.0:
return "(i) FORMULATION EXPLAINS THE GAP", f"seed-mean All {mean_all:.2f} px lies in the pre-stated 60–80 px band: the same architecture with an absolute-coordinate read-out lands where the paper's baselines land"
if mean_all <= 52.89:
return "(ii) EXPLANATION ELSEWHERE", f"seed-mean All {mean_all:.2f} px is at or below the published zero-velocity 52.89: the output formulation is NOT what separates the published MotionBERT row from ours; the difference lies elsewhere (the paper's baseline pipeline / features / training details) and is reported as such"
return "(iii) PARTIAL / BEYOND — DESCRIPTIVE", f"seed-mean All {mean_all:.2f} px is outside both pre-stated bands (52.89–60 or > 80): the formulation accounts for part of / more than the published gap; reported descriptively, no binary conclusion"
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--n-boot", type=int, default=10000)
ap.add_argument("--out", default=str(OUT))
ap.add_argument("--tag", default="", help="suffix for the provenance run json name (dry runs: `dryrun` -> run_report_formulation_abs_dryrun_*.json)")
a = ap.parse_args()
t0 = time.time()
d = load_split("test")
gt = d["S10"][:, P.T_OBS:]
hm, thr, _ = M.hm_mask(gt)
stamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
hdr = "| " + " | ".join(lab for _, lab, _ in COLS) + " |"
summary = {"stamp": stamp, "s0_utc": S0_UTC, "n_boot": a.n_boot, "arms": {}, "references": {}, "gpu_minutes": {}}
L = ["# Formulation ablation — absolute-coordinate read-out vs the CockpitWM formulation (EXPLANATORY, not for adoption) — AIDE test, n = 609", "",
f"Generated {stamp} by `aide/eval/report_formulation_abs.py` from metrics_test.json / run json / pred_test.npz only (locked protocol: driver `first`, grid `floor`, "
f"HM top {int(hm.sum())} (threshold {thr:.2f} px), PCK @ {P.pck_threshold_px(0.05):.0f} px; every run selected on val All-MPJPE of the EMA weights only, test evaluated once by the harness; "
f"CI = 10k clip-bootstrap percentile interval; group rows mean ± sd over seeds, ddof 1). Pre-registered in docs/decisions.md 2026-09-15 at **{S0_UTC}** (before any run).", "",
"**Question.** The published Driver-WM Table-1 MotionBERT row (All 73.51) is worse than Driver-WM main (71.47) and worse than copying the last pose (published zero-velocity 52.89), "
"while the same architecture trained on our keypoint protocol with the CockpitWM formulation reaches 48.46 ± 0.15 (5 seeds). **Test.** The same two architectures are re-trained with an "
"ABSOLUTE-coordinate read-out — `pred = out ⊙ (W, H)` px, PyTorch default (non-zero) init of the read-out, no residual to the last pose, no zero-velocity start, no anchor mixture — with "
"everything else identical: input tokens [(Δx,Δy)/200 to the last pose, x/W, y/H, conf], blocks, recipe (`aide/train/run_arch_attribution.sh:24` verbatim), loss (`--loss euc` for the "
"MotionBERT architecture; CockpitWM keeps all four Stage-A terms euc 1.0 + Laplace NLL 0.1 + bone 0.05 + jerk 0.01 — none depends on the residual parametrisation), seeds 42 / 123 / 456. "
"The paired reference of every abs run is the seed-matched residual run that already exists (`motionbert_kp_s<k>_v2`, `cwm3d_kp_s<k>_v2`; untouched).", ""]
# ------------------------------------------------------------------ 1. levels
L += ["## 1. Test levels — published rows (labelled, typed verbatim in `aide/eval/paper_rows.py`), our references, and the two absolute-formulation arms", "",
"| row | seed / n " + hdr + " best val All | best ep / epochs / stop | GPU min |", "|---|---|" + "---|" * len(COLS) + "---|---|---|"]
for label, key in PAPER:
r = PAPER_ROWS[key]
L.append(f"| {label} | paper (single seed) | " + " | ".join(f"{r[c]:.{nd}f}" for c, _, nd in COLS) + " | – | – | – |")
summary["references"][label] = {c: r[c] for c, _, _ in COLS}
zv = level_cells("zero_velocity")
if zv:
L.append("| Zero-velocity (ours, locked protocol, run `zero_velocity`) | analytic | " + " | ".join(zv) + " | – | – | 0 |")
summary["references"]["zero_velocity (ours)"] = {c: metrics_test("zero_velocity")[c]["value"] for c, _, _ in COLS}
consistency = {}
for abs_stem, res_stem, abs_label, res_label in ARMS:
cells5, n5 = mean_cells([f"{res_stem}_s{k}_v2" for k in SEEDS5])
L.append(f"| **{res_label}** — 5-seed mean ± sd | n = {n5} | " + " | ".join(cells5) + " | – | – | – |")
vals5 = [metrics_test(f"{res_stem}_s{k}_v2")["mpjpe_all"]["value"] for k in SEEDS5 if metrics_test(f"{res_stem}_s{k}_v2")]
if len(vals5) == 5:
q = QUOTED[res_stem]
consistency[res_stem] = {"recomputed": (float(np.mean(vals5)), float(np.std(vals5, ddof=1))), "quoted_arch_attribution": q,
"match": abs(np.mean(vals5) - q[0]) < 0.006 and abs(np.std(vals5, ddof=1) - q[1]) < 0.006}
for k in SEEDS3:
n = f"{res_stem}_s{k}_v2"
lc = level_cells(n)
if lc:
be, ep, st, g, _, bv, _, _ = run_meta(n)
L.append(f"| {res_label} — `{n}` | {k} | " + " | ".join(lc) + f" | {bv:.3f} | {be} / {ep} / {st} | {g} |" if bv is not None else
f"| {res_label} — `{n}` | {k} | " + " | ".join(lc) + f" | – | {be} / {ep} / {st} | {g} |")
arm = {"per_seed": {}, "residual_reference": res_stem}
for k in SEEDS3:
n = f"{abs_stem}_s{k}_v2"
lc = level_cells(n)
be, ep, st, g, npar, bv, ts, form = run_meta(n)
if lc is None:
L.append(f"| **{abs_label}** — `{n}` | {k} | " + " | ".join("_pending_" for _ in COLS) + " | – | – | – |")
arm["per_seed"][k] = {"status": "PENDING"}
continue
m = metrics_test(n)
arm["per_seed"][k] = {"status": "DONE", **{c: {kk: m[c][kk] for kk in ("value", "ci_lo", "ci_hi")} for c, _, _ in COLS}, "best_epoch": be, "epochs_run": ep,
"stop": st, "gpu_minutes": g, "n_params": npar, "best_val_all": bv, "t_start_utc": ts, "formulation": form,
"after_s0": (ts is not None and ts > S0_UTC)}
if g is not None:
summary["gpu_minutes"][n] = float(g)
L.append(f"| **{abs_label}** — `{n}` | {k} | " + " | ".join(lc) + f" | {bv:.3f} | {be} / {ep} / {st} | {g} |")
cells3, n3 = mean_cells([f"{abs_stem}_s{k}_v2" for k in SEEDS3])
L.append(f"| **{abs_label} — mean ± sd** | n = {n3} | " + " | ".join(cells3) + " | – | – | – |")
done = [metrics_test(f"{abs_stem}_s{k}_v2") for k in SEEDS3]
done = [m for m in done if m is not None]
arm["n_done"] = len(done)
arm["seed_mean"] = {c: (float(np.mean([m[c]["value"] for m in done])) if done else None) for c, _, _ in COLS}
arm["seed_sd"] = {c: (float(np.std([m[c]["value"] for m in done], ddof=1)) if len(done) > 1 else None) for c, _, _ in COLS}
summary["arms"][abs_stem] = arm
L += ["", "Published MotionBERT row vs our residual MotionBERT-kp: the table's first row and the `motionbert_kp` group row are the two numbers the ablation is about (73.51 vs 48.46 ± 0.15). "
"For every row the CockpitWM formulation is the residual-to-last-pose read-out with zero init (+ anchor mixture for CockpitWM itself); the absolute formulation is the same network with the read-out replaced as described above."]
if consistency:
L += ["", "Consistency check of the 5-seed reference means against `arch_attribution.md` §3.1: " + "; ".join(
f"`{k}` recomputed {v['recomputed'][0]:.2f} ± {v['recomputed'][1]:.2f} vs quoted {v['quoted_arch_attribution'][0]:.2f} ± {v['quoted_arch_attribution'][1]:.2f} ({'match' if v['match'] else 'MISMATCH'})"
for k, v in consistency.items()) + "."]
summary["consistency"] = consistency
# ------------------------------------------------------------------ 2. paired Δ
L += ["", "## 2. Paired per-clip Δ = absolute − residual (seed-matched, same architecture; errors: positive = the absolute formulation is worse; PCK: negative = worse)", ""]
for abs_stem, res_stem, abs_label, res_label in ARMS:
per_seed = {k: paired(f"{abs_stem}_s{k}_v2", f"{res_stem}_s{k}_v2", d, gt, hm, a.n_boot) for k in SEEDS3}
per_seed = {k: v for k, v in per_seed.items() if v}
L += [f"### {abs_label} vs {res_label}", ""]
if not per_seed:
L += ["_(no finished pair yet)_", ""]
summary["arms"][abs_stem]["paired"] = {}
continue
seeds = list(per_seed)
L += ["| cell | " + " | ".join(f"abs s{k}" for k in seeds) + " | " + " | ".join(f"residual s{k}" for k in seeds) + " | " + " | ".join(f"Δ s{k} [CI]" for k in seeds) + " | mean Δ ± sd |",
"|---|" + "---|" * (3 * len(seeds)) + "---|"]
pr = {}
for c in CELLS + tuple(f"All h={h + 1}" for h in range(P.T_PRED)):
rows = [per_seed[k][c] for k in seeds]
nd = 3 if c in ("d-n", "HM d-n") else 2
mean_txt = ms([r["mean"] for r in rows], nd) if len(rows) > 1 else f"{rows[0]['mean']:+.{nd}f}"
L.append(f"| {c} | " + " | ".join(f"{r['a']:.{nd}f}" for r in rows) + " | " + " | ".join(f"{r['b']:.{nd}f}" for r in rows) + " | "
+ " | ".join(fmt_ci(r, nd) for r in rows) + f" | {mean_txt} |")
pr[c] = {str(k): {kk: per_seed[k][c][kk] for kk in ("a", "b", "mean", "ci_lo", "ci_hi", "p_lt0")} for k in seeds}
L.append("")
summary["arms"][abs_stem]["paired"] = pr
# ------------------------------------------------------------------ 3. reading
L += ["## 3. Pre-registered reading and outcome", "",
"Pre-stated (decisions row, before any run; applied to the seed-mean test All-MPJPE of each arm separately): **(i)** 60–80 px → the published MotionBERT gap is explained by the output "
"formulation; **(ii)** ≤ 52.89 px (published zero-velocity) → the formulation is NOT the explanation, the difference lies elsewhere and is reported as such; **(iii)** anything else "
"(52.89–60 px or > 80 px) → the formulation accounts for part of / more than the gap; descriptive, no binary conclusion. Nothing is adopted from this table; the attribution wording of "
"`arch_attribution.md` is untouched; any paper sentence derived from this table needs owner review.", ""]
outcomes = {}
for abs_stem, res_stem, abs_label, res_label in ARMS:
arm = summary["arms"][abs_stem]
mean_all = arm["seed_mean"]["mpjpe_all"] if arm["n_done"] == 3 else None
verdict, why = reading(mean_all)
sd = arm["seed_sd"]["mpjpe_all"]
ref5 = consistency.get(res_stem, {}).get("recomputed")
gap_txt = ""
if mean_all is not None and ref5:
gap_txt = f" Δ to our residual re-instantiation of the same architecture: {mean_all - ref5[0]:+.2f} px (seed means); Δ to the published MotionBERT row 73.51: {mean_all - 73.51:+.2f} px; Δ to the published Driver-WM main 71.47: {mean_all - 71.47:+.2f} px."
L.append(f"- **{abs_label}** — seed-mean test All-MPJPE **{'—' if mean_all is None else f'{mean_all:.2f} ± {sd:.2f}'}** (n = {arm['n_done']}/3) → **{verdict}**: {why}.{gap_txt}")
outcomes[abs_stem] = {"mean_all": mean_all, "sd_all": sd, "verdict": verdict, "why": why, "n_done": arm["n_done"]}
summary["outcomes"] = outcomes
both = [o["verdict"] for o in outcomes.values()]
if all(o["n_done"] == 3 for o in outcomes.values()):
if all(v.startswith("(i)") for v in both):
one = "Both arms fall in the pre-stated 60–80 px band: **the published MotionBERT gap (73.51 vs our 48.46) is explained by the output formulation, not by the architecture** — the same networks with an absolute-coordinate read-out land where the paper's baselines land, while their residual-to-last-pose re-instantiations beat zero-velocity."
elif all(v.startswith("(ii)") for v in both):
one = "Both arms stay at or below the published zero-velocity: **the output formulation is NOT what separates the published MotionBERT row from ours**; the explanation lies elsewhere (the paper's baseline pipeline / features / training details) and is reported as such."
else:
one = "The two arms do not read the same way (" + "; ".join(f"{k}: {o['verdict']}" for k, o in outcomes.items()) + "): **reported descriptively, no single binary conclusion**; the numbers above stand on their own."
L += ["", f"**Outcome sentence.** {one}"]
summary["outcome_sentence"] = one
else:
L += ["", "**Outcome sentence.** _pending — not every abs run has finished_"]
summary["outcome_sentence"] = None
# ------------------------------------------------------------------ 4. runs, S0, provenance
L += ["", "## 4. Runs, GPU minutes, pre-registration check", "", "| run | formulation (run json config) | t_start_utc | after S0 " + S0_UTC + "? | params | GPU min |", "|---|---|---|---|---|---|"]
tot = 0.0
for abs_stem, *_ in ARMS:
for k in SEEDS3:
n = f"{abs_stem}_s{k}_v2"
be, ep, st, g, npar, bv, ts, form = run_meta(n)
if ts is None:
L.append(f"| `{n}` | – | _pending_ | – | – | – |")
continue
tot += float(g or 0)
L.append(f"| `{n}` | {form} | {ts} | {'yes' if ts > S0_UTC else '**NO**'} | {npar:,} | {g} |")
L += [f"| **total (new runs)** | | | | | **{tot:.2f}** |", "",
"## Provenance", "",
f"- New run dirs only: `aide/results/runs/motionbert_kp_abs_s<k>_v2`, `aide/results/runs/cwm3d_kp_abs_s<k>_v2` (launcher `aide/train/run_formulation_abs.sh`, gate before every launch: free VRAM ≥ 3 + 4 GB, MemAvailable ≥ 28 GB, < 2 trainers alive on the host incl. the BATON CAN-arm trainers, OMP/MKL 4; pids in `aide/results/formulation_abs/pids.txt`). "
"The comparison runs `motionbert_kp_s*_v2`, `cwm3d_kp_s*_v2`, `zero_velocity` are the existing ones (not retrained).",
"- Code: `--formulation {residual,abs}` in `aide/train/train_kp.py`; `heads.AbsoluteReadout`, `HorizonHead(zero_init=)`, `CWM3D(formulation=)`, `MotionBERTKP(formulation=)`. The default `residual` path is asserted byte-identical to the pre-change code by "
"`aide/tests/test_formulation_abs.py` (fixture `aide/tests/fixtures/formulation_abs_prechange.pt` generated from the unmodified files before the edit).",
"- Published numbers: `aide/eval/paper_rows.py` (typed verbatim from arXiv 2605.05092v2 Table 1; single-seed rows). No AIDE test clip entered any training or selection; every abs run was selected on val All-MPJPE only and its test split evaluated once."]
summary["gpu_minutes_total"] = tot
text = "\n".join(L)
out = Path(a.out)
if out.exists():
with open(out, "a") as f:
f.write(f"\n\n---\n\n<!-- appended regeneration {stamp} -->\n\n" + text)
mode = "appended"
else:
out.write_text(text)
mode = "written"
js = out.with_suffix(".json")
if js.exists():
old = json.load(open(js))
old = old if isinstance(old, list) else [old]
js.write_text(json.dumps(old + [summary], indent=1, default=str))
else:
js.write_text(json.dumps([summary], indent=1, default=str))
write_run_json(P.RESULTS / "tables", "report_formulation_abs" + (f"_{a.tag}" if a.tag else ""), [Path(__file__), M.__file__, P.__file__], [P.CACHE_NPZ], seed=0, t_start=t0, input_listing=False,
extra={"out": str(out), "mode": mode, "outcomes": outcomes, "gpu_minutes": summary["gpu_minutes"], "s0_utc": S0_UTC})
print(text)
print(f"\n[{mode}] {out}")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
22.7 kB
·
Xet hash:
e9d30069a6fd77b1d699ecf16e887da2af8f2ffff3e5d97b9e40373ab999140d

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.