autohetero 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.
Files changed (47) hide show
  1. autohetero-0.1.0/LICENSE +21 -0
  2. autohetero-0.1.0/PKG-INFO +254 -0
  3. autohetero-0.1.0/README.md +229 -0
  4. autohetero-0.1.0/autohetero/__init__.py +15 -0
  5. autohetero-0.1.0/autohetero/calibrate.py +242 -0
  6. autohetero-0.1.0/autohetero/devices.py +88 -0
  7. autohetero-0.1.0/autohetero/dispatch.py +177 -0
  8. autohetero-0.1.0/autohetero/executor.py +112 -0
  9. autohetero-0.1.0/autohetero/features.py +51 -0
  10. autohetero-0.1.0/autohetero/history.py +182 -0
  11. autohetero-0.1.0/autohetero/monitor.py +83 -0
  12. autohetero-0.1.0/autohetero/ops/__init__.py +33 -0
  13. autohetero-0.1.0/autohetero/ops/analytics.py +23 -0
  14. autohetero-0.1.0/autohetero/ops/image.py +43 -0
  15. autohetero-0.1.0/autohetero/ops/inputs.py +42 -0
  16. autohetero-0.1.0/autohetero/ops/models.py +39 -0
  17. autohetero-0.1.0/autohetero/ops/science.py +15 -0
  18. autohetero-0.1.0/autohetero/predictor.py +146 -0
  19. autohetero-0.1.0/autohetero/report.py +45 -0
  20. autohetero-0.1.0/autohetero.egg-info/PKG-INFO +254 -0
  21. autohetero-0.1.0/autohetero.egg-info/SOURCES.txt +45 -0
  22. autohetero-0.1.0/autohetero.egg-info/dependency_links.txt +1 -0
  23. autohetero-0.1.0/autohetero.egg-info/requires.txt +13 -0
  24. autohetero-0.1.0/autohetero.egg-info/top_level.txt +1 -0
  25. autohetero-0.1.0/pyproject.toml +38 -0
  26. autohetero-0.1.0/setup.cfg +4 -0
  27. autohetero-0.1.0/tests/test_calibrate.py +91 -0
  28. autohetero-0.1.0/tests/test_collect.py +15 -0
  29. autohetero-0.1.0/tests/test_crossover.py +23 -0
  30. autohetero-0.1.0/tests/test_demo.py +68 -0
  31. autohetero-0.1.0/tests/test_devices.py +64 -0
  32. autohetero-0.1.0/tests/test_dispatch.py +185 -0
  33. autohetero-0.1.0/tests/test_eval_week5.py +40 -0
  34. autohetero-0.1.0/tests/test_eval_week8.py +83 -0
  35. autohetero-0.1.0/tests/test_executor.py +133 -0
  36. autohetero-0.1.0/tests/test_experiments.py +53 -0
  37. autohetero-0.1.0/tests/test_features.py +57 -0
  38. autohetero-0.1.0/tests/test_history.py +132 -0
  39. autohetero-0.1.0/tests/test_monitor.py +26 -0
  40. autohetero-0.1.0/tests/test_ops_data.py +41 -0
  41. autohetero-0.1.0/tests/test_ops_image.py +32 -0
  42. autohetero-0.1.0/tests/test_ops_models.py +28 -0
  43. autohetero-0.1.0/tests/test_ops_parity.py +42 -0
  44. autohetero-0.1.0/tests/test_predictor.py +83 -0
  45. autohetero-0.1.0/tests/test_report.py +42 -0
  46. autohetero-0.1.0/tests/test_trials.py +76 -0
  47. autohetero-0.1.0/tests/test_week6.py +58 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SRIVATHSA B S
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: autohetero
3
+ Version: 0.1.0
4
+ Summary: Self-adaptive, zero-configuration CPU-GPU workload dispatch for Python applications
5
+ Author: SRIVATHSA B S
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/VARITHSA/autohetero
8
+ Project-URL: Repository, https://github.com/VARITHSA/autohetero
9
+ Project-URL: Issues, https://github.com/VARITHSA/autohetero/issues
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: torch>=2.1
14
+ Requires-Dist: torchvision
15
+ Requires-Dist: numpy
16
+ Requires-Dist: scikit-learn
17
+ Requires-Dist: psutil
18
+ Requires-Dist: nvidia-ml-py>=12
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: matplotlib; extra == "dev"
22
+ Provides-Extra: demo
23
+ Requires-Dist: streamlit; extra == "demo"
24
+ Dynamic: license-file
25
+
26
+ # AutoHetero
27
+
28
+ ![Python](https://img.shields.io/badge/python-3.11%2B-blue) ![PyTorch](https://img.shields.io/badge/pytorch-2.x-orange) ![License](https://img.shields.io/badge/license-MIT-green)
29
+
30
+ **AutoHetero runs each PyTorch call on the CPU, the GPU, or both — whichever is fastest.**
31
+
32
+ A GPU isn't always the faster choice. For small inputs, moving data to the GPU costs more than the work itself, and a GPU that's busy with another job can end up slower than the CPU. I built AutoHetero to make that decision automatically: it benchmarks your machine once, predicts the fastest device for every call, and shifts work to the CPU when the GPU falls behind.
33
+
34
+ ## Features
35
+
36
+ - **One line to enable.** No configuration, no `.to("cuda")`.
37
+ - **Tensors or NumPy.** Results come back in the same type and on the same device you passed in.
38
+ - **Hybrid mode.** Large batches can be split across the CPU and GPU at the same time.
39
+ - **Adapts while running.** If the GPU slows down mid-call, the rest of the work is rebalanced.
40
+ - **Safe fallback.** GPU errors (like running out of memory) rerun the call on the CPU instead of crashing.
41
+ - **Transparent.** A short log line for every decision, and `autohetero.report()` shows what ran where.
42
+
43
+ ## Requirements
44
+
45
+ - Python 3.11+ and PyTorch 2.x
46
+ - An NVIDIA GPU with a CUDA build of PyTorch. Without one, AutoHetero still works and runs everything on the CPU.
47
+
48
+ ## Installation
49
+
50
+ **To use it in your own project**, install it from PyPI into that project's environment:
51
+
52
+ ```bash
53
+ pip install autohetero
54
+ ```
55
+
56
+ **To run the demos, tests and benchmarks**, clone the repository:
57
+
58
+ ```bash
59
+ git clone https://github.com/VARITHSA/autohetero.git
60
+ cd autohetero
61
+ pip install -e . # add ".[dev]" for tests, ".[demo]" for the demo
62
+ ```
63
+
64
+ Check that PyTorch can see your GPU (it should print `True`):
65
+
66
+ ```bash
67
+ python -c "import torch; print(torch.cuda.is_available())"
68
+ ```
69
+
70
+ If it prints `False`, install the CUDA build of PyTorch for your driver from [pytorch.org](https://pytorch.org/get-started/locally/).
71
+
72
+ ## Try it
73
+
74
+ From the cloned repository:
75
+
76
+ 1. **With and without, side by side.** This runs the same image pipeline as plain PyTorch on the CPU, by hand on the GPU, and with AutoHetero, checks that all three give the same answer, and prints their times:
77
+
78
+ ```bash
79
+ python demo/compare.py
80
+ ```
81
+
82
+ 2. **The demo app.** Install the demo extra, then start the app; it opens in your browser:
83
+
84
+ ```bash
85
+ pip install -e ".[demo]"
86
+ ```
87
+
88
+ ```bash
89
+ streamlit run demo/app.py
90
+ ```
91
+
92
+ Pick a batch size and resolution and click **Run**. Turn on **GPU stress** to watch AutoHetero move work to the CPU. The **playground** page in the sidebar runs any built-in op at any size.
93
+
94
+ 3. **The measured results.** Open `demo/showcase.ipynb` in Jupyter (`pip install jupyter` first). It reads the results from my RTX 3050 runs, so it works on a machine without a GPU.
95
+
96
+ ## Using it in your code
97
+
98
+ 1. Import AutoHetero and call `autohetero.enable()` once, at the start of your program.
99
+ 2. Use the built-in ops (`autohetero.ops.*`), or put `@autohetero.auto` on your own functions.
100
+ 3. Keep your data on the CPU, as usual. Don't call `.to("cuda")`; AutoHetero moves the data and brings the result back.
101
+ 4. Call `autohetero.report()` at the end to see where each call ran.
102
+
103
+ **Built-in ops** — one line:
104
+
105
+ ```python
106
+ import torch
107
+ import autohetero
108
+
109
+ autohetero.enable() # the one line: built-in ops now run where they're fastest
110
+
111
+ images = torch.rand(16, 3, 720, 1280) # on the CPU, as usual
112
+ edges = autohetero.ops.sobel(autohetero.ops.blur(images)) # each op is dispatched; the result comes back on the CPU
113
+ ```
114
+
115
+ **Your own functions** — one decorator:
116
+
117
+ ```python
118
+ import numpy as np
119
+ import torch
120
+ import autohetero
121
+
122
+ @autohetero.auto(splittable=True)
123
+ def normalize(x):
124
+ # x arrives as a torch tensor on whichever device AutoHetero chose
125
+ return (x - x.mean(dim=1, keepdim=True)) / x.std(dim=1, keepdim=True)
126
+
127
+ out = normalize(np.random.rand(10_000, 512).astype(np.float32)) # numpy in -> numpy out
128
+ ```
129
+
130
+ Models work too. Pass them in as arguments:
131
+
132
+ ```python
133
+ import torchvision
134
+
135
+ model = torchvision.models.resnet18(weights=None).eval()
136
+
137
+ @autohetero.auto(splittable=True)
138
+ def classify(images, model):
139
+ with torch.no_grad():
140
+ return model(images).argmax(1)
141
+
142
+ batch = torch.rand(64, 3, 224, 224)
143
+ labels = classify(batch, model)
144
+ ```
145
+
146
+ **Manual override**, when you know better:
147
+
148
+ ```python
149
+ with autohetero.force("cpu"): # or "gpu", or "hybrid"
150
+ labels = classify(batch, model)
151
+ ```
152
+
153
+ **See what happened:**
154
+
155
+ ```python
156
+ autohetero.report()
157
+ ```
158
+
159
+ ```
160
+ function calls modes time saved vs GPU (est.) fallbacks switches
161
+ -------- ----- --------------- -------- ------------------- --------- --------
162
+ blur 3 GPU 3 91.2 ms 12.0 ms 0 0
163
+ classify 2 HYBRID 1, GPU 1 612.0 ms 48.0 ms 0 1
164
+ ```
165
+
166
+ The first call on a new machine runs a one-time calibration (about 30 seconds).
167
+
168
+ ## How it works
169
+
170
+ 1. **Calibrate.** On first use, AutoHetero times its built-in ops on the CPU and GPU and caches the results in `~/.cache/autohetero/`.
171
+ 2. **Predict.** A small learned model (random forests) estimates how long each call will take on each device. Your own functions are predicted from their own past runs; the first call measures both devices.
172
+ 3. **Run.** Long calls run in chunks. If a chunk takes more than 1.5× longer than expected, the rest of the call is split between the CPU and GPU by their measured speeds.
173
+ 4. **Learn.** Every call is logged with its predicted and actual time, so predictions improve over time. Call `autohetero.retrain()` to update the model.
174
+
175
+ The full design is in [DESIGN.md](https://github.com/VARITHSA/autohetero/blob/main/DESIGN.md).
176
+
177
+ ## API
178
+
179
+ | Function | What it does |
180
+ |----------|--------------|
181
+ | `autohetero.enable()` | Turns on dispatch for the built-in ops and calibrates the machine (once). |
182
+ | `@autohetero.auto(splittable=False, batch_dim=0)` | Runs every call of a function on the fastest option. Set `splittable=True` only if each output row depends only on the matching input row; that allows chunking and Hybrid mode. |
183
+ | `autohetero.force(mode)` | Context manager: run on `"cpu"`, `"gpu"` or `"hybrid"`. Applies to the current thread only. |
184
+ | `autohetero.report()` | Prints (and returns) what ran where, total time, and the estimated time saved. |
185
+ | `autohetero.retrain()` | Updates the prediction model from the calls recorded so far. |
186
+
187
+ ### Tips for `@auto` functions
188
+
189
+ - Use torch operations — inputs arrive as tensors, even if you passed NumPy arrays.
190
+ - Don't modify inputs in place (`x += 1`).
191
+ - Pass models as arguments, not as globals.
192
+ - If the GPU fails, the call reruns on the CPU, so avoid side effects you can't repeat.
193
+
194
+ ## Built-in ops
195
+
196
+ | Area | Ops | Can be split across devices |
197
+ |------|-----|-----------------------------|
198
+ | Images | `blur`, `resize`, `sobel` | yes |
199
+ | Models | `resnet18`, `mobilenetv2` (random weights, for benchmarking) | yes |
200
+ | Data | `filter`, `sort`, `groupby` | `filter` only |
201
+ | Science | `matmul`, `fft` | yes |
202
+
203
+ ## Configuration
204
+
205
+ There's nothing to configure. Two options if you need them:
206
+
207
+ - `AUTOHETERO_QUIET=1` turns off the log lines.
208
+ - Delete `~/.cache/autohetero/` to recalibrate. (It also recalibrates on its own when the GPU, driver or PyTorch version changes.)
209
+
210
+ ## Tests
211
+
212
+ ```bash
213
+ pip install -e ".[dev]"
214
+ pytest # runs without a GPU
215
+ pytest -m gpu # needs an NVIDIA GPU
216
+ ```
217
+
218
+ ## Benchmarks
219
+
220
+ The evaluation scripts reproduce the results for the project's three research questions. Run them on a machine with an NVIDIA GPU:
221
+
222
+ ```bash
223
+ python bench/collect.py # benchmark dataset
224
+ python bench/experiments.py all # idle / GPU-stress / CPU-stress experiments
225
+ python eval/overhead.py # dispatch overhead
226
+ python eval/crossover.py # then the figures and tables, written to eval/out/
227
+ python eval/rq1.py
228
+ python eval/rq2.py
229
+ python eval/hybrid_gain.py
230
+ python eval/rq3.py
231
+ ```
232
+
233
+ [REQUIREMENTS.md](https://github.com/VARITHSA/autohetero/blob/main/REQUIREMENTS.md) lists every requirement and its current status.
234
+
235
+ ## Project structure
236
+
237
+ ```
238
+ autohetero/ the library (dispatch, prediction, execution, built-in ops)
239
+ bench/ benchmark collection, experiments, load generators
240
+ eval/ scripts that produce the figures and tables
241
+ demo/ Streamlit demo
242
+ tests/ test suite
243
+ ```
244
+
245
+ ## Limitations
246
+
247
+ - Built for one machine with one NVIDIA GPU, for inference and data processing (not training).
248
+ - Hybrid mode only applies to splittable calls with at least 2 items.
249
+ - Very short calls aren't chunked, so they can't be rebalanced mid-call.
250
+ - Each call adds about 10 µs of overhead (a few ms the first time a new input size is seen).
251
+
252
+ ## License
253
+
254
+ MIT — see [LICENSE](https://github.com/VARITHSA/autohetero/blob/main/LICENSE).
@@ -0,0 +1,229 @@
1
+ # AutoHetero
2
+
3
+ ![Python](https://img.shields.io/badge/python-3.11%2B-blue) ![PyTorch](https://img.shields.io/badge/pytorch-2.x-orange) ![License](https://img.shields.io/badge/license-MIT-green)
4
+
5
+ **AutoHetero runs each PyTorch call on the CPU, the GPU, or both — whichever is fastest.**
6
+
7
+ A GPU isn't always the faster choice. For small inputs, moving data to the GPU costs more than the work itself, and a GPU that's busy with another job can end up slower than the CPU. I built AutoHetero to make that decision automatically: it benchmarks your machine once, predicts the fastest device for every call, and shifts work to the CPU when the GPU falls behind.
8
+
9
+ ## Features
10
+
11
+ - **One line to enable.** No configuration, no `.to("cuda")`.
12
+ - **Tensors or NumPy.** Results come back in the same type and on the same device you passed in.
13
+ - **Hybrid mode.** Large batches can be split across the CPU and GPU at the same time.
14
+ - **Adapts while running.** If the GPU slows down mid-call, the rest of the work is rebalanced.
15
+ - **Safe fallback.** GPU errors (like running out of memory) rerun the call on the CPU instead of crashing.
16
+ - **Transparent.** A short log line for every decision, and `autohetero.report()` shows what ran where.
17
+
18
+ ## Requirements
19
+
20
+ - Python 3.11+ and PyTorch 2.x
21
+ - An NVIDIA GPU with a CUDA build of PyTorch. Without one, AutoHetero still works and runs everything on the CPU.
22
+
23
+ ## Installation
24
+
25
+ **To use it in your own project**, install it from PyPI into that project's environment:
26
+
27
+ ```bash
28
+ pip install autohetero
29
+ ```
30
+
31
+ **To run the demos, tests and benchmarks**, clone the repository:
32
+
33
+ ```bash
34
+ git clone https://github.com/VARITHSA/autohetero.git
35
+ cd autohetero
36
+ pip install -e . # add ".[dev]" for tests, ".[demo]" for the demo
37
+ ```
38
+
39
+ Check that PyTorch can see your GPU (it should print `True`):
40
+
41
+ ```bash
42
+ python -c "import torch; print(torch.cuda.is_available())"
43
+ ```
44
+
45
+ If it prints `False`, install the CUDA build of PyTorch for your driver from [pytorch.org](https://pytorch.org/get-started/locally/).
46
+
47
+ ## Try it
48
+
49
+ From the cloned repository:
50
+
51
+ 1. **With and without, side by side.** This runs the same image pipeline as plain PyTorch on the CPU, by hand on the GPU, and with AutoHetero, checks that all three give the same answer, and prints their times:
52
+
53
+ ```bash
54
+ python demo/compare.py
55
+ ```
56
+
57
+ 2. **The demo app.** Install the demo extra, then start the app; it opens in your browser:
58
+
59
+ ```bash
60
+ pip install -e ".[demo]"
61
+ ```
62
+
63
+ ```bash
64
+ streamlit run demo/app.py
65
+ ```
66
+
67
+ Pick a batch size and resolution and click **Run**. Turn on **GPU stress** to watch AutoHetero move work to the CPU. The **playground** page in the sidebar runs any built-in op at any size.
68
+
69
+ 3. **The measured results.** Open `demo/showcase.ipynb` in Jupyter (`pip install jupyter` first). It reads the results from my RTX 3050 runs, so it works on a machine without a GPU.
70
+
71
+ ## Using it in your code
72
+
73
+ 1. Import AutoHetero and call `autohetero.enable()` once, at the start of your program.
74
+ 2. Use the built-in ops (`autohetero.ops.*`), or put `@autohetero.auto` on your own functions.
75
+ 3. Keep your data on the CPU, as usual. Don't call `.to("cuda")`; AutoHetero moves the data and brings the result back.
76
+ 4. Call `autohetero.report()` at the end to see where each call ran.
77
+
78
+ **Built-in ops** — one line:
79
+
80
+ ```python
81
+ import torch
82
+ import autohetero
83
+
84
+ autohetero.enable() # the one line: built-in ops now run where they're fastest
85
+
86
+ images = torch.rand(16, 3, 720, 1280) # on the CPU, as usual
87
+ edges = autohetero.ops.sobel(autohetero.ops.blur(images)) # each op is dispatched; the result comes back on the CPU
88
+ ```
89
+
90
+ **Your own functions** — one decorator:
91
+
92
+ ```python
93
+ import numpy as np
94
+ import torch
95
+ import autohetero
96
+
97
+ @autohetero.auto(splittable=True)
98
+ def normalize(x):
99
+ # x arrives as a torch tensor on whichever device AutoHetero chose
100
+ return (x - x.mean(dim=1, keepdim=True)) / x.std(dim=1, keepdim=True)
101
+
102
+ out = normalize(np.random.rand(10_000, 512).astype(np.float32)) # numpy in -> numpy out
103
+ ```
104
+
105
+ Models work too. Pass them in as arguments:
106
+
107
+ ```python
108
+ import torchvision
109
+
110
+ model = torchvision.models.resnet18(weights=None).eval()
111
+
112
+ @autohetero.auto(splittable=True)
113
+ def classify(images, model):
114
+ with torch.no_grad():
115
+ return model(images).argmax(1)
116
+
117
+ batch = torch.rand(64, 3, 224, 224)
118
+ labels = classify(batch, model)
119
+ ```
120
+
121
+ **Manual override**, when you know better:
122
+
123
+ ```python
124
+ with autohetero.force("cpu"): # or "gpu", or "hybrid"
125
+ labels = classify(batch, model)
126
+ ```
127
+
128
+ **See what happened:**
129
+
130
+ ```python
131
+ autohetero.report()
132
+ ```
133
+
134
+ ```
135
+ function calls modes time saved vs GPU (est.) fallbacks switches
136
+ -------- ----- --------------- -------- ------------------- --------- --------
137
+ blur 3 GPU 3 91.2 ms 12.0 ms 0 0
138
+ classify 2 HYBRID 1, GPU 1 612.0 ms 48.0 ms 0 1
139
+ ```
140
+
141
+ The first call on a new machine runs a one-time calibration (about 30 seconds).
142
+
143
+ ## How it works
144
+
145
+ 1. **Calibrate.** On first use, AutoHetero times its built-in ops on the CPU and GPU and caches the results in `~/.cache/autohetero/`.
146
+ 2. **Predict.** A small learned model (random forests) estimates how long each call will take on each device. Your own functions are predicted from their own past runs; the first call measures both devices.
147
+ 3. **Run.** Long calls run in chunks. If a chunk takes more than 1.5× longer than expected, the rest of the call is split between the CPU and GPU by their measured speeds.
148
+ 4. **Learn.** Every call is logged with its predicted and actual time, so predictions improve over time. Call `autohetero.retrain()` to update the model.
149
+
150
+ The full design is in [DESIGN.md](https://github.com/VARITHSA/autohetero/blob/main/DESIGN.md).
151
+
152
+ ## API
153
+
154
+ | Function | What it does |
155
+ |----------|--------------|
156
+ | `autohetero.enable()` | Turns on dispatch for the built-in ops and calibrates the machine (once). |
157
+ | `@autohetero.auto(splittable=False, batch_dim=0)` | Runs every call of a function on the fastest option. Set `splittable=True` only if each output row depends only on the matching input row; that allows chunking and Hybrid mode. |
158
+ | `autohetero.force(mode)` | Context manager: run on `"cpu"`, `"gpu"` or `"hybrid"`. Applies to the current thread only. |
159
+ | `autohetero.report()` | Prints (and returns) what ran where, total time, and the estimated time saved. |
160
+ | `autohetero.retrain()` | Updates the prediction model from the calls recorded so far. |
161
+
162
+ ### Tips for `@auto` functions
163
+
164
+ - Use torch operations — inputs arrive as tensors, even if you passed NumPy arrays.
165
+ - Don't modify inputs in place (`x += 1`).
166
+ - Pass models as arguments, not as globals.
167
+ - If the GPU fails, the call reruns on the CPU, so avoid side effects you can't repeat.
168
+
169
+ ## Built-in ops
170
+
171
+ | Area | Ops | Can be split across devices |
172
+ |------|-----|-----------------------------|
173
+ | Images | `blur`, `resize`, `sobel` | yes |
174
+ | Models | `resnet18`, `mobilenetv2` (random weights, for benchmarking) | yes |
175
+ | Data | `filter`, `sort`, `groupby` | `filter` only |
176
+ | Science | `matmul`, `fft` | yes |
177
+
178
+ ## Configuration
179
+
180
+ There's nothing to configure. Two options if you need them:
181
+
182
+ - `AUTOHETERO_QUIET=1` turns off the log lines.
183
+ - Delete `~/.cache/autohetero/` to recalibrate. (It also recalibrates on its own when the GPU, driver or PyTorch version changes.)
184
+
185
+ ## Tests
186
+
187
+ ```bash
188
+ pip install -e ".[dev]"
189
+ pytest # runs without a GPU
190
+ pytest -m gpu # needs an NVIDIA GPU
191
+ ```
192
+
193
+ ## Benchmarks
194
+
195
+ The evaluation scripts reproduce the results for the project's three research questions. Run them on a machine with an NVIDIA GPU:
196
+
197
+ ```bash
198
+ python bench/collect.py # benchmark dataset
199
+ python bench/experiments.py all # idle / GPU-stress / CPU-stress experiments
200
+ python eval/overhead.py # dispatch overhead
201
+ python eval/crossover.py # then the figures and tables, written to eval/out/
202
+ python eval/rq1.py
203
+ python eval/rq2.py
204
+ python eval/hybrid_gain.py
205
+ python eval/rq3.py
206
+ ```
207
+
208
+ [REQUIREMENTS.md](https://github.com/VARITHSA/autohetero/blob/main/REQUIREMENTS.md) lists every requirement and its current status.
209
+
210
+ ## Project structure
211
+
212
+ ```
213
+ autohetero/ the library (dispatch, prediction, execution, built-in ops)
214
+ bench/ benchmark collection, experiments, load generators
215
+ eval/ scripts that produce the figures and tables
216
+ demo/ Streamlit demo
217
+ tests/ test suite
218
+ ```
219
+
220
+ ## Limitations
221
+
222
+ - Built for one machine with one NVIDIA GPU, for inference and data processing (not training).
223
+ - Hybrid mode only applies to splittable calls with at least 2 items.
224
+ - Very short calls aren't chunked, so they can't be rebalanced mid-call.
225
+ - Each call adds about 10 µs of overhead (a few ms the first time a new input size is seen).
226
+
227
+ ## License
228
+
229
+ MIT — see [LICENSE](https://github.com/VARITHSA/autohetero/blob/main/LICENSE).
@@ -0,0 +1,15 @@
1
+ """AutoHetero: per-call CPU / GPU / Hybrid dispatch for PyTorch workloads.
2
+
3
+ import autohetero
4
+ autohetero.enable() # Level 1: also dispatch the built-in autohetero.ops
5
+ @autohetero.auto # Level 2: one function
6
+ with autohetero.force("cpu"): # Level 3: manual override
7
+ autohetero.report() # what ran where, time taken, estimated time saved
8
+ autohetero.retrain() # learn from this machine's measured calls
9
+ """
10
+ from . import ops
11
+ from .dispatch import auto, enable, force
12
+ from .predictor import retrain
13
+ from .report import report
14
+
15
+ __all__ = ["auto", "enable", "force", "ops", "report", "retrain"]