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.

@@ -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
+ [![PyPI](https://img.shields.io/pypi/v/efficient-polling-lr-scheduler.svg)](https://pypi.org/project/efficient-polling-lr-scheduler/)
40
+ [![Python](https://img.shields.io/pypi/pyversions/efficient-polling-lr-scheduler.svg)](https://pypi.org/project/efficient-polling-lr-scheduler/)
41
+ [![License](https://img.shields.io/pypi/l/efficient-polling-lr-scheduler.svg)](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
+ | ![Loss curves](https://raw.githubusercontent.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/main/images/training_comparison_losses.png) | ![Learning-rate trajectories](https://raw.githubusercontent.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/main/images/training_comparison_LRs.png) |
176
+ | Training & validation loss over 150 epochs. | Mean selected LR per epoch (symlog). |
177
+
178
+ ![Polls per epoch](https://raw.githubusercontent.com/luiz-linkezio/Efficient-Polling-Based-Learning-Rate-Optimization-for-Neural-Networks/main/images/polls_per_epoch.png)
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.