BitGuard can run its existing verified full-dataset bootstrap, preparation, training, evaluation, and edge-export pipeline on Modal. The Modal integration does not replace the scientific pipeline; it only supplies a GPU container and durable storage.
The named Modal Volume bitguard-bnn is mounted at /bitguard, but BitGuard does not run directly on that filesystem. The bootstrap uses POSIX hard links and no-clobber rename operations that Modal Volume mounts do not provide. Instead, the runner restores a durable snapshot to a normal Linux working disk, runs BitGuard there, and mirrors it back periodically:
/work/bitguard/ # normal Linux working filesystem
├── BitGuardData/
└── BitGuardRuns/
│
│ rsync every 3 minutes + final sync
▼
/bitguard/snapshot-v2/ # persistent Modal Volume
├── BitGuardData/
└── BitGuardRuns/
The Function requests a 512 GiB ephemeral working disk, which is Modal's current minimum accepted explicit Function disk request. The repository and locked CUDA environment are baked into the Modal Image. BitGuard's normal atomic checkpoints and bootstrap state remain authoritative; the Volume is only the durable snapshot/restore layer.
From a local clone of this repository:
python -m pip install "modal>=1.5,<1.6"
modal setupReview the official UNSW BoT-IoT academic-use terms before enabling the BoT-IoT run. The command-line acknowledgement is only a confirmation that you reviewed those terms; it is not a license grant.
The cheapest default is T4:
modal run -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset all \
--accept-botiot-licenseFor a faster GPU, change --gpu to L4, A10, A100, L40S, or H100.
BitGuard is small enough that data preparation and CPU-side Parquet preprocessing can
be a substantial part of wall-clock time, so a more expensive GPU is not guaranteed
to reduce total cost.
For a long run that should continue if the local terminal disconnects:
modal run -d -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset all \
--accept-botiot-licenseModal Functions have a 24-hour maximum runtime in this integration. If the job is interrupted or reaches that limit, run the same command again. The same Volume is mounted and BitGuard reuses verified bootstrap stages and compatible training checkpoints.
N-BaIoT:
modal run -n bitguard-bnn modal_train.py --gpu T4 --dataset nbaiotBoT-IoT:
modal run -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset botiot \
--accept-botiot-licenseUse the lightweight status reader below. It does not construct the training CUDA image, so status checks do not rebuild PyTorch:
modal run -n bitguard-status modal_status.py::statusYou can also inspect the persistent filesystem directly:
modal volume ls bitguard-bnn /
modal volume ls bitguard-bnn snapshot-v2/BitGuardData/.bitguard
modal volume ls bitguard-bnn snapshot-v2/BitGuardRunsDownload all run artifacts:
modal volume get bitguard-bnn snapshot-v2/BitGuardRuns ./BitGuardRunsOr download a particular run directory after locating it with modal volume ls.
If automatic acquisition is unsuitable, upload an archive or directory to the Volume:
modal volume put bitguard-bnn ./bot-iot.zip uploads/bot-iot.zipThen run:
modal run -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset botiot \
--accept-botiot-license \
--botiot-source uploads/bot-iot.zip--botiot-source is intentionally restricted to paths inside the persistent Modal
Volume, so a retry sees exactly the same source bytes.
Normal interruption recovery does not need --restart-stage; rerun the same
command first. Use a stage restart only when BitGuard's bootstrap report explicitly
requires it or when you intentionally want to invalidate that stage and everything
after it:
modal run -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset all \
--accept-botiot-license \
--restart-stage trainValid stage names are the same as the normal BitGuard bootstrap pipeline, such as
environment, acquire, extract, inspect, shard, validate, and train.
A prepare-only invocation is available:
modal run -n bitguard-bnn modal_train.py \
--gpu T4 \
--dataset all \
--accept-botiot-license \
--prepare-onlyThe current BitGuard bootstrap verifies the selected CUDA profile before executing the pipeline, so this convenience path still allocates the selected GPU. For minimizing cloud cost, the normal full run is generally preferable because it proceeds directly from preparation into training in the same invocation.
Modal charges the GPU, CPU, memory, and persistent Volume separately. The integration requests 8 physical CPU cores and 32 GiB RAM because the full BitGuard path performs substantial Parquet/Pandas preprocessing around a small BNN. T4 is therefore the default: it leaves more of a free monthly compute allowance for CPU-side work and retries. Use Modal's billing commands to inspect actual usage rather than estimating from GPU price alone:
modal billing summary --for "this month"
modal billing report --for "this month" --show-resourcesName the ephemeral run with -n bitguard-bnn so it can be addressed by name while it is running:
modal app logs bitguard-bnn -fIf a run has already stopped, use the ap-... App ID printed by modal run and omit -f:
modal app logs ap-XXXXXXXX --tail 1000modal run creates an ephemeral App. A stopped ephemeral App is not a currently deployed App, so following logs by its source-code App(...) name is not reliable unless the run was explicitly named with -n.