auditml 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- auditml-0.1.0/PKG-INFO +267 -0
- auditml-0.1.0/README.md +228 -0
- auditml-0.1.0/pyproject.toml +87 -0
- auditml-0.1.0/setup.cfg +4 -0
- auditml-0.1.0/src/auditml/__init__.py +20 -0
- auditml-0.1.0/src/auditml/attacks/__init__.py +87 -0
- auditml-0.1.0/src/auditml/attacks/attribute_inference.py +717 -0
- auditml-0.1.0/src/auditml/attacks/base.py +230 -0
- auditml-0.1.0/src/auditml/attacks/mia_shadow.py +662 -0
- auditml-0.1.0/src/auditml/attacks/mia_threshold.py +463 -0
- auditml-0.1.0/src/auditml/attacks/model_inversion.py +484 -0
- auditml-0.1.0/src/auditml/attacks/results.py +62 -0
- auditml-0.1.0/src/auditml/attacks/visualization.py +424 -0
- auditml-0.1.0/src/auditml/auditor.py +600 -0
- auditml-0.1.0/src/auditml/cli.py +421 -0
- auditml-0.1.0/src/auditml/config/__init__.py +37 -0
- auditml-0.1.0/src/auditml/config/loader.py +165 -0
- auditml-0.1.0/src/auditml/config/schema.py +148 -0
- auditml-0.1.0/src/auditml/data/__init__.py +21 -0
- auditml-0.1.0/src/auditml/data/datasets.py +193 -0
- auditml-0.1.0/src/auditml/data/transforms.py +55 -0
- auditml-0.1.0/src/auditml/defenses/__init__.py +0 -0
- auditml-0.1.0/src/auditml/models/__init__.py +65 -0
- auditml-0.1.0/src/auditml/models/base.py +42 -0
- auditml-0.1.0/src/auditml/models/cnn.py +74 -0
- auditml-0.1.0/src/auditml/models/resnet.py +112 -0
- auditml-0.1.0/src/auditml/py.typed +0 -0
- auditml-0.1.0/src/auditml/reporting/__init__.py +11 -0
- auditml-0.1.0/src/auditml/reporting/attack_comparison.py +234 -0
- auditml-0.1.0/src/auditml/reporting/attack_visualization.py +159 -0
- auditml-0.1.0/src/auditml/reporting/comparison.py +284 -0
- auditml-0.1.0/src/auditml/reporting/html_report.py +651 -0
- auditml-0.1.0/src/auditml/reporting/report_generator.py +316 -0
- auditml-0.1.0/src/auditml/reporting/visualization.py +223 -0
- auditml-0.1.0/src/auditml/training/__init__.py +12 -0
- auditml-0.1.0/src/auditml/training/dp_trainer.py +325 -0
- auditml-0.1.0/src/auditml/training/trainer.py +283 -0
- auditml-0.1.0/src/auditml/utils/__init__.py +14 -0
- auditml-0.1.0/src/auditml/utils/device.py +52 -0
- auditml-0.1.0/src/auditml/utils/experiment.py +131 -0
- auditml-0.1.0/src/auditml/utils/logging.py +58 -0
- auditml-0.1.0/src/auditml/utils/reproducibility.py +35 -0
- auditml-0.1.0/src/auditml/utils/rust_accel.py +170 -0
- auditml-0.1.0/src/auditml.egg-info/PKG-INFO +267 -0
- auditml-0.1.0/src/auditml.egg-info/SOURCES.txt +67 -0
- auditml-0.1.0/src/auditml.egg-info/dependency_links.txt +1 -0
- auditml-0.1.0/src/auditml.egg-info/entry_points.txt +2 -0
- auditml-0.1.0/src/auditml.egg-info/requires.txt +18 -0
- auditml-0.1.0/src/auditml.egg-info/top_level.txt +1 -0
- auditml-0.1.0/tests/test_attack_comparison.py +255 -0
- auditml-0.1.0/tests/test_attacks_base.py +249 -0
- auditml-0.1.0/tests/test_attribute_inference.py +288 -0
- auditml-0.1.0/tests/test_attribute_inference_eval.py +244 -0
- auditml-0.1.0/tests/test_cli.py +625 -0
- auditml-0.1.0/tests/test_config.py +151 -0
- auditml-0.1.0/tests/test_data.py +93 -0
- auditml-0.1.0/tests/test_dp_comparison.py +311 -0
- auditml-0.1.0/tests/test_dp_training.py +269 -0
- auditml-0.1.0/tests/test_integration.py +449 -0
- auditml-0.1.0/tests/test_mia_shadow.py +250 -0
- auditml-0.1.0/tests/test_mia_shadow_eval.py +215 -0
- auditml-0.1.0/tests/test_mia_threshold.py +207 -0
- auditml-0.1.0/tests/test_mia_threshold_eval.py +265 -0
- auditml-0.1.0/tests/test_model_inversion.py +239 -0
- auditml-0.1.0/tests/test_model_inversion_eval.py +201 -0
- auditml-0.1.0/tests/test_models.py +81 -0
- auditml-0.1.0/tests/test_public_api.py +326 -0
- auditml-0.1.0/tests/test_report_generator.py +330 -0
- auditml-0.1.0/tests/test_training.py +111 -0
auditml-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: auditml
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A privacy auditing toolkit for PyTorch machine learning models.
|
|
5
|
+
Author-email: Eeman Asghar <2022bba124@student.uet.edu.pk>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/EemanAsghar/AuditML-Privacy-Toolkit
|
|
8
|
+
Project-URL: Documentation, https://eemanasghar.github.io/AuditML-Privacy-Toolkit/
|
|
9
|
+
Project-URL: Repository, https://github.com/EemanAsghar/AuditML-Privacy-Toolkit
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/EemanAsghar/AuditML-Privacy-Toolkit/issues
|
|
11
|
+
Keywords: privacy,machine-learning,pytorch,membership-inference,differential-privacy
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: torch>=2.1.0
|
|
23
|
+
Requires-Dist: torchvision>=0.16.0
|
|
24
|
+
Requires-Dist: numpy>=1.26.0
|
|
25
|
+
Requires-Dist: pandas>=2.0.0
|
|
26
|
+
Requires-Dist: scikit-learn>=1.3.0
|
|
27
|
+
Requires-Dist: opacus>=1.4.0
|
|
28
|
+
Requires-Dist: matplotlib>=3.8.0
|
|
29
|
+
Requires-Dist: seaborn>=0.12.0
|
|
30
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
31
|
+
Requires-Dist: tqdm>=4.66.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: mypy>=1.7.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mkdocs-material>=9.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "dev"
|
|
39
|
+
|
|
40
|
+
# AuditML
|
|
41
|
+
|
|
42
|
+
**Privacy Auditing Toolkit for PyTorch Models**
|
|
43
|
+
|
|
44
|
+
[](https://www.python.org/)
|
|
45
|
+
[](https://pytorch.org/)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
[](https://eemanasghar.github.io/AuditML-Privacy-Toolkit/)
|
|
48
|
+
|
|
49
|
+
AuditML lets you measure how much private information leaks from a trained PyTorch model.
|
|
50
|
+
One function call audits your model for membership inference, model inversion, and attribute
|
|
51
|
+
inference attacks — with an interactive HTML report that opens automatically in your browser.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
| | |
|
|
58
|
+
|---|---|
|
|
59
|
+
| **Threshold MIA** | Exploit loss/confidence/entropy gaps between members and non-members |
|
|
60
|
+
| **Shadow Model MIA** | Train surrogate models to build a membership classifier |
|
|
61
|
+
| **Model Inversion** | Reconstruct per-class images via gradient ascent |
|
|
62
|
+
| **Attribute Inference** | Predict sensitive attributes from model outputs |
|
|
63
|
+
| **DP Training** | Opacus DP-SGD with automatic (ε, δ) accounting |
|
|
64
|
+
| **HTML Reports** | Interactive browser report — charts, ROC curves, risk level — auto-opens after audit |
|
|
65
|
+
| **Rust acceleration** | 11× faster threshold scanning, 3× faster SSIM (optional) |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install auditml
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import auditml
|
|
77
|
+
|
|
78
|
+
# Split your training set into members / non-members
|
|
79
|
+
member_loader, nonmember_loader = auditml.split_loaders(train_dataset)
|
|
80
|
+
|
|
81
|
+
# Audit your model — works with any nn.Module
|
|
82
|
+
results = auditml.audit(model, member_loader, nonmember_loader)
|
|
83
|
+
|
|
84
|
+
print(results.summary())
|
|
85
|
+
# ⚠ Leakage detected — highest AUC: 0.641 (mia_threshold)
|
|
86
|
+
|
|
87
|
+
# Open an interactive HTML report in your browser
|
|
88
|
+
results.report("./report", open_browser=True)
|
|
89
|
+
|
|
90
|
+
# Save results to reload later
|
|
91
|
+
results.save("audit_results.json")
|
|
92
|
+
results2 = auditml.AuditResults.load("audit_results.json")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Installation
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install auditml
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or from source:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://github.com/EemanAsghar/AuditML-Privacy-Toolkit.git
|
|
107
|
+
cd AuditML-Privacy-Toolkit
|
|
108
|
+
pip install -e ".[dev]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Optional: Rust extension (~11× speedup)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pip install maturin
|
|
115
|
+
cd rust && maturin build --release --out ../dist
|
|
116
|
+
pip install ../dist/auditml_rust-*.whl --force-reinstall
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Python API
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import auditml
|
|
125
|
+
from torch.utils.data import DataLoader
|
|
126
|
+
|
|
127
|
+
# 1. Split dataset into members / non-members
|
|
128
|
+
member_loader, nonmember_loader = auditml.split_loaders(
|
|
129
|
+
train_dataset,
|
|
130
|
+
member_ratio=0.5, # 50/50 split
|
|
131
|
+
batch_size=64,
|
|
132
|
+
seed=42,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# 2. Run all attacks (or pick specific ones)
|
|
136
|
+
results = auditml.audit(
|
|
137
|
+
model,
|
|
138
|
+
member_loader,
|
|
139
|
+
nonmember_loader,
|
|
140
|
+
attacks=["mia_threshold", "model_inversion"], # omit for all 4
|
|
141
|
+
device="auto", # auto | cpu | cuda | mps
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# 3. Inspect results
|
|
145
|
+
print(results.summary())
|
|
146
|
+
results["mia_threshold"].auc_roc # → 0.641
|
|
147
|
+
results.most_vulnerable() # → AttackSummary(mia_threshold: ...)
|
|
148
|
+
results.is_vulnerable() # → True
|
|
149
|
+
|
|
150
|
+
# 4. HTML report (auto-opens in browser)
|
|
151
|
+
results.report("./my_report", open_browser=True)
|
|
152
|
+
|
|
153
|
+
# 5. Save / reload without re-running
|
|
154
|
+
results.save("results.json")
|
|
155
|
+
results2 = auditml.AuditResults.load("results.json")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Shadow MIA with a custom architecture
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
results = auditml.audit(
|
|
162
|
+
model, member_loader, nonmember_loader,
|
|
163
|
+
attacks=["mia_shadow"],
|
|
164
|
+
shadow_model_fn=lambda: MyCNN(num_classes=10), # optional — MLP fallback used if omitted
|
|
165
|
+
)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## CLI
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Train a model
|
|
174
|
+
auditml train --config configs/mnist_baseline.yaml
|
|
175
|
+
|
|
176
|
+
# Run a full privacy audit (opens HTML report automatically)
|
|
177
|
+
auditml audit --config configs/mnist_baseline.yaml
|
|
178
|
+
|
|
179
|
+
# Run specific attacks
|
|
180
|
+
auditml audit --config configs/mnist_baseline.yaml --attack mia_threshold model_inversion
|
|
181
|
+
|
|
182
|
+
# Print resolved config as JSON
|
|
183
|
+
auditml show-config --config configs/mnist_baseline.yaml
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Config format
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
experiment_name: mnist_baseline
|
|
192
|
+
|
|
193
|
+
data:
|
|
194
|
+
dataset: mnist # mnist | cifar10 | cifar100
|
|
195
|
+
train_ratio: 0.5
|
|
196
|
+
|
|
197
|
+
model:
|
|
198
|
+
arch: cnn # cnn | resnet
|
|
199
|
+
|
|
200
|
+
training:
|
|
201
|
+
epochs: 30
|
|
202
|
+
batch_size: 64
|
|
203
|
+
learning_rate: 0.001
|
|
204
|
+
device: auto # auto | cpu | cuda | mps
|
|
205
|
+
|
|
206
|
+
attacks:
|
|
207
|
+
- mia_threshold
|
|
208
|
+
|
|
209
|
+
dp:
|
|
210
|
+
enabled: false
|
|
211
|
+
epsilon: 5.0
|
|
212
|
+
delta: 1.0e-5
|
|
213
|
+
max_grad_norm: 1.0
|
|
214
|
+
|
|
215
|
+
reporting:
|
|
216
|
+
output_dir: ./outputs
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Project structure
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
AuditML/
|
|
225
|
+
├── src/auditml/
|
|
226
|
+
│ ├── attacks/ # MIA, shadow, model inversion, attribute inference
|
|
227
|
+
│ ├── config/ # YAML schema → typed dataclasses
|
|
228
|
+
│ ├── data/ # Dataset loaders (MNIST, CIFAR-10, CIFAR-100)
|
|
229
|
+
│ ├── models/ # CNN + ResNet architectures
|
|
230
|
+
│ ├── training/ # Standard trainer + Opacus DP trainer
|
|
231
|
+
│ ├── reporting/ # Report generator, HTML report, comparison modules
|
|
232
|
+
│ └── utils/ # Device detection, Rust acceleration, logging
|
|
233
|
+
├── rust/ # Rust/PyO3 extension (optional)
|
|
234
|
+
├── configs/ # Example YAML configs
|
|
235
|
+
├── scripts/ # Experiment runners
|
|
236
|
+
├── benchmarks/ # Rust vs NumPy benchmark
|
|
237
|
+
├── tests/ # pytest suite — 380 tests
|
|
238
|
+
└── docs/ # MkDocs documentation
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Benchmark: Rust acceleration
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
find_best_threshold (N=10,000)
|
|
247
|
+
NumPy : 160.00 ms
|
|
248
|
+
Rust : 14.00 ms
|
|
249
|
+
Speedup : 11.4x ✅
|
|
250
|
+
|
|
251
|
+
compute_ssim (pixels=784)
|
|
252
|
+
NumPy : 21.0 µs
|
|
253
|
+
Rust : 7.0 µs
|
|
254
|
+
Speedup : 3.0x ✅
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Documentation
|
|
260
|
+
|
|
261
|
+
Full documentation at **[eemanasghar.github.io/AuditML-Privacy-Toolkit](https://eemanasghar.github.io/AuditML-Privacy-Toolkit/)**
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT © Eeman Asghar, NUML Faisalabad, 2025
|
auditml-0.1.0/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# AuditML
|
|
2
|
+
|
|
3
|
+
**Privacy Auditing Toolkit for PyTorch Models**
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[](https://pytorch.org/)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://eemanasghar.github.io/AuditML-Privacy-Toolkit/)
|
|
9
|
+
|
|
10
|
+
AuditML lets you measure how much private information leaks from a trained PyTorch model.
|
|
11
|
+
One function call audits your model for membership inference, model inversion, and attribute
|
|
12
|
+
inference attacks — with an interactive HTML report that opens automatically in your browser.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
| | |
|
|
19
|
+
|---|---|
|
|
20
|
+
| **Threshold MIA** | Exploit loss/confidence/entropy gaps between members and non-members |
|
|
21
|
+
| **Shadow Model MIA** | Train surrogate models to build a membership classifier |
|
|
22
|
+
| **Model Inversion** | Reconstruct per-class images via gradient ascent |
|
|
23
|
+
| **Attribute Inference** | Predict sensitive attributes from model outputs |
|
|
24
|
+
| **DP Training** | Opacus DP-SGD with automatic (ε, δ) accounting |
|
|
25
|
+
| **HTML Reports** | Interactive browser report — charts, ROC curves, risk level — auto-opens after audit |
|
|
26
|
+
| **Rust acceleration** | 11× faster threshold scanning, 3× faster SSIM (optional) |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install auditml
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import auditml
|
|
38
|
+
|
|
39
|
+
# Split your training set into members / non-members
|
|
40
|
+
member_loader, nonmember_loader = auditml.split_loaders(train_dataset)
|
|
41
|
+
|
|
42
|
+
# Audit your model — works with any nn.Module
|
|
43
|
+
results = auditml.audit(model, member_loader, nonmember_loader)
|
|
44
|
+
|
|
45
|
+
print(results.summary())
|
|
46
|
+
# ⚠ Leakage detected — highest AUC: 0.641 (mia_threshold)
|
|
47
|
+
|
|
48
|
+
# Open an interactive HTML report in your browser
|
|
49
|
+
results.report("./report", open_browser=True)
|
|
50
|
+
|
|
51
|
+
# Save results to reload later
|
|
52
|
+
results.save("audit_results.json")
|
|
53
|
+
results2 = auditml.AuditResults.load("audit_results.json")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install auditml
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or from source:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/EemanAsghar/AuditML-Privacy-Toolkit.git
|
|
68
|
+
cd AuditML-Privacy-Toolkit
|
|
69
|
+
pip install -e ".[dev]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Optional: Rust extension (~11× speedup)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install maturin
|
|
76
|
+
cd rust && maturin build --release --out ../dist
|
|
77
|
+
pip install ../dist/auditml_rust-*.whl --force-reinstall
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Python API
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import auditml
|
|
86
|
+
from torch.utils.data import DataLoader
|
|
87
|
+
|
|
88
|
+
# 1. Split dataset into members / non-members
|
|
89
|
+
member_loader, nonmember_loader = auditml.split_loaders(
|
|
90
|
+
train_dataset,
|
|
91
|
+
member_ratio=0.5, # 50/50 split
|
|
92
|
+
batch_size=64,
|
|
93
|
+
seed=42,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 2. Run all attacks (or pick specific ones)
|
|
97
|
+
results = auditml.audit(
|
|
98
|
+
model,
|
|
99
|
+
member_loader,
|
|
100
|
+
nonmember_loader,
|
|
101
|
+
attacks=["mia_threshold", "model_inversion"], # omit for all 4
|
|
102
|
+
device="auto", # auto | cpu | cuda | mps
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# 3. Inspect results
|
|
106
|
+
print(results.summary())
|
|
107
|
+
results["mia_threshold"].auc_roc # → 0.641
|
|
108
|
+
results.most_vulnerable() # → AttackSummary(mia_threshold: ...)
|
|
109
|
+
results.is_vulnerable() # → True
|
|
110
|
+
|
|
111
|
+
# 4. HTML report (auto-opens in browser)
|
|
112
|
+
results.report("./my_report", open_browser=True)
|
|
113
|
+
|
|
114
|
+
# 5. Save / reload without re-running
|
|
115
|
+
results.save("results.json")
|
|
116
|
+
results2 = auditml.AuditResults.load("results.json")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Shadow MIA with a custom architecture
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
results = auditml.audit(
|
|
123
|
+
model, member_loader, nonmember_loader,
|
|
124
|
+
attacks=["mia_shadow"],
|
|
125
|
+
shadow_model_fn=lambda: MyCNN(num_classes=10), # optional — MLP fallback used if omitted
|
|
126
|
+
)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## CLI
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Train a model
|
|
135
|
+
auditml train --config configs/mnist_baseline.yaml
|
|
136
|
+
|
|
137
|
+
# Run a full privacy audit (opens HTML report automatically)
|
|
138
|
+
auditml audit --config configs/mnist_baseline.yaml
|
|
139
|
+
|
|
140
|
+
# Run specific attacks
|
|
141
|
+
auditml audit --config configs/mnist_baseline.yaml --attack mia_threshold model_inversion
|
|
142
|
+
|
|
143
|
+
# Print resolved config as JSON
|
|
144
|
+
auditml show-config --config configs/mnist_baseline.yaml
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Config format
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
experiment_name: mnist_baseline
|
|
153
|
+
|
|
154
|
+
data:
|
|
155
|
+
dataset: mnist # mnist | cifar10 | cifar100
|
|
156
|
+
train_ratio: 0.5
|
|
157
|
+
|
|
158
|
+
model:
|
|
159
|
+
arch: cnn # cnn | resnet
|
|
160
|
+
|
|
161
|
+
training:
|
|
162
|
+
epochs: 30
|
|
163
|
+
batch_size: 64
|
|
164
|
+
learning_rate: 0.001
|
|
165
|
+
device: auto # auto | cpu | cuda | mps
|
|
166
|
+
|
|
167
|
+
attacks:
|
|
168
|
+
- mia_threshold
|
|
169
|
+
|
|
170
|
+
dp:
|
|
171
|
+
enabled: false
|
|
172
|
+
epsilon: 5.0
|
|
173
|
+
delta: 1.0e-5
|
|
174
|
+
max_grad_norm: 1.0
|
|
175
|
+
|
|
176
|
+
reporting:
|
|
177
|
+
output_dir: ./outputs
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Project structure
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
AuditML/
|
|
186
|
+
├── src/auditml/
|
|
187
|
+
│ ├── attacks/ # MIA, shadow, model inversion, attribute inference
|
|
188
|
+
│ ├── config/ # YAML schema → typed dataclasses
|
|
189
|
+
│ ├── data/ # Dataset loaders (MNIST, CIFAR-10, CIFAR-100)
|
|
190
|
+
│ ├── models/ # CNN + ResNet architectures
|
|
191
|
+
│ ├── training/ # Standard trainer + Opacus DP trainer
|
|
192
|
+
│ ├── reporting/ # Report generator, HTML report, comparison modules
|
|
193
|
+
│ └── utils/ # Device detection, Rust acceleration, logging
|
|
194
|
+
├── rust/ # Rust/PyO3 extension (optional)
|
|
195
|
+
├── configs/ # Example YAML configs
|
|
196
|
+
├── scripts/ # Experiment runners
|
|
197
|
+
├── benchmarks/ # Rust vs NumPy benchmark
|
|
198
|
+
├── tests/ # pytest suite — 380 tests
|
|
199
|
+
└── docs/ # MkDocs documentation
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Benchmark: Rust acceleration
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
find_best_threshold (N=10,000)
|
|
208
|
+
NumPy : 160.00 ms
|
|
209
|
+
Rust : 14.00 ms
|
|
210
|
+
Speedup : 11.4x ✅
|
|
211
|
+
|
|
212
|
+
compute_ssim (pixels=784)
|
|
213
|
+
NumPy : 21.0 µs
|
|
214
|
+
Rust : 7.0 µs
|
|
215
|
+
Speedup : 3.0x ✅
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Documentation
|
|
221
|
+
|
|
222
|
+
Full documentation at **[eemanasghar.github.io/AuditML-Privacy-Toolkit](https://eemanasghar.github.io/AuditML-Privacy-Toolkit/)**
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
MIT © Eeman Asghar, NUML Faisalabad, 2025
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel>=0.41.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "auditml"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A privacy auditing toolkit for PyTorch machine learning models."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Eeman Asghar", email = "2022bba124@student.uet.edu.pk"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["privacy", "machine-learning", "pytorch", "membership-inference", "differential-privacy"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
"torch>=2.1.0",
|
|
29
|
+
"torchvision>=0.16.0",
|
|
30
|
+
"numpy>=1.26.0",
|
|
31
|
+
"pandas>=2.0.0",
|
|
32
|
+
"scikit-learn>=1.3.0",
|
|
33
|
+
"opacus>=1.4.0",
|
|
34
|
+
"matplotlib>=3.8.0",
|
|
35
|
+
"seaborn>=0.12.0",
|
|
36
|
+
"pyyaml>=6.0.1",
|
|
37
|
+
"tqdm>=4.66.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/EemanAsghar/AuditML-Privacy-Toolkit"
|
|
42
|
+
Documentation = "https://eemanasghar.github.io/AuditML-Privacy-Toolkit/"
|
|
43
|
+
Repository = "https://github.com/EemanAsghar/AuditML-Privacy-Toolkit"
|
|
44
|
+
"Bug Tracker" = "https://github.com/EemanAsghar/AuditML-Privacy-Toolkit/issues"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=7.4.0",
|
|
49
|
+
"pytest-cov>=4.1.0",
|
|
50
|
+
"ruff>=0.1.0",
|
|
51
|
+
"mypy>=1.7.0",
|
|
52
|
+
"mkdocs-material>=9.0.0",
|
|
53
|
+
"mkdocstrings[python]>=0.24.0",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
auditml = "auditml.cli:main"
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.packages.find]
|
|
60
|
+
where = ["src"]
|
|
61
|
+
|
|
62
|
+
[tool.setuptools.package-data]
|
|
63
|
+
auditml = ["py.typed"]
|
|
64
|
+
|
|
65
|
+
[tool.ruff]
|
|
66
|
+
target-version = "py310"
|
|
67
|
+
line-length = 100
|
|
68
|
+
|
|
69
|
+
[tool.ruff.lint]
|
|
70
|
+
select = ["E", "F", "I", "N", "W", "UP"]
|
|
71
|
+
ignore = [
|
|
72
|
+
"N812", # torch.nn.functional as F is standard PyTorch convention
|
|
73
|
+
"E402", # sys.path manipulation before project imports is intentional in scripts
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint.per-file-ignores]
|
|
77
|
+
"src/auditml/reporting/html_report.py" = ["E501"] # HTML/CSS template strings
|
|
78
|
+
|
|
79
|
+
[tool.mypy]
|
|
80
|
+
python_version = "3.10"
|
|
81
|
+
warn_return_any = true
|
|
82
|
+
warn_unused_configs = true
|
|
83
|
+
disallow_untyped_defs = true
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
testpaths = ["tests"]
|
|
87
|
+
addopts = "-v"
|
auditml-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""AuditML — A privacy auditing toolkit for PyTorch models.
|
|
2
|
+
|
|
3
|
+
Quick start
|
|
4
|
+
-----------
|
|
5
|
+
>>> import auditml
|
|
6
|
+
>>> results = auditml.audit(model, train_loader, test_loader)
|
|
7
|
+
>>> print(results.summary())
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from auditml.auditor import AttackSummary, AuditResults, audit, split_loaders
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"audit",
|
|
16
|
+
"split_loaders",
|
|
17
|
+
"AuditResults",
|
|
18
|
+
"AttackSummary",
|
|
19
|
+
"__version__",
|
|
20
|
+
]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""AuditML privacy attack implementations.
|
|
2
|
+
|
|
3
|
+
All attacks inherit from ``BaseAttack`` and return ``AttackResult``.
|
|
4
|
+
Use ``get_attack()`` to instantiate an attack by name.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
import torch.nn as nn
|
|
12
|
+
|
|
13
|
+
from auditml.attacks.base import BaseAttack
|
|
14
|
+
from auditml.attacks.results import AttackResult
|
|
15
|
+
from auditml.config.schema import AttackType, AuditMLConfig
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
# Registry mapping AttackType → concrete class.
|
|
21
|
+
# Entries are added as each attack is implemented in Tasks 2.2–2.12.
|
|
22
|
+
# Using strings for lazy imports avoids circular-import issues and
|
|
23
|
+
# means we don't crash if an attack file has an uninstalled dependency.
|
|
24
|
+
_ATTACK_REGISTRY: dict[AttackType, str] = {
|
|
25
|
+
AttackType.MIA_THRESHOLD: "auditml.attacks.mia_threshold.ThresholdMIA",
|
|
26
|
+
AttackType.MIA_SHADOW: "auditml.attacks.mia_shadow.ShadowMIA",
|
|
27
|
+
AttackType.MODEL_INVERSION: "auditml.attacks.model_inversion.ModelInversion",
|
|
28
|
+
AttackType.ATTRIBUTE_INFERENCE: "auditml.attacks.attribute_inference.AttributeInference",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_attack(
|
|
33
|
+
attack_type: AttackType | str,
|
|
34
|
+
target_model: nn.Module,
|
|
35
|
+
config: AuditMLConfig,
|
|
36
|
+
device: str = "cpu",
|
|
37
|
+
**kwargs,
|
|
38
|
+
) -> BaseAttack:
|
|
39
|
+
"""Instantiate a concrete attack by type.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
attack_type:
|
|
44
|
+
Which attack to create — an ``AttackType`` enum value or its
|
|
45
|
+
string form (e.g. ``"mia_threshold"``).
|
|
46
|
+
target_model:
|
|
47
|
+
The trained model to attack.
|
|
48
|
+
config:
|
|
49
|
+
Full AuditML configuration.
|
|
50
|
+
device:
|
|
51
|
+
Torch device string.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
BaseAttack
|
|
56
|
+
A ready-to-run attack instance.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
ValueError
|
|
61
|
+
If *attack_type* is not recognised or not yet implemented.
|
|
62
|
+
"""
|
|
63
|
+
if isinstance(attack_type, str):
|
|
64
|
+
attack_type = AttackType(attack_type)
|
|
65
|
+
|
|
66
|
+
if attack_type not in _ATTACK_REGISTRY:
|
|
67
|
+
implemented = [k.value for k in _ATTACK_REGISTRY]
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"Attack {attack_type.value!r} is not yet implemented. "
|
|
70
|
+
f"Available: {implemented or 'none yet — coming in Tasks 2.2-2.12'}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Lazy import: "auditml.attacks.mia_threshold.ThresholdMIA" → class
|
|
74
|
+
dotted_path = _ATTACK_REGISTRY[attack_type]
|
|
75
|
+
module_path, class_name = dotted_path.rsplit(".", 1)
|
|
76
|
+
import importlib
|
|
77
|
+
module = importlib.import_module(module_path)
|
|
78
|
+
cls = getattr(module, class_name)
|
|
79
|
+
|
|
80
|
+
return cls(target_model=target_model, config=config, device=device, **kwargs)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
"AttackResult",
|
|
85
|
+
"BaseAttack",
|
|
86
|
+
"get_attack",
|
|
87
|
+
]
|