blink-gpu 0.1.0__py3-none-any.whl
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.
- blink/__init__.py +30 -0
- blink/__main__.py +117 -0
- blink/_analyzer.py +98 -0
- blink/_predictor.py +164 -0
- blink/_version.py +1 -0
- blink/py.typed +1 -0
- blink_gpu-0.1.0.dist-info/METADATA +315 -0
- blink_gpu-0.1.0.dist-info/RECORD +11 -0
- blink_gpu-0.1.0.dist-info/WHEEL +5 -0
- blink_gpu-0.1.0.dist-info/entry_points.txt +3 -0
- blink_gpu-0.1.0.dist-info/top_level.txt +1 -0
blink/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Blink — GPU Performance Predictor
|
|
3
|
+
==================================
|
|
4
|
+
Predict GPU execution time and memory usage for PyTorch models
|
|
5
|
+
*before* running them on GPU hardware.
|
|
6
|
+
|
|
7
|
+
Quick start
|
|
8
|
+
-----------
|
|
9
|
+
>>> from blink import BlinkPredictor
|
|
10
|
+
>>> predictor = BlinkPredictor()
|
|
11
|
+
>>> result = predictor.predict("resnet18", batch_size=32)
|
|
12
|
+
>>> print(f"Exec time: {result['exec_time_ms']:.1f} ms")
|
|
13
|
+
>>> print(f"Memory : {result['memory_mb']:.1f} MB")
|
|
14
|
+
|
|
15
|
+
Or with your own model:
|
|
16
|
+
>>> import torch.nn as nn
|
|
17
|
+
>>> model = nn.Sequential(nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10))
|
|
18
|
+
>>> result = BlinkPredictor().predict(model, batch_size=64)
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from blink._predictor import BlinkPredictor
|
|
23
|
+
from blink._analyzer import BlinkAnalyzer
|
|
24
|
+
from blink._version import __version__
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"BlinkPredictor",
|
|
28
|
+
"BlinkAnalyzer",
|
|
29
|
+
"__version__",
|
|
30
|
+
]
|
blink/__main__.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
blink.__main__
|
|
3
|
+
==============
|
|
4
|
+
CLI entry point for the blink-gpu package.
|
|
5
|
+
|
|
6
|
+
Usage
|
|
7
|
+
-----
|
|
8
|
+
# Quick prediction from the command line
|
|
9
|
+
blink predict resnet50 --batch-size 32
|
|
10
|
+
|
|
11
|
+
# Start the Streamlit dashboard
|
|
12
|
+
blink dashboard
|
|
13
|
+
|
|
14
|
+
# Start the FastAPI server
|
|
15
|
+
blink-server
|
|
16
|
+
blink-server --host 0.0.0.0 --port 8000 --workers 4
|
|
17
|
+
|
|
18
|
+
# Check installed version
|
|
19
|
+
blink --version
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main() -> None:
|
|
28
|
+
"""Entry point for the ``blink`` CLI command."""
|
|
29
|
+
parser = argparse.ArgumentParser(
|
|
30
|
+
prog="blink",
|
|
31
|
+
description="Blink — GPU performance predictor for PyTorch models",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument("--version", action="store_true", help="Show version and exit")
|
|
34
|
+
|
|
35
|
+
sub = parser.add_subparsers(dest="command")
|
|
36
|
+
|
|
37
|
+
# ── predict ───────────────────────────────────────────────────────────────
|
|
38
|
+
p_pred = sub.add_parser("predict", help="Predict GPU usage for a named model")
|
|
39
|
+
p_pred.add_argument("model", help='Model name, e.g. "resnet50"')
|
|
40
|
+
p_pred.add_argument("--batch-size", "-b", type=int, default=32)
|
|
41
|
+
p_pred.add_argument("--all-batches", action="store_true",
|
|
42
|
+
help="Also show batch sizes 1,2,4,8,16,64")
|
|
43
|
+
|
|
44
|
+
# ── dashboard ─────────────────────────────────────────────────────────────
|
|
45
|
+
p_dash = sub.add_parser("dashboard", help="Launch the Streamlit dashboard")
|
|
46
|
+
p_dash.add_argument("--port", type=int, default=8501)
|
|
47
|
+
|
|
48
|
+
# ── server ────────────────────────────────────────────────────────────────
|
|
49
|
+
p_srv = sub.add_parser("server", help="Launch the FastAPI REST server")
|
|
50
|
+
p_srv.add_argument("--host", default="0.0.0.0")
|
|
51
|
+
p_srv.add_argument("--port", type=int, default=8000)
|
|
52
|
+
p_srv.add_argument("--workers", "-w", type=int, default=1)
|
|
53
|
+
|
|
54
|
+
args = parser.parse_args()
|
|
55
|
+
|
|
56
|
+
# ── --version ──────────────────────────────────────────────────────────────
|
|
57
|
+
if args.version or args.command is None:
|
|
58
|
+
from blink._version import __version__
|
|
59
|
+
print(f"blink-gpu {__version__}")
|
|
60
|
+
if args.command is None and not args.version:
|
|
61
|
+
parser.print_help()
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
# ── predict ───────────────────────────────────────────────────────────────
|
|
65
|
+
if args.command == "predict":
|
|
66
|
+
from blink._predictor import BlinkPredictor
|
|
67
|
+
p = BlinkPredictor()
|
|
68
|
+
batch_sizes = ([1, 2, 4, 8, 16, args.batch_size, 64]
|
|
69
|
+
if args.all_batches else [args.batch_size])
|
|
70
|
+
batch_sizes = sorted(set(batch_sizes))
|
|
71
|
+
|
|
72
|
+
print(f"\n🔮 Blink prediction for '{args.model}'\n")
|
|
73
|
+
print(f"{'Batch':>6} {'Exec (ms)':>10} {'Memory (MB)':>12} CI-Exec (80%)")
|
|
74
|
+
print("-" * 60)
|
|
75
|
+
for bs in batch_sizes:
|
|
76
|
+
try:
|
|
77
|
+
r = p.predict(args.model, batch_size=bs)
|
|
78
|
+
ci = f"[{r['exec_time_lower']:.1f} – {r['exec_time_upper']:.1f}]"
|
|
79
|
+
print(f"{bs:>6} {r['exec_time_ms']:>10.2f} {r['memory_mb']:>12.1f} {ci}")
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"{bs:>6} ERROR: {e}")
|
|
82
|
+
print()
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# ── dashboard ─────────────────────────────────────────────────────────────
|
|
86
|
+
if args.command == "dashboard":
|
|
87
|
+
import subprocess
|
|
88
|
+
from pathlib import Path
|
|
89
|
+
dash = Path(__file__).parent.parent / "dashboard.py"
|
|
90
|
+
print(f"Launching Blink dashboard on http://localhost:{args.port} ...")
|
|
91
|
+
subprocess.run([
|
|
92
|
+
sys.executable, "-m", "streamlit", "run", str(dash),
|
|
93
|
+
f"--server.port={args.port}",
|
|
94
|
+
], check=True)
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
# ── server ────────────────────────────────────────────────────────────────
|
|
98
|
+
if args.command == "server":
|
|
99
|
+
serve(host=args.host, port=args.port, workers=args.workers)
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def serve(host: str = "0.0.0.0", port: int = 8000, workers: int = 1) -> None:
|
|
104
|
+
"""Entry point for the ``blink-server`` CLI command."""
|
|
105
|
+
import uvicorn
|
|
106
|
+
print(f"🚀 Starting Blink REST API on http://{host}:{port} | docs: /docs")
|
|
107
|
+
uvicorn.run(
|
|
108
|
+
"api.main:app",
|
|
109
|
+
host=host,
|
|
110
|
+
port=port,
|
|
111
|
+
workers=workers,
|
|
112
|
+
log_level="info",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
main()
|
blink/_analyzer.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
blink._analyzer
|
|
3
|
+
===============
|
|
4
|
+
BlinkAnalyzer — public-facing facade over ModelAnalyser.
|
|
5
|
+
Extracts architecture features from any PyTorch nn.Module.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
13
|
+
import torch.nn as nn
|
|
14
|
+
|
|
15
|
+
_ROOT = Path(__file__).parent.parent
|
|
16
|
+
if str(_ROOT) not in sys.path:
|
|
17
|
+
sys.path.insert(0, str(_ROOT))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BlinkAnalyzer:
|
|
21
|
+
"""
|
|
22
|
+
Extract architecture features from a PyTorch model.
|
|
23
|
+
|
|
24
|
+
Used internally by BlinkPredictor, but also useful standalone
|
|
25
|
+
if you want to inspect what Blink sees about your model.
|
|
26
|
+
|
|
27
|
+
Examples
|
|
28
|
+
--------
|
|
29
|
+
>>> from blink import BlinkAnalyzer
|
|
30
|
+
>>> import torchvision.models as tv
|
|
31
|
+
>>> model = tv.resnet18(weights=None)
|
|
32
|
+
>>> feats = BlinkAnalyzer().analyze(model)
|
|
33
|
+
>>> feats["flops"]
|
|
34
|
+
1814073344
|
|
35
|
+
>>> feats["num_conv_layers"]
|
|
36
|
+
20
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self._analyser = None
|
|
41
|
+
|
|
42
|
+
def _get(self):
|
|
43
|
+
if self._analyser is None:
|
|
44
|
+
from model_analyser import ModelAnalyzer
|
|
45
|
+
self._analyser = ModelAnalyzer()
|
|
46
|
+
return self._analyser
|
|
47
|
+
|
|
48
|
+
def analyze(
|
|
49
|
+
self,
|
|
50
|
+
model: "nn.Module",
|
|
51
|
+
input_shape: tuple = (3, 224, 224),
|
|
52
|
+
) -> dict:
|
|
53
|
+
"""
|
|
54
|
+
Extract architecture features from *model*.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
model : nn.Module
|
|
59
|
+
Any PyTorch model.
|
|
60
|
+
input_shape : tuple
|
|
61
|
+
(C, H, W) input shape. Default ``(3, 224, 224)``.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
dict
|
|
66
|
+
Architecture features used by Blink's prediction models, e.g.
|
|
67
|
+
``flops``, ``num_conv_layers``, ``model_size_mb``, etc.
|
|
68
|
+
"""
|
|
69
|
+
return self._get().extract_features(model, input_shape)
|
|
70
|
+
|
|
71
|
+
def summary(self, model: "nn.Module", input_shape: tuple = (3, 224, 224)) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Return a human-readable string summary of the model's key metrics.
|
|
74
|
+
|
|
75
|
+
Examples
|
|
76
|
+
--------
|
|
77
|
+
>>> print(BlinkAnalyzer().summary(model))
|
|
78
|
+
Model Architecture Summary
|
|
79
|
+
==========================
|
|
80
|
+
Parameters : 11,689,512
|
|
81
|
+
FLOPs : 1,814 M
|
|
82
|
+
Conv layers : 20
|
|
83
|
+
Size (MB) : 44.59
|
|
84
|
+
"""
|
|
85
|
+
feats = self.analyze(model, input_shape)
|
|
86
|
+
flops_m = feats.get('flops', 0) / 1e6
|
|
87
|
+
lines = [
|
|
88
|
+
"Model Architecture Summary",
|
|
89
|
+
"==========================",
|
|
90
|
+
f"Parameters : {feats.get('total_parameters', 0):>12,}",
|
|
91
|
+
f"FLOPs : {flops_m:>10.1f} M",
|
|
92
|
+
f"Conv layers : {feats.get('num_conv_layers', 0):>10}",
|
|
93
|
+
f"FC layers : {feats.get('num_fc_layers', 0):>10}",
|
|
94
|
+
f"BN layers : {feats.get('num_bn_layers', 0):>10}",
|
|
95
|
+
f"Model depth : {feats.get('model_depth', 0):>10}",
|
|
96
|
+
f"Size (MB) : {feats.get('model_size_mb', 0):>10.2f}",
|
|
97
|
+
]
|
|
98
|
+
return "\n".join(lines)
|
blink/_predictor.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
blink._predictor
|
|
3
|
+
================
|
|
4
|
+
BlinkPredictor — public-facing facade over gpu_predictor.GpuPredictor.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Union, List, Optional
|
|
12
|
+
|
|
13
|
+
import torch.nn as nn
|
|
14
|
+
|
|
15
|
+
# Ensure the repo root is on sys.path so the original modules are importable,
|
|
16
|
+
# regardless of how/where the package was installed.
|
|
17
|
+
_ROOT = Path(__file__).parent.parent
|
|
18
|
+
if str(_ROOT) not in sys.path:
|
|
19
|
+
sys.path.insert(0, str(_ROOT))
|
|
20
|
+
|
|
21
|
+
_DEFAULT_MODELS_DIR = _ROOT / "models"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BlinkPredictor:
|
|
25
|
+
"""
|
|
26
|
+
Predict GPU execution time and peak memory for a PyTorch model.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
models_dir : str or Path, optional
|
|
31
|
+
Path to the directory containing Blink's trained model files.
|
|
32
|
+
Defaults to ``<repo_root>/models``.
|
|
33
|
+
|
|
34
|
+
Examples
|
|
35
|
+
--------
|
|
36
|
+
>>> from blink import BlinkPredictor
|
|
37
|
+
>>> p = BlinkPredictor()
|
|
38
|
+
|
|
39
|
+
Predict with a pre-trained model name:
|
|
40
|
+
>>> result = p.predict("resnet50", batch_size=16)
|
|
41
|
+
>>> result["exec_time_ms"]
|
|
42
|
+
28.4
|
|
43
|
+
|
|
44
|
+
Predict with your own nn.Module:
|
|
45
|
+
>>> import torch.nn as nn
|
|
46
|
+
>>> model = nn.Sequential(nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10))
|
|
47
|
+
>>> result = p.predict(model, batch_size=32)
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# Supported named model aliases
|
|
51
|
+
NAMED_MODELS = {
|
|
52
|
+
"resnet18", "resnet50", "vgg16", "mobilenet_v2", "densenet121",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def __init__(self, models_dir: Optional[Union[str, Path]] = None):
|
|
56
|
+
self._models_dir = Path(models_dir) if models_dir else _DEFAULT_MODELS_DIR
|
|
57
|
+
self._predictor = None # lazy-loaded
|
|
58
|
+
|
|
59
|
+
# ── Lazy init ─────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
def _get_predictor(self):
|
|
62
|
+
if self._predictor is None:
|
|
63
|
+
from gpu_predictor import GPUPredictor
|
|
64
|
+
self._predictor = GPUPredictor(
|
|
65
|
+
model_path=str(self._models_dir / "random_forest_model.joblib"),
|
|
66
|
+
memory_model_path=str(self._models_dir / "memory_model.joblib"),
|
|
67
|
+
)
|
|
68
|
+
return self._predictor
|
|
69
|
+
|
|
70
|
+
# ── Public API ────────────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
def predict(
|
|
73
|
+
self,
|
|
74
|
+
model: Union[str, "nn.Module"],
|
|
75
|
+
batch_size: int = 32,
|
|
76
|
+
input_shape: tuple = (3, 224, 224),
|
|
77
|
+
) -> dict:
|
|
78
|
+
"""
|
|
79
|
+
Predict execution time and peak memory for *model* at *batch_size*.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
model : str or nn.Module
|
|
84
|
+
Either a model name string (e.g. ``"resnet18"``), or an
|
|
85
|
+
instantiated ``torch.nn.Module``.
|
|
86
|
+
batch_size : int
|
|
87
|
+
Batch size to predict for.
|
|
88
|
+
input_shape : tuple
|
|
89
|
+
Input tensor shape (C, H, W). Default ``(3, 224, 224)``.
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
dict with keys:
|
|
94
|
+
exec_time_ms : float — predicted execution time (ms)
|
|
95
|
+
exec_time_lower : float — 80 % CI lower bound (ms)
|
|
96
|
+
exec_time_upper : float — 80 % CI upper bound (ms)
|
|
97
|
+
memory_mb : float — predicted peak memory (MB)
|
|
98
|
+
memory_lower_mb : float — 80 % CI lower bound (MB)
|
|
99
|
+
memory_upper_mb : float — 80 % CI upper bound (MB)
|
|
100
|
+
source : str — which backend produced this prediction
|
|
101
|
+
"""
|
|
102
|
+
predictor = self._get_predictor()
|
|
103
|
+
|
|
104
|
+
# Resolve named model
|
|
105
|
+
if isinstance(model, str):
|
|
106
|
+
model = _load_named_model(model)
|
|
107
|
+
|
|
108
|
+
# Extract features
|
|
109
|
+
from model_analyser import ModelAnalyzer
|
|
110
|
+
analyser = ModelAnalyzer()
|
|
111
|
+
features = analyser.extract_features(model, input_shape)
|
|
112
|
+
features["batch_size"] = batch_size
|
|
113
|
+
|
|
114
|
+
raw = predictor.predict([features])
|
|
115
|
+
if isinstance(raw, list):
|
|
116
|
+
raw = raw[0]
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
"exec_time_ms": raw.get("exec_time_ms", 0.0),
|
|
120
|
+
"exec_time_lower": raw.get("exec_time_lower", 0.0),
|
|
121
|
+
"exec_time_upper": raw.get("exec_time_upper", 0.0),
|
|
122
|
+
"memory_mb": raw.get("memory_usage_mb", 0.0),
|
|
123
|
+
"memory_lower_mb": raw.get("memory_lower_mb", 0.0),
|
|
124
|
+
"memory_upper_mb": raw.get("memory_upper_mb", 0.0),
|
|
125
|
+
"source": raw.get("source", "blink"),
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
def predict_batch(
|
|
129
|
+
self,
|
|
130
|
+
model: Union[str, "nn.Module"],
|
|
131
|
+
batch_sizes: List[int],
|
|
132
|
+
input_shape: tuple = (3, 224, 224),
|
|
133
|
+
) -> List[dict]:
|
|
134
|
+
"""
|
|
135
|
+
Predict for multiple batch sizes in one call.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
list[dict]
|
|
140
|
+
One result dict per entry in *batch_sizes*.
|
|
141
|
+
"""
|
|
142
|
+
return [self.predict(model, bs, input_shape) for bs in batch_sizes]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
def _load_named_model(name: str) -> "nn.Module":
|
|
148
|
+
"""Load a torchvision pre-trained model by name."""
|
|
149
|
+
import torchvision.models as tv
|
|
150
|
+
name = name.lower().replace("-", "_")
|
|
151
|
+
loaders = {
|
|
152
|
+
"resnet18": lambda: tv.resnet18(weights=None),
|
|
153
|
+
"resnet50": lambda: tv.resnet50(weights=None),
|
|
154
|
+
"vgg16": lambda: tv.vgg16(weights=None),
|
|
155
|
+
"mobilenet_v2": lambda: tv.mobilenet_v2(weights=None),
|
|
156
|
+
"densenet121": lambda: tv.densenet121(weights=None),
|
|
157
|
+
}
|
|
158
|
+
if name not in loaders:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
f"Unknown model '{name}'. "
|
|
161
|
+
f"Supported names: {sorted(loaders)}. "
|
|
162
|
+
"Or pass an nn.Module directly."
|
|
163
|
+
)
|
|
164
|
+
return loaders[name]()
|
blink/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
blink/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561 — tells type checkers this package has type info
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blink-gpu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Predict GPU execution time & memory for PyTorch models — without running them.
|
|
5
|
+
Author-email: Aniket Mishra <aniket@blink-gpu.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Aniketxmishra/Blink_Main
|
|
8
|
+
Project-URL: Documentation, https://github.com/Aniketxmishra/Blink_Main#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/Aniketxmishra/Blink_Main.git
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/Aniketxmishra/Blink_Main/issues
|
|
11
|
+
Keywords: gpu,performance,prediction,pytorch,neural-network,profiling,machine-learning,explainability
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: System :: Hardware
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: pandas>=2.0
|
|
26
|
+
Requires-Dist: scikit-learn>=1.3
|
|
27
|
+
Requires-Dist: xgboost>=2.0
|
|
28
|
+
Requires-Dist: joblib>=1.3
|
|
29
|
+
Requires-Dist: thop>=0.1.1
|
|
30
|
+
Provides-Extra: full
|
|
31
|
+
Requires-Dist: optuna; extra == "full"
|
|
32
|
+
Requires-Dist: lightgbm; extra == "full"
|
|
33
|
+
Requires-Dist: pynvml; extra == "full"
|
|
34
|
+
Requires-Dist: shap>=0.44; extra == "full"
|
|
35
|
+
Requires-Dist: streamlit>=1.30; extra == "full"
|
|
36
|
+
Requires-Dist: plotly>=5.18; extra == "full"
|
|
37
|
+
Requires-Dist: matplotlib>=3.8; extra == "full"
|
|
38
|
+
Requires-Dist: seaborn>=0.13; extra == "full"
|
|
39
|
+
Provides-Extra: api
|
|
40
|
+
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
41
|
+
Requires-Dist: uvicorn[standard]>=0.27; extra == "api"
|
|
42
|
+
Requires-Dist: python-multipart; extra == "api"
|
|
43
|
+
Requires-Dist: httpx; extra == "api"
|
|
44
|
+
Provides-Extra: gnn
|
|
45
|
+
Requires-Dist: torch-geometric; extra == "gnn"
|
|
46
|
+
Provides-Extra: explain
|
|
47
|
+
Requires-Dist: shap>=0.44; extra == "explain"
|
|
48
|
+
Provides-Extra: dev
|
|
49
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
50
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
51
|
+
Requires-Dist: ruff; extra == "dev"
|
|
52
|
+
Requires-Dist: black; extra == "dev"
|
|
53
|
+
Requires-Dist: mypy; extra == "dev"
|
|
54
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
55
|
+
Provides-Extra: all
|
|
56
|
+
Requires-Dist: blink-gpu[api,dev,explain,full,gnn]; extra == "all"
|
|
57
|
+
|
|
58
|
+
# Blink 🔭
|
|
59
|
+
> **GPU Performance Predictor for Deep Learning Models**
|
|
60
|
+
|
|
61
|
+
Blink predicts **execution time** and **memory usage** of PyTorch neural networks on GPU without actually running them. It combines classical ML (XGBoost, Random Forest) with a Graph Neural Network (GNN) that encodes the computational graph of any model architecture.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 📋 Table of Contents
|
|
66
|
+
- [Overview](#overview)
|
|
67
|
+
- [Architecture](#architecture)
|
|
68
|
+
- [Project Structure](#project-structure)
|
|
69
|
+
- [Installation](#installation)
|
|
70
|
+
- [Usage](#usage)
|
|
71
|
+
- [Data Pipeline](#data-pipeline)
|
|
72
|
+
- [Model Performance](#model-performance)
|
|
73
|
+
- [Dashboard](#dashboard)
|
|
74
|
+
- [Paper Reproducibility](#paper-reproducibility)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Overview
|
|
79
|
+
|
|
80
|
+
Given a PyTorch model and a batch size, Blink answers:
|
|
81
|
+
- *How long will a forward pass take on this GPU?*
|
|
82
|
+
- *How much GPU memory will it consume?*
|
|
83
|
+
|
|
84
|
+
This is useful for:
|
|
85
|
+
- **Batch size optimization** before deployment
|
|
86
|
+
- **Hardware cost estimation** for training runs
|
|
87
|
+
- **NAS (Neural Architecture Search)** — filtering architectures by predicted cost
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Architecture
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
PyTorch Model
|
|
95
|
+
│
|
|
96
|
+
▼
|
|
97
|
+
┌─────────────────────┐
|
|
98
|
+
│ Feature Extractor │ ← layer counts, FLOPs, params, depth, width, skip connections
|
|
99
|
+
│ + GNN Extractor │ ← graph-based architecture encoding (ArchitectureGNN)
|
|
100
|
+
└─────────┬───────────┘
|
|
101
|
+
│
|
|
102
|
+
▼
|
|
103
|
+
┌─────────────────────┐
|
|
104
|
+
│ Prediction Models │
|
|
105
|
+
│ ───────────────── │
|
|
106
|
+
│ · XGBoost (tuned) │ ← main predictor (best MAPE)
|
|
107
|
+
│ · Random Forest │ ← ensemble comparison
|
|
108
|
+
│ · GNN Predictor │ ← graph-native, generalizes across architectures
|
|
109
|
+
│ · Linear / Ridge │ ← baselines
|
|
110
|
+
└─────────┬───────────┘
|
|
111
|
+
│
|
|
112
|
+
▼
|
|
113
|
+
Predicted: execution_time_ms, memory_mb
|
|
114
|
+
+ Uncertainty bounds (lower / upper)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Project Structure
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Blink/
|
|
123
|
+
├── dashboard.py # 🖥️ Main Streamlit web app (run this)
|
|
124
|
+
├── prediction_api.py # 🌐 Flask REST API
|
|
125
|
+
│
|
|
126
|
+
├── ── Core ML Modules ──
|
|
127
|
+
│ ├── model_profiler.py # GPU profiler (CUDA events)
|
|
128
|
+
│ ├── feature_extractor.py # Static feature extraction from nn.Module
|
|
129
|
+
│ ├── gnn_extractor.py # GNN-based graph feature extraction
|
|
130
|
+
│ ├── gnn_model.py # ArchitectureGNN model definition (PyG)
|
|
131
|
+
│ ├── prediction_model.py # Train XGBoost / RF / Linear models
|
|
132
|
+
│ ├── train_gnn.py # Train the GNN predictor
|
|
133
|
+
│ ├── train_memory_model.py# Train memory prediction model
|
|
134
|
+
│ ├── gpu_predictor.py # Inference class with caching & batch support
|
|
135
|
+
│ ├── model_analyser.py # Model complexity analysis utilities
|
|
136
|
+
│ ├── advanced_features.py # Extended feature engineering
|
|
137
|
+
│ ├── dynamic_predictor.py # Dynamic / online prediction
|
|
138
|
+
│ ├── gpu_info.py # GPU metadata (pynvml)
|
|
139
|
+
│ ├── workload_scheduler.py# Batch workload scheduler
|
|
140
|
+
│ └── performance_monitor.py
|
|
141
|
+
│
|
|
142
|
+
├── scripts/ # 🔬 Experiment & data scripts
|
|
143
|
+
│ ├── collect_data.py # Profile CNN/Transformer/custom models → data/raw/
|
|
144
|
+
│ ├── enhance_dataset.py # Augment dataset (more batch sizes / models)
|
|
145
|
+
│ ├── diverse_architectures.py # Profile diverse arch families
|
|
146
|
+
│ ├── ablation_study.py # 5-condition ablation (Table II in paper)
|
|
147
|
+
│ ├── generate_paper_figures.py # Reproduce all paper figures
|
|
148
|
+
│ └── generate_paper_tables.py # Reproduce paper tables
|
|
149
|
+
│
|
|
150
|
+
├── tests/ # ✅ Test suite
|
|
151
|
+
│ ├── test_diverse_models.py
|
|
152
|
+
│ ├── test_predictors.py
|
|
153
|
+
│ ├── test_profiler.py
|
|
154
|
+
│ ├── test_gnn_scaling.py
|
|
155
|
+
│ └── evaluate_gnn_vs_xgb.py
|
|
156
|
+
│
|
|
157
|
+
├── data/
|
|
158
|
+
│ ├── raw/ # Raw profiling CSVs (gitignored)
|
|
159
|
+
│ ├── processed/ # Feature-engineered CSVs
|
|
160
|
+
│ ├── enriched/ # Final training-ready dataset
|
|
161
|
+
│ └── feedback_log.csv # Online feedback loop log
|
|
162
|
+
│
|
|
163
|
+
├── models/ # Serialized model artifacts (gitignored)
|
|
164
|
+
│ ├── xgboost_(tuned)_model.joblib
|
|
165
|
+
│ ├── random_forest_model.joblib
|
|
166
|
+
│ ├── gnn_predictor.pth
|
|
167
|
+
│ ├── memory_model.joblib
|
|
168
|
+
│ └── ...
|
|
169
|
+
│
|
|
170
|
+
├── results/
|
|
171
|
+
│ ├── figures/ # Paper figures (PNG)
|
|
172
|
+
│ ├── ablation_study_table.csv
|
|
173
|
+
│ ├── gnn_scaling_table.csv
|
|
174
|
+
│ └── ...
|
|
175
|
+
│
|
|
176
|
+
├── templates/index.html # HTML template for web interface
|
|
177
|
+
├── legacy/ # Archived / superseded scripts
|
|
178
|
+
├── requirements.txt
|
|
179
|
+
└── .gitignore
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Installation
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# 1. Clone the repo
|
|
188
|
+
git clone <your-repo-url>
|
|
189
|
+
cd Blink
|
|
190
|
+
|
|
191
|
+
# 2. Create a virtual environment
|
|
192
|
+
python -m venv venv
|
|
193
|
+
venv\Scripts\activate # Windows
|
|
194
|
+
# source venv/bin/activate # Linux/macOS
|
|
195
|
+
|
|
196
|
+
# 3. Install dependencies
|
|
197
|
+
pip install -r requirements.txt
|
|
198
|
+
|
|
199
|
+
# 4. Install PyTorch Geometric (match your CUDA version)
|
|
200
|
+
# See: https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html
|
|
201
|
+
pip install torch-geometric
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Requirements:** NVIDIA GPU with CUDA, Python ≥ 3.10
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Usage
|
|
209
|
+
|
|
210
|
+
### 1. Launch the Dashboard
|
|
211
|
+
```bash
|
|
212
|
+
streamlit run dashboard.py
|
|
213
|
+
```
|
|
214
|
+
Features: live model prediction, batch size optimizer, model comparison, performance monitor.
|
|
215
|
+
|
|
216
|
+
### 2. Collect Profiling Data
|
|
217
|
+
```bash
|
|
218
|
+
python scripts/collect_data.py --batch-sizes 1 4 16 32 64
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 3. Train Prediction Models
|
|
222
|
+
```bash
|
|
223
|
+
# Train XGBoost / RF / Linear baseline models
|
|
224
|
+
python prediction_model.py
|
|
225
|
+
|
|
226
|
+
# Train GNN predictor
|
|
227
|
+
python train_gnn.py
|
|
228
|
+
|
|
229
|
+
# Train memory model
|
|
230
|
+
python train_memory_model.py
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 4. Run Ablation Study
|
|
234
|
+
```bash
|
|
235
|
+
python scripts/ablation_study.py
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 5. Predict via Python API
|
|
239
|
+
```python
|
|
240
|
+
from gpu_predictor import GPUPredictor
|
|
241
|
+
import torchvision.models as models
|
|
242
|
+
|
|
243
|
+
predictor = GPUPredictor()
|
|
244
|
+
model = models.resnet50(pretrained=False)
|
|
245
|
+
result = predictor.predict_for_custom_model(model, batch_size=16)
|
|
246
|
+
print(result)
|
|
247
|
+
# {'execution_time_ms': 12.4, 'memory_mb': 1820, 'confidence_lower': 11.1, ...}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Data Pipeline
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
collect_data.py
|
|
256
|
+
└─▶ data/raw/*.csv (GPU profiling measurements)
|
|
257
|
+
│
|
|
258
|
+
▼
|
|
259
|
+
feature_extractor.py
|
|
260
|
+
└─▶ data/processed/*.csv (static model features)
|
|
261
|
+
│
|
|
262
|
+
▼
|
|
263
|
+
enhance_dataset.py
|
|
264
|
+
└─▶ data/enriched/*.csv (augmented, training-ready)
|
|
265
|
+
│
|
|
266
|
+
▼
|
|
267
|
+
prediction_model.py / train_gnn.py
|
|
268
|
+
└─▶ models/ (trained predictors)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Model Performance
|
|
274
|
+
|
|
275
|
+
Results on held-out test set (20% split):
|
|
276
|
+
|
|
277
|
+
| Model | Exec Time MAPE | Memory MAPE | Notes |
|
|
278
|
+
|---|---|---|---|
|
|
279
|
+
| XGBoost (tuned) | ~8% | ~6% | Best overall |
|
|
280
|
+
| Random Forest | ~11% | ~9% | Robust baseline |
|
|
281
|
+
| GNN Predictor | ~10% | ~8% | Best on unseen architectures |
|
|
282
|
+
| Linear Regression | ~22% | ~19% | Baseline |
|
|
283
|
+
|
|
284
|
+
*(Full ablation study results: `results/ablation_study_table.csv`)*
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Dashboard
|
|
289
|
+
|
|
290
|
+
The Streamlit dashboard (`dashboard.py`) provides:
|
|
291
|
+
|
|
292
|
+
| Tab | Description |
|
|
293
|
+
|---|---|
|
|
294
|
+
| 🎯 Prediction | Predict execution time & memory for standard or custom models |
|
|
295
|
+
| ⚡ Batch Optimizer | Find optimal batch size within a memory budget |
|
|
296
|
+
| 📊 Model Comparison | Compare predictions across multiple architectures |
|
|
297
|
+
| 📈 Performance Monitor | Live GPU utilization and prediction history |
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Paper Reproducibility
|
|
302
|
+
|
|
303
|
+
To reproduce all paper figures and tables:
|
|
304
|
+
```bash
|
|
305
|
+
python scripts/generate_paper_figures.py
|
|
306
|
+
python scripts/generate_paper_tables.py
|
|
307
|
+
python scripts/ablation_study.py
|
|
308
|
+
```
|
|
309
|
+
Outputs saved to `results/figures/`.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
blink/__init__.py,sha256=UDhgI4dDpgE1Q3YVLm74C52xHua6Hefk9BGfjwRi1mY,905
|
|
2
|
+
blink/__main__.py,sha256=mXMtOZ4oRM3RYFJC09QjPZar2THUA17o0iw9vELk8pw,5209
|
|
3
|
+
blink/_analyzer.py,sha256=3i0CDjSdvAM2GFPVilbQi2WXPN7bUpdqudHKt7SxAUQ,3009
|
|
4
|
+
blink/_predictor.py,sha256=wcvqUS_oFwsu0jpTT7_llP6DPbU12-Wq-0NFuaxjLLg,6053
|
|
5
|
+
blink/_version.py,sha256=QTYqXqSTHFRkM9TEgpDFcHvwLbvqHDqvqfQ9EiXkcAM,23
|
|
6
|
+
blink/py.typed,sha256=lXMgLeTOnHBTwAn-DccqgnOKJtar2iZt2pXnesWpLfg,78
|
|
7
|
+
blink_gpu-0.1.0.dist-info/METADATA,sha256=8iiaw8VyMirwvwUhv6G7CnwbLWCBePpCcieQJQKl4eU,10656
|
|
8
|
+
blink_gpu-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
9
|
+
blink_gpu-0.1.0.dist-info/entry_points.txt,sha256=UdF6SJDELNZ97RJGcoxSRmoNYXnSe_KbIwaGkkiC0Gw,82
|
|
10
|
+
blink_gpu-0.1.0.dist-info/top_level.txt,sha256=sU9Oyo7qzPcr4N7WRlLbNaNIJxCBOcWERCHfjqincMQ,6
|
|
11
|
+
blink_gpu-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blink
|