ptAI API — User Guide
This API lets you run adversarial-ML attacks against your own model and dataset. Every attack the web console offers is available as a single HTTP endpoint — upload your assets, pick the algorithm, get the result.
- Base URL:
https://api.pt4ai.k3ylabs.devon the hosted instance, orhttps://<host>:8000on your own deployment. The examples below usehttps://127.0.0.1:8000; replace it with yours. - Interactive docs:
GET /docs— the easiest place to try a request from the browser. - Machine-readable spec:
GET /openapi.json - Postman:
GET /postman-import(import page) orGET /postman(raw collection JSON).
1. What you can do
| Goal | Endpoint |
|---|---|
| Fool the model at inference time (gradient access) | POST /api/attack/evasion/whitebox |
| Fool the model with only prediction access | POST /api/attack/evasion/blackbox |
| Transfer adversarial inputs from a surrogate | POST /api/attack/evasion/greybox |
| Test whether the model leaks training-set membership | POST /api/attack/inference |
| Steal a copy of the model from its predictions | POST /api/attack/extraction |
| Inject malicious training samples (backdoor it) | POST /api/attack/poisoning |
| Run a full robustness sweep with a verdict | POST /api/attack/pentest |
| Run any of the above from a single config file | POST /api/attack |
| Fool an object detector (Faster R-CNN / YOLOv5) — boxes vanish, appear or change class | POST /api/attack/object-detection — see §14 |
All attack endpoints work with structured (tabular CSV) and image (built-in MNIST/CIFAR-10 or your own class-per-folder ZIP) data. Models can be Keras, PyTorch, scikit-learn, XGBoost, LightGBM, CatBoost or ONNX (see §3).
The unified endpoint — POST /api/attack
One convenience endpoint runs any attack from a single full-config JSON
instead of separate form fields. The config carries data_type, family,
scenario/attack, options, and params; you still attach the data files.
# config.json describes the whole request:
# {"data_type":"structured","family":"evasion","scenario":"white","attack":"pgd",
# "columns_to_drop":"flow_id,src_ip,dst_ip,src_port,dst_port","label_col":"label",
# "params":{"eps":0.1,"eps_step":0.01,"max_iter":40}}
curl -k -X POST https://127.0.0.1:8000/api/attack \
-H 'X-API-Key: your-key-here' \
-F config_file=@config.json \
-F dataset=@data.csv -F model=@model.h5 \
-F scaler=@scaler.joblib -F encoder=@encoder.joblib \
-o result.zip
Download ready-made configs (one per attack) from /templates — the
full-config set. The granular endpoints below still work exactly as before;
/api/attack is just a one-file shortcut.
2. How a request works
Every attack endpoint is a multipart/form-data POST. The form fields,
top to bottom in Swagger UI, are:
data_type—structuredorimage(pick this first; it decides which file slots you need).- Attack dropdown — algorithm to run. Different endpoints offer different choices; only valid algorithms appear.
params— a JSON object string with the algorithm's parameters. Don't put anattackkey insideparams; that's the dropdown's job.params_file(optional) — a.jsonfile with the same structure; values override the inlineparamson key collision.- File slots —
dataset,model,scaler,encoder(structured) ordataset_zip(image). - Image-only fields —
source(mnist/cifar10/zip),image_size,color_mode,limit.
Every attack returns a ZIP by default — a single archive with all
results and artifacts. Append ?format=json to any attack URL if you'd
rather get the JSON envelope inline.
3. What to attach
Structured data
| Slot | Required | Format |
|---|---|---|
dataset |
yes | .csv |
model |
yes | Keras .h5 / .keras, or another supported format (below) |
scaler |
yes for Keras, optional otherwise | .joblib / .pkl |
encoder |
yes for Keras, optional otherwise | .joblib / .pkl |
columns_to_drop |
no | comma-separated column names (default: flow_id,src_ip,dst_ip,src_port,dst_port) |
label_col |
no | ground-truth column (default: label) |
label_binary_col |
no | optional binary label column |
Image data
| Slot | Required | Notes |
|---|---|---|
source |
yes | mnist · cifar10 · zip |
dataset_zip |
only when source=zip |
class-per-folder ZIP |
model |
usually yes | Keras .h5 / .keras or another supported format (optional for extraction) |
image_size |
when source=zip |
WxH, e.g. 28x28 |
color_mode |
when source=zip |
rgb · grayscale |
limit |
no | max samples to keep (default 200) |
Other model formats
Besides Keras, model accepts PyTorch (.pt TorchScript, .pth, or .safetensors plus an
architecture file), scikit-learn (.joblib / .pkl / .skops), XGBoost (.json / .ubj),
LightGBM (.txt), CatBoost (.cbm) and ONNX (.onnx). These files are opened only inside an
isolated sandbox on the server. Models without gradients (trees, ONNX) are attacked white-box
through a surrogate model (a transfer attack); the result says so. If an attack can't run on the
uploaded model type, the API answers 422 with the reason.
4. Evasion — three sub-endpoints
Pick the sub-endpoint that matches the attacker's access model. Each exposes only the algorithms valid for that scenario.
| Sub-endpoint | Available algorithms |
|---|---|
/api/attack/evasion/whitebox |
fgsm · pgd · bim · jsma · cw · deepfool · apgd |
/api/attack/evasion/blackbox |
zoo · boundary · hsj |
/api/attack/evasion/greybox |
same gradient-based set as white-box (uses a surrogate) |
deepfool and apgd are image-only.
Parameters per algorithm
White-box / grey-box:
| Algorithm | Common parameters (defaults shown) |
|---|---|
fgsm |
eps=0.1 · eps_step · num_random_init=0 · batch_size=32 · targeted=false · y_target |
pgd |
eps=0.1 · eps_step=0.01 · max_iter=40 · targeted=false · y_target |
bim |
eps=0.1 · eps_step=0.01 · max_iter=10 · targeted=false · y_target |
jsma |
theta=1.0 · gamma=0.1 · targeted=true · y_target |
cw |
confidence=0.0 · learning_rate=0.001 · binary_search_steps=10 · max_iter=20 · initial_const=0.9 · batch_size=32 |
deepfool (image) |
max_iter=50 · epsilon=1e-6 · nb_grads=10 |
apgd (image) |
eps=0.03 · max_iter=100 |
Black-box:
| Algorithm | Common parameters (defaults shown) |
|---|---|
zoo |
confidence=0.5 · learning_rate=0.01 · max_iter=20 · binary_search_steps=10 · initial_const=1.0 · nb_parallel=20 · batch_size=1 |
boundary |
max_iter=1000 · epsilon=0.01 · step_adapt=0.667 · init_size=100 · batch_size=64 |
hsj |
max_iter=25 · max_eval=10000 · init_eval=100 |
curl — white-box PGD on structured data
curl -k -X POST https://127.0.0.1:8000/api/attack/evasion/whitebox \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' \
-F 'attack=pgd' \
-F 'params={"eps":0.1,"eps_step":0.01,"max_iter":40}' \
-F 'dataset=@./data.csv' \
-F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' \
-F 'encoder=@./encoder.joblib' \
-o result.zip
curl — black-box HopSkipJump on MNIST
curl -k -X POST https://127.0.0.1:8000/api/attack/evasion/blackbox \
-H 'X-API-Key: your-key-here' \
-F 'data_type=image' \
-F 'attack=hsj' \
-F 'params={"max_iter":25,"max_eval":5000}' \
-F 'source=mnist' \
-F 'limit=200' \
-F 'model=@./mnist_cnn.h5' \
-o result.zip
curl — grey-box FGSM (gradients on surrogate)
curl -k -X POST https://127.0.0.1:8000/api/attack/evasion/greybox \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' \
-F 'attack=fgsm' \
-F 'params={"eps":0.1}' \
-F 'dataset=@./data.csv' \
-F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' \
-F 'encoder=@./encoder.joblib' \
-o result.zip
What you get back
A ZIP (ptai_evasion_<attack>_<id>.zip) containing results.json (the full
envelope below), metrics.json, and confusion-matrix CSVs. Add ?format=json to the URL
to get this envelope inline instead of the ZIP:
{
"metrics": {
"clean_accuracy": 0.92,
"adversarial_accuracy": 0.41,
"accuracy_drop": 0.51,
"n_samples": 1000,
"perturbation_linf": 0.10,
"perturbation_l2_mean": 1.4
},
"artifacts": {
"confusion_clean": [[...]],
"confusion_adversarial": [[...]]
}
}
5. Membership Inference
Tests whether the model leaks information about its training set. Rule-Based MIA (loss threshold) and Black-Box MIA (meta-classifier) run in parallel.
| Field | Choices / default | What it means |
|---|---|---|
attack_model_type |
rf (default) · gb · lr |
Meta-classifier for Black-Box MIA |
split_ratio (in params) |
0.7 |
Fraction of samples treated as 'members' |
max_samples (in params) |
1000 |
Cap per split (members / non-members) |
seed (in params) |
42 |
RNG seed |
curl
curl -k -X POST https://127.0.0.1:8000/api/attack/inference \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' \
-F 'attack_model_type=rf' \
-F 'params={"split_ratio":0.7,"max_samples":1000}' \
-F 'dataset=@./data.csv' \
-F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' \
-F 'encoder=@./encoder.joblib' \
-o result.zip
What you get back
A ZIP with results.json + metrics.json. Both MIA variants report accuracy,
precision, recall, f1, auc, advantage. High advantage = the model leaks
membership. (Add ?format=json for the inline envelope.)
6. Model Extraction
CopycatCNN — query the victim model, train a stolen ("thieved") model on its responses, measure how closely it matches.
Field (in params) |
Default | What it means |
|---|---|---|
nb_stolen |
500 |
Query budget against the victim |
nb_epochs |
5 |
Training epochs for the stolen model |
batch_size |
64 |
|
use_probability |
true |
true = soft labels · false = hard labels |
curl
curl -k -X POST https://127.0.0.1:8000/api/attack/extraction \
-H 'X-API-Key: your-key-here' \
-F 'data_type=image' \
-F 'params={"nb_stolen":500,"nb_epochs":5,"use_probability":true}' \
-F 'source=cifar10' \
-F 'limit=2000' \
-F 'model=@./cifar_cnn.h5' \
-o result.zip
What you get back
A ZIP with results.json + metrics.json reporting fidelity (agreement with
victim), victim_accuracy, stolen_accuracy, plus per-class fidelity and a query-budget
curve. (Add ?format=json for the inline envelope.)
7. Poisoning
Inject a small fraction of malicious training samples, retrain a clone of your model, and measure how badly it's been backdoored.
attack value |
Method |
|---|---|
backdoor |
BadNets — visible trigger (Gu 2017) |
clean_label |
Adversarial perturbation + visible trigger (Turner 2018) |
hidden_trigger |
Invisible trigger via feature-space optimisation (Saha 2019) |
Common parameters (all variants)
| Field | Default |
|---|---|
target_class |
0 |
poison_fraction |
0.10 |
nb_epochs |
8 |
batch_size |
64 |
seed |
42 |
Trigger placement
Structured data:
| Field | Default | Notes |
|---|---|---|
trigger_features |
-1 |
Comma-separated indices; negatives allowed (-1 = last column) |
trigger_value |
1.0 |
Value written to trigger features |
Image data:
| Field | Default | Choices |
|---|---|---|
patch_size |
4 |
1–256 px side length |
patch_value |
1.0 |
Pixel value |
patch_position |
bottom-right |
top-left · top-right · bottom-left · bottom-right · center |
Variant-specific extras
clean_label adds: pp_poison (0.33) · eps (0.3) · eps_step (0.1) ·
max_iter (100)
hidden_trigger adds: source_class · feature_layer (-2) ·
learning_rate (0.01) · max_iter (200) · htb_batch_size (32)
curl — image backdoor
curl -k -X POST https://127.0.0.1:8000/api/attack/poisoning \
-H 'X-API-Key: your-key-here' \
-F 'data_type=image' \
-F 'attack=backdoor' \
-F 'params={"target_class":0,"patch_size":4,"patch_position":"bottom-right","poison_fraction":0.1}' \
-F 'source=mnist' \
-F 'limit=1000' \
-F 'model=@./mnist_cnn.h5' \
-o result.zip
curl — structured clean-label
curl -k -X POST https://127.0.0.1:8000/api/attack/poisoning \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' \
-F 'attack=clean_label' \
-F 'params={"target_class":0,"trigger_features":"-1","trigger_value":1.0,"poison_fraction":0.1,"pp_poison":0.33,"eps":0.3,"eps_step":0.1,"max_iter":100}' \
-F 'dataset=@./data.csv' \
-F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' \
-F 'encoder=@./encoder.joblib' \
-o result.zip
What you get back
A ZIP with results.json + metrics.json, confusion/target-confidence CSVs, and
(for structured data) the full poisoned_train.csv. Headline metrics: training
samples, poisoned samples, clean accuracy, Attack Success Rate (ASR), plus per-class
CDA / ASR and label distribution before vs. after. (Add ?format=json for the inline
envelope; the poisoned CSV is then base64 inside artifacts.)
8. Adversarial Penetration Test
Full robustness sweep across FGSM / PGD / BIM at ε ∈ [0.00, 1.00]. Emits a pass/fail robustness assessment (clean vs. adversarial accuracy per ε). Structured data only.
| Field | Default | What it means |
|---|---|---|
use_fgsm |
true |
Include FGSM in the sweep |
use_pgd |
true |
Include PGD in the sweep |
use_bim |
true |
Include BIM in the sweep |
eps_step (in params) |
0.05 |
Spacing of the ε-grid |
clean_threshold (in params) |
none | Minimum acceptable clean accuracy for the verdict |
adv_threshold (in params) |
none | Minimum acceptable adversarial accuracy at the worst ε |
At least one algorithm must be selected.
curl
curl -k -X POST https://127.0.0.1:8000/api/attack/pentest \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' \
-F 'use_fgsm=true' -F 'use_pgd=true' -F 'use_bim=true' \
-F 'params={"eps_step":0.05}' \
-F 'dataset=@./data.csv' \
-F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' \
-F 'encoder=@./encoder.joblib' \
-o pentest_result.zip
What you get back
A ZIP with results.json + metrics.json. Metrics include: clean accuracy;
per-attack and overall minimum / average adversarial accuracy; an accuracy-vs-ε
curve per attack; and robustness flags (is_robust, is_robust_min, is_robust_avg).
(Add ?format=json for the inline envelope.)
9. Async execution — long-running attacks
Some attacks are slow — jsma/hsj can run 15+ minutes, and cw/zoo/boundary/ pentest/inference (rf/gb) commonly take several minutes. Every attack endpoint now runs the attack as a background job:
- If it finishes within
PTAI_SYNC_WAIT_SECONDS(default 25s), you get exactly the same response as before — the ZIP or JSON envelope, inline, no changes needed to existing clients/scripts. - If it's still running after that window (or you passed
?async=true), you instead get202 Accepted:json { "job_id": "9f5e2c...", "status": "queued", "status_url": "/api/jobs/9f5e2c...", "result_url": "/api/jobs/9f5e2c.../result?format=zip" }
Then:
| Action | Request |
|---|---|
| Poll status | GET /api/jobs/{job_id} → queued · running · done · error · timeout · cancelled |
Fetch the result once done |
GET /api/jobs/{job_id}/result?format=zip\|json — same envelope/ZIP as a synchronous response |
| Cancel | DELETE /api/jobs/{job_id} — immediate if still queued; if already running, the job is marked cancelled right away but the underlying computation (a synchronous ART/TensorFlow call in a worker thread) can't be force-killed and finishes in the background rather than stopping instantly |
# submit, then poll until done
curl -s -k -X POST https://127.0.0.1:8000/api/attack/evasion/blackbox \
-H 'X-API-Key: your-key-here' \
-F 'data_type=structured' -F 'attack=hsj' \
-F 'dataset=@./data.csv' -F 'model=@./model.h5' \
-F 'scaler=@./scaler.joblib' -F 'encoder=@./encoder.joblib' > submit.json
job_id=$(python3 -c "import json;print(json.load(open('submit.json'))['job_id'])")
until [ "$(curl -s -k https://127.0.0.1:8000/api/jobs/$job_id -H 'X-API-Key: your-key-here' | python3 -c "import json,sys;print(json.load(sys.stdin)['status'])")" = "done" ]; do sleep 5; done
curl -s -k https://127.0.0.1:8000/api/jobs/$job_id/result -H 'X-API-Key: your-key-here' -o result.zip
A closed client connection (Postman tab closed, curl killed, proxy timeout) while polling has no effect on the job or on any other request — job/worker-slot accounting is fully decoupled from any single HTTP connection, which is also what stops a burst of abandoned requests from starving every other caller.
10. Response format
Every attack endpoint returns a ZIP by default (all results + artifacts as files).
Append ?format=json to get this envelope inline instead:
{
"run_id": "0a1b2c3d4e5f...",
"data_type": "structured",
"family": "evasion",
"attack": "pgd",
"scenario": "white",
"metrics": { "...": "..." },
"plots": { "...": "base64-encoded PNG" },
"artifacts": { "...": "..." }
}
run_id— one-off identifier for the request (no server-side state).scenariois only set for evasion (white/black/grey).metricscarries the headline numbers (accuracy, ASR, fidelity, …) — evasion also adds*_tpr/*_fpr/*_f1_score/*_auc_scoreandconfidence_curve_clean/confidence_curve_adversarial(a downsampled, sorted array for a client-side confidence-shift chart).artifactscarries supporting data (confusion matrices, poisoned CSVs, …).plotscarries base64-encoded PNG sample images where applicable (image evasion:sample_<i>_clean/sample_<i>_adversarial, up to 6 pairs; image poisoning:preview_clean/preview_trigger) — empty for attacks that don't produce one. Exact keys present vary per attack family/data type; don't assume a fixed key set, check for presence.
The ZIP (default) unpacks this same content into files — always manifest.json,
results.json, metrics.json, plus whatever applies to the attack (confusion CSVs,
poisoned_train.csv, plots/*.png).
11. Errors
| Status | When |
|---|---|
202 |
Attack didn't finish within the sync-wait window — see §9, poll GET /api/jobs/{job_id} |
400 |
Missing required file slot · params.attack conflicts with the dropdown · invalid data_type · params JSON parse error (including Infinity/NaN, which are rejected) · pentest with no algorithm selected · poisoning target_class/source_class outside the model's class range |
404 |
Unknown/expired job_id |
409 |
GET /api/jobs/{job_id}/result called while the job is still queued/running, or after it was cancelled |
413 |
Upload too large · dataset / image batch exceeds server limits · requested image_size too large · model has too many parameters |
422 |
params JSON is wrong for the chosen algorithm — the response carries the exact field path (e.g. params.fgsm.eps: Input should be less than or equal to 10) |
500 |
Unexpected server error |
504 |
Job exceeded the server's wall-clock timeout (GET /api/jobs/{job_id} reports status: "timeout") |
Note: attacks no longer get rejected outright when the server is at
PTAI_MAX_CONCURRENT_ATTACKS capacity — they queue as a background job
(status: "queued") instead, so ordinary bursts don't produce a hard
failure the way a 429 used to.
The 413 / 504 caps are configurable by the operator of the deployment; if you hit one, ask them to raise it or reduce your input size.
12. Authentication
Standard deployments require an API key. Send it on every attack request:
curl -H 'X-API-Key: your-key-here' ...
If you get a 401 or 403, you need a key from the operator. Public
endpoints (/, /healthz, /docs, /openapi.json, /guide, /demo,
/postman, /postman-import, /templates (and its downloads), /readme)
never require a key. Every
/api/attack/* and /api/jobs/* endpoint requires it.
In Swagger (/docs), click Authorize (top right) and paste your key
once — every "Try it out" call then includes it automatically. In
Postman, the collection's own Authorization tab is pre-wired for an
API key — set the apiKey collection variable once and every request
inherits it.
Browser login (separate, optional, deployment-dependent)
Some deployments also put a username/password login gate in front of the
human-browsable documentation pages — /docs, /redoc, /openapi.json,
/guide, /postman-import, /templates. The landing page (/) and the demo
(/demo) always stay public. If you're redirected to /login when
opening one of these in a browser, ask the operator for the browser-login
credentials (separate from your X-API-Key). A signed session cookie keeps you
in for 12 hours; use the "Logout" link on the landing page to end it early.
This only ever applies to pages you browse. Every /api/* endpoint, /healthz,
the raw Postman download (/postman), individual template downloads
(/templates/config/{name}, /templates/params/{name}), and /readme stay
reachable with no session — only the X-API-Key header applies to those, exactly
as described above.
13. Other endpoints
| Path | Purpose |
|---|---|
GET / |
Landing page with links to Swagger, the web console, Postman and this guide |
GET /healthz |
{"ok": true} liveness check |
GET /api/auth/whoami |
Check an API key: {"ok": true} with a valid X-API-Key, 401 otherwise |
GET /docs |
Swagger UI — easiest way to try a request |
GET /openapi.json |
Raw OpenAPI 3 schema (import into Postman / Insomnia / Bruno) |
GET /postman |
Download Postman collection JSON (if shipped) |
GET /templates |
Attacks JSON Templates page — explanation + per-attack downloads |
GET /templates/config.zip · GET /templates/params.zip |
Download all full-config / params-only templates as a ZIP |
GET /templates/config/{name} · GET /templates/params/{name} |
Download one template |
GET /guide |
This guide, rendered as HTML |
GET /readme |
Download this file as Markdown |
GET /demo |
Interactive demo with pre-computed attack results on built-in models |
GET /postman-import |
Postman import page |
GET /login · POST /login · GET /logout |
Browser login gate (if the operator enabled it) — see §12 |
GET /api/jobs/{job_id} · GET /api/jobs/{job_id}/result · DELETE /api/jobs/{job_id} |
Poll / fetch / cancel a background attack job — see §9 |
GET /api/object-detection/catalog · GET /api/object-detection/images/{id} |
Object-detection models, attacks, compatibility and built-in sample images — see §14 |
14. Object detection
Evasion attacks from IBM ART against object detectors. Unlike the families above you don't upload a model: you pick one of the built-in detectors and attack a built-in COCO sample (12 openly licensed images with ground-truth boxes) and/or your own JPEG/PNG images.
model |
Detector | Input · pixel range |
|---|---|---|
frcnn_mobilenet_v3_320 |
Faster R-CNN MobileNetV3-Large 320 FPN (torchvision) — fastest | 320² · [0, 1] |
frcnn_resnet50_fpn |
Faster R-CNN ResNet-50 FPN (torchvision) — slowest | 512² · [0, 1] |
yolov5s |
YOLOv5s v7.0 (ultralytics) | 416² · [0, 255] |
attack |
ART class | Kind | Main params (defaults) |
|---|---|---|---|
fgsm |
FastGradientMethod | full image, L∞ | eps 8 |
pgd |
ProjectedGradientDescent | full image, L∞ | eps 8 · eps_step 2 · max_iter 10 |
dpatch |
DPatch | universal patch (top-left) | patch_size 64 · learning_rate 8 · max_iter 40 |
robust_dpatch |
RobustDPatch | patch + random crop/brightness/rotation | patch_size 64 · patch_x/patch_y 16 · max_iter 30 · sample_size 2 · brightness 0.2 · crop 8 · rotations false |
adv_patch |
AdversarialPatchPyTorch | patch (Adam, rotation) | patch_size 64 · patch_x/patch_y 16 · learning_rate 8 · max_iter 40 · rotation_max 10 |
Pixel units: eps, eps_step and learning_rate are always in 0–255
pixel units, whatever the model — eps: 8 means 8/255 on the Faster R-CNN
models and 8 on YOLOv5. Out-of-range values are clamped server-side (the
catalog lists every range).
Request (multipart form)
| Field | Default | Notes |
|---|---|---|
model |
frcnn_mobilenet_v3_320 |
dropdown |
attack |
pgd |
dropdown |
params / params_file |
{} |
as in §2 — omitted keys use the defaults above |
images |
(empty) | comma-separated sample ids from the catalog, e.g. 000000206487.jpg,000000118209.jpg; empty and no uploads → the first 4 samples |
files |
— | your own JPEG/PNG images (≤ 10 MB each; at most 8 images per run in total) |
label_source |
ground_truth |
clean_predictions = attack/measure against the model's own clean detections (forced for uploads, which have no ground truth) |
score_threshold |
0.5 |
detections below it don't count for recall / precision / vanished boxes |
seed |
0 |
reproducibility |
# 1. what can I run?
curl -k https://127.0.0.1:8000/api/object-detection/catalog -H 'X-API-Key: your-key-here'
# 2. PGD on YOLOv5s against two COCO samples → ZIP
curl -k -X POST https://127.0.0.1:8000/api/attack/object-detection \
-H 'X-API-Key: your-key-here' \
-F model=yolov5s -F attack=pgd \
-F 'params={"eps":8,"eps_step":2,"max_iter":10}' \
-F images=000000206487.jpg,000000118209.jpg \
-o od_result.zip
# 3. your own images, JSON envelope
curl -k -X POST 'https://127.0.0.1:8000/api/attack/object-detection?format=json' \
-H 'X-API-Key: your-key-here' \
-F model=frcnn_mobilenet_v3_320 -F attack=fgsm \
-F files=@street.jpg -F files=@parking.png
Jobs work exactly as in §9: fast runs (seconds) return inline, slower ones
(ResNet-50, patch attacks with many iterations, several images) return 202 —
poll GET /api/jobs/{job_id}. DELETE /api/jobs/{job_id} also stops the
detector run at its next checkpoint (the current image / patch step finishes).
What you get back
ZIP (default) — ptai_object_detection_<attack>_<run>.zip:
| File | Content |
|---|---|
result.json |
the full report (below) |
img_<i>_clean.png · img_<i>_adv.png |
the exact model inputs before / after the attack (letterboxed S×S, lossless) |
img_<i>_pert.png |
amplified perturbation heatmap |
img_<i>_clean_boxes.jpg · img_<i>_adv_boxes.jpg |
annotated copies with detections |
patch.png |
the learned patch (patch attacks) |
datasets/adversarial_images.npz |
x float32 NHWC in [0,1], image_ids |
datasets/benign_and_adversarial.npz |
clean then adversarial x, is_adversarial, image_ids |
datasets/predictions_clean.json · predictions_adversarial.json |
detections in COCO results format |
?format=json — the usual envelope with family: "object_detection":
metrics.summary— clean vs adversarialmap50,map(mAP@[.5:.95]),recall,precision,fp_per_image,detections;vanished/vanished_pct(confident clean detections with no same-class IoU ≥ 0.5 match after the attack),new_detections,label_changes, and separateexecuted(ran within constraints) vsimpact(detector measurably worse) flags plus averdictsentence.metrics.budget(full-image attacks: ε and the measured max L∞) ormetrics.patch(size, area %, location);metrics.perturbation(L∞/L2 in 0–255 units, % pixels changed);metrics.timings(attack vs inference seconds);metrics.per_class(AP@50 clean vs adversarial).artifacts.images[]— per image: ground truth and clean / adversarial boxes ([x1,y1,x2,y2]in pixels of the letterboxed S×S model input, S =metrics.model.input_size), with category and score.
Compatibility
Every model × attack cell has an evidence state taken from ptAI's compatibility
mapping (documented example, API candidate, …) and is marked
validated: true once ptAI's own smoke test passed for the installed versions —
see cells in the catalog. A cell that isn't runnable returns 422 with the
reason. Overload is listed in the matrix but not runnable yet.
Errors follow §11; in addition:
| Status | When |
|---|---|
413 |
An uploaded image is larger than the per-file limit (10 MB) |
422 |
More than 8 images in one run, or the model × attack cell isn't runnable |
429 |
The detector service's queue is full — retry after a run finishes |
502 |
The detector service failed (a run ended in error, or the API couldn't authenticate to it — operator configuration) |
503 |
Object detection isn't enabled on this deployment, or its service is unreachable |