Skip to content

Reproduce

Every published number comes from a script in benchmarks/ and a JSON file in results/. All of them run in the manual bench GitHub Actions workflow, so each result file records the run id, job, commit, command and runtime that produced it (provenance):

gh workflow run bench -R rakshit-737/specimen-malware-analysis -f suite=all -f seeds=5
# suites: rules | family | avast (rules+family) | static-temporal | static | malbehavd | api-cross | maldetconv | light | all

The workflow downloads pinned data (SHA-256 checked; the whole 1.7 GB EMBER archive and the 1.6 GB Speakeasy reports only ever inside Actions), runs the suite, checks every result file (scripts/check_results.py: provenance, finite values, proportions and intervals in [0, 1]) and uploads results/, figures and model files as artefacts. Only the small JSON files are committed; python scripts/render_results.py then regenerates every table in the README and on these pages, and CI fails if they drift.

Benchmarks

result file bench suite script wall clock (Actions) source run commit expected headline value
static_ember_temporal.json suite=static-temporal python benchmarks/bench_static_temporal.py --seeds 5 31 min 37091150763 68dfb7c AUC 0.9892, TPR@0.1% 0.488
static_ember.json suite=static python benchmarks/bench_static.py 6 min 37093305708 a575df4 LightGBM AUC 0.9941
rules_avast.json suite=rules python benchmarks/bench_rules.py --seeds 5 --benign <speakeasy cache> 10 min 37109545948 be11eac shipped recall 0.293, FPR 0.0058 %
family_avast.json suite=family python benchmarks/bench_family.py 14 min 37091150763 68dfb7c shipped behaviour+static accuracy 0.9497, tau 0.85
behaviour_malbehavd.json suite=malbehavd python benchmarks/bench_malbehavd.py 1 min 37093305708 a575df4 LR 70/30 0.9627, duplicate-free 0.9343
api_cross.json suite=api-cross python benchmarks/bench_api_cross.py --seeds 5 61 min 37109548412 be11eac Li et al. RF (TF-IDF) 0.6578
repro_maldetconv.json suite=maldetconv python benchmarks/repro_maldetconv.py --seeds 10 --epochs 20 32 min 37093305708 a575df4 n=100 reproduction 0.9498

Wall clock is the script's own runtime on a GitHub-hosted ubuntu-24.04 runner (4 vCPU), excluding downloads. Re-runs on other hardware should agree within the published intervals.

All scripts need pip install -e ".[ml]"; api-cross also needs xgboost, maldetconv needs CPU torch, and the benign Speakeasy cache needs huggingface_hub. Every script has --help and exits with a one-line hint when its data is missing.

Data, locally

export SPECIMEN_DATA=/data/specimen        # anywhere outside the repo
python scripts/download_data.py --dest "$SPECIMEN_DATA"          # Avast 593 MB, EMBER prefix 120 MB, MalbehavD, Mal-API, Oliveira
python scripts/download_data.py --dest "$SPECIMEN_DATA" --verify # checks the pinned SHA-256s, not only SHA256SUMS
python -c "from specimen.ml.avast import build_cache; build_cache()"  # Avast token cache, needed by rules/family

A file that does not match its pinned hash is renamed *.bad and the script exits non-zero. The benign Speakeasy reports (scripts/build_speakeasy_cache.py) and the whole EMBER archive (--ember-mb 0) are over 1 GB and belong in the bench workflow, not on a shared laptop.

Models

The trained family model and the EMBER gate are too large for git. scripts/model_assets.json pins their SHA-256s and says where they come from; python scripts/fetch_models.py downloads them from the pinned release, else the latest release, else the bench artefact that produced them, and refuses any file whose hash differs. release.yml attaches the same files to every release and lists their SHA-256s in the release notes.

Demo pages

python scripts/fetch_models.py --only family_   # pinned family model, SHA-256 verified
python scripts/build_demo.py                     # regenerates docs/demo/*.md and docs/demo/summary.json
python scripts/render_results.py                 # README example and walkthrough numbers
python -m mkdocs build --strict                  # pip install -r docs/requirements.txt

The docs workflow runs the same commands and fails if the regenerated demo index differs from the committed one.