efficient-polling-lr-scheduler 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.
Potentially problematic release.
This version of efficient-polling-lr-scheduler might be problematic. Click here for more details.
- efficient_polling_lr_scheduler-0.1.0/.gitignore +23 -0
- efficient_polling_lr_scheduler-0.1.0/CHANGELOG.md +50 -0
- efficient_polling_lr_scheduler-0.1.0/LICENSE +21 -0
- efficient_polling_lr_scheduler-0.1.0/PKG-INFO +315 -0
- efficient_polling_lr_scheduler-0.1.0/README.md +281 -0
- efficient_polling_lr_scheduler-0.1.0/examples/cifar10.py +253 -0
- efficient_polling_lr_scheduler-0.1.0/pyproject.toml +87 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/__init__.py +59 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/_snapshot.py +93 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/closures.py +78 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/efficient.py +289 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/polling.py +323 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/py.typed +0 -0
- efficient_polling_lr_scheduler-0.1.0/src/efficient_polling_lr_scheduler/training.py +246 -0
- efficient_polling_lr_scheduler-0.1.0/tests/conftest.py +60 -0
- efficient_polling_lr_scheduler-0.1.0/tests/test_efficient.py +375 -0
- efficient_polling_lr_scheduler-0.1.0/tests/test_polling.py +224 -0
- efficient_polling_lr_scheduler-0.1.0/tests/test_snapshot.py +145 -0
- efficient_polling_lr_scheduler-0.1.0/tests/test_training.py +147 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
base_paper.pdf
|
|
2
|
+
Polling-Optimisation-for-Gradient-Descent/
|
|
3
|
+
models/
|
|
4
|
+
CLAUDE.md
|
|
5
|
+
notes.txt
|
|
6
|
+
.~lock.*#
|
|
7
|
+
|
|
8
|
+
# Python
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
|
|
14
|
+
# Packaging
|
|
15
|
+
dist/
|
|
16
|
+
build/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
|
|
19
|
+
# Tooling caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ipynb_checkpoints/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `efficient-polling-lr-scheduler` package are documented here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
|
+
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-07-30
|
|
8
|
+
|
|
9
|
+
First release: the research code from `notebooks/cifar10.ipynb` extracted into an
|
|
10
|
+
installable, tested library.
|
|
11
|
+
|
|
12
|
+
> **Naming history.** This library was briefly published as `efficient-polling`
|
|
13
|
+
> (also 0.1.0, import `efficient_polling`) before being renamed to
|
|
14
|
+
> `efficient-polling-lr-scheduler` and republished. The old distribution was
|
|
15
|
+
> removed from PyPI; nothing else changed, and the algorithms are identical.
|
|
16
|
+
> Note that the classes are not `torch.optim.lr_scheduler.LRScheduler` subclasses
|
|
17
|
+
> despite the name — they wrap the optimizer and run through `optimizer.step(closure)`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `PollingOptimizer` / `PollingSGD` — the replicated base polling method of Tan
|
|
22
|
+
et al.: every candidate learning rate is applied as a trial step from an
|
|
23
|
+
identical snapshot, and the highest-scoring one (ties favouring the smallest)
|
|
24
|
+
is kept.
|
|
25
|
+
- `EfficientPollingOptimizer` / `EfficientPollingSGD` — the proposed extension:
|
|
26
|
+
the same selection, polled on demand via exponential backoff, with the
|
|
27
|
+
two-tier divergence guard (spike-triggered polls and rollback checkpoints).
|
|
28
|
+
- `StateSnapshot` — exact save/restore of parameters, module buffers and
|
|
29
|
+
optimizer state, so every candidate departs from an identical pre-step
|
|
30
|
+
condition. Gradients are preserved, since all candidates reuse the single
|
|
31
|
+
gradient computed at the polled point.
|
|
32
|
+
- `make_closure`, `accuracy`, `negative_loss` — batch closures and selection
|
|
33
|
+
criteria; polling by loss instead of accuracy is supported.
|
|
34
|
+
- `StepInfo`, `PollResult`, `EpochStats`, `History` — per-step and per-epoch
|
|
35
|
+
telemetry, including poll counts, rollbacks, spikes and the optimizer-step
|
|
36
|
+
count behind the paper's cost model.
|
|
37
|
+
- `train_epoch`, `evaluate`, `fit` — optional training helpers that accept either
|
|
38
|
+
a polling optimizer or a plain `torch.optim.Optimizer`, so the baseline and
|
|
39
|
+
both polling methods run through one loop.
|
|
40
|
+
- `examples/cifar10.py` — reproduces the paper's three runs from the command line.
|
|
41
|
+
|
|
42
|
+
### Notes
|
|
43
|
+
|
|
44
|
+
- Polling wraps any `torch.optim.Optimizer`, so momentum, weight decay and Adam
|
|
45
|
+
all work, although the paper's results use vanilla SGD.
|
|
46
|
+
- Candidate learning rates are absolute and applied to every parameter group,
|
|
47
|
+
which overrides per-group learning rates.
|
|
48
|
+
- `max_poll_interval` counts blind steps *between* polls, so the steady state is
|
|
49
|
+
one poll every `max_poll_interval + 1` batches; `0` polls every batch and
|
|
50
|
+
recovers the base method exactly.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luiz Henrique
|
|
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,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: efficient-polling-lr-scheduler
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Polling-based learning-rate selection for PyTorch: the accuracy of per-batch LR polling at roughly the cost of plain SGD.
|
|
5
|
+
Project-URL: Homepage, https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks
|
|
6
|
+
Project-URL: Repository, https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks
|
|
7
|
+
Project-URL: Issues, https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Luiz Henrique, José Ronaldo
|
|
10
|
+
Maintainer-email: Luiz Henrique <luizlinkezio@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: deep-learning,hyperparameter-optimization,learning-rate,learning-rate-schedule,optimizer,polling,pytorch,sgd
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: torch>=2.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: examples
|
|
31
|
+
Requires-Dist: matplotlib>=3.7; extra == 'examples'
|
|
32
|
+
Requires-Dist: numpy>=1.24; extra == 'examples'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Efficient Polling-Based Learning Rate Optimization for Neural Networks
|
|
36
|
+
|
|
37
|
+
> Get the accuracy of polling-based learning-rate selection at essentially the cost of plain SGD.
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/efficient-polling-lr-scheduler/)
|
|
40
|
+
[](https://pypi.org/project/efficient-polling-lr-scheduler/)
|
|
41
|
+
[](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install efficient-polling-lr-scheduler
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
[🇧🇷 Versão em português](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/README(pt-br).md) · [🎥 Presentation video](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/videos/apresentação.mp4)
|
|
48
|
+
|
|
49
|
+
This repository replicates the **Polling Method** of Tan et al. on CIFAR-10 and introduces **Efficient Polling**, a novel extension that recovers the same learning-rate schedule — and the same accuracy — while polling only **5% of batches**, cutting optimizer steps by 75% and per-epoch wall-clock time by **3.3×**. Both methods ship as a PyTorch package.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## TL;DR
|
|
54
|
+
|
|
55
|
+
The learning rate is the single most influential hyperparameter in gradient-based training. Instead of picking it by hand or by a fixed schedule, **polling** tests several candidate learning rates at every batch and keeps the one that most improves batch accuracy. It works remarkably well, but it triples training time.
|
|
56
|
+
|
|
57
|
+
**Efficient Polling** observes that the polled choice is highly redundant — within each training phase consecutive polls pick the same learning rate — and polls *on demand* instead: an exponential-backoff schedule doubles the gap between polls while the selection is stable, and a two-tier divergence guard protects the unpolled steps.
|
|
58
|
+
|
|
59
|
+
| Method | Best Val | Test Acc | Test Loss | Polled Batches | s/Epoch |
|
|
60
|
+
|---|---|---|---|---|---|
|
|
61
|
+
| Baseline (fixed SGD, `1e-3`) | 57.28% | 56.70% | 1.2155 | — | 2.50 |
|
|
62
|
+
| Polling (base paper) | 84.65% | **83.99%** | **0.6832** | 100% | 9.10 |
|
|
63
|
+
| **Efficient Polling (ours)** | **85.07%** | 83.93% | 0.7319 | **5.05%** | **2.79** |
|
|
64
|
+
|
|
65
|
+
*150 epochs, single seed (42), one fully reproducible run per method, NVIDIA RTX 5070.*
|
|
66
|
+
|
|
67
|
+
Efficient Polling **matches** the base method's accuracy (within 0.1 pp on test) at only **12% over plain SGD** — versus the base method's +264%.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Quickstart
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install efficient-polling-lr-scheduler
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Polling needs to re-evaluate the model to score a candidate step, so instead of the bare `optimizer.step()` you pass a **closure** that returns `(loss, score)` — the same contract as `torch.optim.LBFGS`, plus the score to maximize. `make_closure` builds it for you:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import torch
|
|
81
|
+
from efficient_polling_lr_scheduler import EfficientPollingSGD, make_closure
|
|
82
|
+
|
|
83
|
+
model = MyModel().to(device)
|
|
84
|
+
loss_fn = torch.nn.CrossEntropyLoss()
|
|
85
|
+
|
|
86
|
+
# Candidate LRs default to {1e-5, 1e-4, 1e-3, 1e-2, 1e-1} around lr.
|
|
87
|
+
optimizer = EfficientPollingSGD(model, lr=1e-3)
|
|
88
|
+
|
|
89
|
+
for inputs, targets in train_loader:
|
|
90
|
+
inputs, targets = inputs.to(device), targets.to(device)
|
|
91
|
+
info = optimizer.step(make_closure(model, loss_fn, inputs, targets))
|
|
92
|
+
# info.lr, info.loss, info.polled, info.spike, info.rolled_back, ...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
No learning-rate schedule, no warmup, no tuning: the learning rate is *measured*. Swap `EfficientPollingSGD` for `PollingSGD` to get the base method (polls every batch), or wrap any optimizer you like:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from efficient_polling_lr_scheduler import EfficientPollingOptimizer
|
|
99
|
+
|
|
100
|
+
optimizer = EfficientPollingOptimizer(
|
|
101
|
+
torch.optim.SGD(model.parameters(), lr=1e-3, momentum=0.9),
|
|
102
|
+
candidate_lrs=(1e-5, 1e-4, 1e-3, 1e-2, 1e-1),
|
|
103
|
+
module=model, # so BatchNorm buffers are restored between trials
|
|
104
|
+
max_poll_interval=64, # backoff cap; 0 polls every batch
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The optional training helpers run a full comparison in a few lines, and accept a plain optimizer too — so the baseline goes through the same loop:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from efficient_polling_lr_scheduler import fit
|
|
112
|
+
|
|
113
|
+
history = fit(model, train_loader, val_loader, optimizer, loss_fn, epochs=150)
|
|
114
|
+
print(history.best_val_acc, sum(history.polls), sum(history.optimizer_steps))
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### API
|
|
118
|
+
|
|
119
|
+
| Object | Role |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `EfficientPollingSGD` / `EfficientPollingOptimizer` | proposed method: polls on demand, with the divergence guard |
|
|
122
|
+
| `PollingSGD` / `PollingOptimizer` | base method: polls every batch |
|
|
123
|
+
| `make_closure`, `accuracy`, `negative_loss` | batch closure and selection criteria (accuracy, or loss) |
|
|
124
|
+
| `StepInfo`, `EpochStats`, `History` | telemetry: chosen LR, polls, spikes, rollbacks, optimizer steps |
|
|
125
|
+
| `fit`, `train_epoch`, `evaluate` | optional training loop helpers |
|
|
126
|
+
| `StateSnapshot` | exact save/restore of parameters, buffers and optimizer state |
|
|
127
|
+
|
|
128
|
+
**Notes.** Despite the distribution name, these are **not** `torch.optim.lr_scheduler.LRScheduler` subclasses: they wrap the optimizer and are driven entirely through `optimizer.step(closure)`, so there is no separate `scheduler.step()` to call after it. Candidate learning rates are absolute and applied to every parameter group, overriding per-group learning rates. Pass `module=` (or the model itself as the first argument) whenever the forward pass mutates buffers, so trials cannot leak BatchNorm statistics. The closure must not call `backward()` or `zero_grad()` — the optimizer owns both.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## How it works
|
|
133
|
+
|
|
134
|
+
### Polling (replicated base method)
|
|
135
|
+
|
|
136
|
+
At each batch, after computing the gradient `g` from weights `θ`, every candidate learning rate is applied as a trial step and the winner is kept:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
ĝθₖ = θ − lrₖ · g for each lrₖ ∈ C
|
|
140
|
+
k* = argmax acc(ĝθₖ, batch) (ties favour the smallest lr)
|
|
141
|
+
θ ← ĝθₖ*
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The candidate set is `C = {1e-5, 1e-4, 1e-3, 1e-2, 1e-1}`, spanning five orders of magnitude around the base LR. The trial updates are realized by snapshotting the model + optimizer state once, then reloading it before each candidate step, so every candidate departs from an identical pre-step condition. This costs `N = 5` trial updates **per batch**.
|
|
145
|
+
|
|
146
|
+
### Efficient Polling (proposed extension)
|
|
147
|
+
|
|
148
|
+
The selection mechanism is untouched, but a batch is polled only when needed:
|
|
149
|
+
|
|
150
|
+
1. **Adaptive polling schedule.** Let `K` be the poll interval. After a poll, if the selection is unchanged, `K ← min(2K, K_max)` (geometric backoff, capped at `K_max = 64`); if it changed, `K ← 1` (poll every batch until it stabilizes again). Between polls, a single blind SGD step uses the last selected LR.
|
|
151
|
+
|
|
152
|
+
2. **Two-tier divergence guard.** Blind steps have no per-step validation, so a high-LR step can diverge. The guard reuses quantities already computed:
|
|
153
|
+
- **Tier 2 — spike-triggered polls (prevention):** if the batch loss exceeds `γ · EMA(loss)` (`γ = 3`, `β = 0.9`), poll immediately so the accuracy criterion can reject an explosive step.
|
|
154
|
+
- **Tier 1 — rollback checkpoints (recovery):** each poll snapshot doubles as a known-good checkpoint; if the loss is non-finite or exceeds `2·ln(C) ≈ 4.61`, restore the checkpoint and resume polling.
|
|
155
|
+
|
|
156
|
+
In the official run, the spike tier alone was sufficient — **0 rollbacks** were ever triggered. Its necessity is real, though: an early unguarded run diverged to `NaN` at epoch 33 from a single blind step at `lr = 1e-1` and never recovered.
|
|
157
|
+
|
|
158
|
+
| Symbol | Value | Role |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `C` | `{1e-5, …, 1e-1}` | candidate learning rates |
|
|
161
|
+
| `lr_init` | `1e-3` | LR before the first poll |
|
|
162
|
+
| `K_max` | `64` | max poll interval (backoff cap) |
|
|
163
|
+
| `γ` | `3` | spike threshold (tier 2) |
|
|
164
|
+
| `β` | `0.9` | loss-EMA decay |
|
|
165
|
+
| `ℓ_rb` | `2·ln 10 ≈ 4.61` | rollback threshold (tier 1) |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Results
|
|
170
|
+
|
|
171
|
+
Both polling methods autonomously discover a **two-phase schedule** entirely from batch-level feedback: the highest candidate (`≈ 1e-1`) drives rapid loss reduction for the first ~36 epochs, then the selection collapses to the smallest candidate (`≈ 1e-5`) for fine refinement near convergence. Efficient Polling recovers the same schedule while polling a tiny fraction of batches.
|
|
172
|
+
|
|
173
|
+
| | |
|
|
174
|
+
|---|---|
|
|
175
|
+
|  |  |
|
|
176
|
+
| Training & validation loss over 150 epochs. | Mean selected LR per epoch (symlog). |
|
|
177
|
+
|
|
178
|
+

|
|
179
|
+
|
|
180
|
+
Polls concentrate exactly where the schedule changes: outside the phase transition the count sits at the steady-state floor of `704 / K_max ≈ 11` polls/epoch; it spikes to 233 at epoch 33 — the exact moment the selected LR collapses from `1e-1` to `1e-5` — when disagreeing polls keep resetting the interval to one. This is the mechanism that lets 5% of the polls recover the full schedule.
|
|
181
|
+
|
|
182
|
+
### Cost model
|
|
183
|
+
|
|
184
|
+
With `P = 5,337` polls over `B = 105,600` batches, each poll costing `N + 1 = 6` steps and each unpolled batch costing 1:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
S_eff = P·(N+1) + (B − P) = 5,337·6 + 100,263 = 132,285 optimizer steps
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
versus `528,000` for base Polling — a 75% reduction, exactly reproducing the measured step count.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Presentation
|
|
195
|
+
|
|
196
|
+
🎥 [Watch the presentation video](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/videos/apresentação.mp4) · 📊 [Slides (PDF)](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/docs/apresentacao_polling.pdf) · [Slides (PPTX)](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/docs/apresentacao_polling.pptx)
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Repository structure
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
.
|
|
204
|
+
├── src/efficient_polling_lr_scheduler/ # the installable package
|
|
205
|
+
│ ├── polling.py # base method (Tan et al.)
|
|
206
|
+
│ ├── efficient.py # Efficient Polling (ours)
|
|
207
|
+
│ ├── _snapshot.py # exact state save/restore for trial steps
|
|
208
|
+
│ ├── closures.py # batch closures and selection criteria
|
|
209
|
+
│ └── training.py # optional fit/train_epoch/evaluate helpers
|
|
210
|
+
├── tests/ # pytest suite for the algorithms
|
|
211
|
+
├── examples/
|
|
212
|
+
│ └── cifar10.py # reproduces the paper's three runs from the CLI
|
|
213
|
+
├── notebooks/
|
|
214
|
+
│ └── cifar10.ipynb # original experiments: data, model, all 3 methods, plots
|
|
215
|
+
├── docs/
|
|
216
|
+
│ ├── apresentacao_polling.pdf
|
|
217
|
+
│ └── apresentacao_polling.pptx
|
|
218
|
+
├── videos/
|
|
219
|
+
│ └── apresentação.mp4 # presentation video
|
|
220
|
+
├── images/ # figures used in the paper and this README
|
|
221
|
+
├── models/ # best checkpoints per method (.pt, gitignored)
|
|
222
|
+
├── pyproject.toml
|
|
223
|
+
├── CHANGELOG.md
|
|
224
|
+
├── README.md
|
|
225
|
+
└── README(pt-br).md
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Setup
|
|
229
|
+
|
|
230
|
+
To *use* the methods, all you need is the package (Python 3.10+, PyTorch 2.0+):
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
pip install efficient-polling-lr-scheduler
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
To *reproduce the experiments*, clone the repository and install with the extras. A CUDA-capable GPU is recommended (CPU works but is slow):
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
git clone https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks.git
|
|
240
|
+
cd Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks
|
|
241
|
+
python -m venv venv
|
|
242
|
+
source venv/bin/activate
|
|
243
|
+
pip install -e ".[dev,examples]" jupyter
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Dataset
|
|
247
|
+
|
|
248
|
+
The experiments load the **CIFAR-10 Python** version from a local directory (the pickled `data_batch_*` / `test_batch` files). Download it from the [official site](https://www.cs.toronto.edu/~kriz/cifar.html):
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
curl -O https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
|
|
252
|
+
tar -xzf cifar-10-python.tar.gz
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Running
|
|
256
|
+
|
|
257
|
+
The example script runs all three methods and prints the comparison table:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
python examples/cifar10.py --data-dir /path/to/cifar-10-batches-py
|
|
261
|
+
# one method only, shorter run:
|
|
262
|
+
python examples/cifar10.py --data-dir ... --methods efficient --epochs 20
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Run the test suite with `pytest`.
|
|
266
|
+
|
|
267
|
+
Alternatively, open the original notebook and run the cells top to bottom, pointing `DATA_DIR` (in the **Constants** cell) at the extracted `cifar-10-batches-py` directory:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
jupyter notebook notebooks/cifar10.ipynb
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The notebook is organized as: Imports → Constants → Configs (seed `42`, device) → Data (dataset, normalization stats, 90/10 train/val split) → Model (`SimpleCIFAR10CNN`, ~0.56M params) → Train (Baseline, Polling, Efficient Polling) → Animations & plots → Test. Best checkpoints are written to `models/`.
|
|
274
|
+
|
|
275
|
+
> **Reproducibility.** A single seed (42) fixes weight init, data shuffling, and the train/val split, so the three methods differ only in their learning-rate logic. All numbers above come from one run per method.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Experimental setup
|
|
280
|
+
|
|
281
|
+
- **Dataset:** CIFAR-10 — 45,000 train / 5,000 val / 10,000 test, normalized per channel with training statistics.
|
|
282
|
+
- **Model:** `SimpleCIFAR10CNN`, a 5-layer CNN (64→64→128→128→256 conv channels, `3×3` kernels, ReLU, MaxPool, AdaptiveAvgPool, Linear head), **557,898 parameters**, no batch norm or dropout so the optimizer is the only source of adaptation.
|
|
283
|
+
- **Optimizer:** vanilla SGD (no momentum, no weight decay), batch size 64, base LR `1e-3`, 150 epochs (704 batches/epoch, 105,600 total).
|
|
284
|
+
- **Hardware:** single NVIDIA GeForce RTX 5070 (12 GB).
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Citation
|
|
289
|
+
|
|
290
|
+
If you use this work, please cite the paper:
|
|
291
|
+
|
|
292
|
+
```bibtex
|
|
293
|
+
@misc{henrique_efficient_polling_lr_scheduler,
|
|
294
|
+
title = {Efficient Polling-Based Learning Rate Optimization for Neural Networks},
|
|
295
|
+
author = {Henrique, Luiz and Ronaldo, Jos{\'e}},
|
|
296
|
+
year = {2026},
|
|
297
|
+
note = {Universidade Federal de Pernambuco},
|
|
298
|
+
url = {https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The base Polling method is from Tan et al. (see `docs/base_paper.pdf`).
|
|
303
|
+
|
|
304
|
+
To cite the software specifically, add `note = {Python package \texttt{efficient-polling-lr-scheduler}}` or reference [the PyPI project](https://pypi.org/project/efficient-polling-lr-scheduler/).
|
|
305
|
+
|
|
306
|
+
## 🧑💻 Authors
|
|
307
|
+
|
|
308
|
+
| [<img src="https://github.com/luiz-linkezio.png" width=115><br><sub>Luiz Henrique</sub><br>](https://github.com/luiz-linkezio) <sub>Developer</sub><br> <sub>[LinkedIn](https://www.linkedin.com/in/lhbas/)</sub><br> <sub>Portfolio</sub> | [<img src="https://github.com/dev-joseronaldo.png" width=115><br><sub>José Ronaldo</sub><br>](https://github.com/Dev-JoseRonaldo) <sub>Developer</sub><br> <sub>[LinkedIn](https://www.linkedin.com/in/devjoseronaldo/)</sub><br> <sub>[Portfolio](https://joseronaldo.netlify.app/)</sub> |
|
|
309
|
+
| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
310
|
+
|
|
311
|
+
Universidade Federal de Pernambuco, Recife, Brazil.
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT — see the [LICENSE](https://github.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/blob/main/LICENSE) file in this repository.
|