[FEAT] Deprecate Numba - #1099
Merged
Merged
Conversation
Merging this PR will improve performance by ×4.6
Performance Changes
Comparing |
Olivier Sprangers (elephaint)
marked this pull request as ready for review
February 18, 2026 20:19
Saul (nasaul)
self-requested a review
February 20, 2026 16:35
Saul (nasaul)
requested changes
Feb 20, 2026
Contributor
There was a problem hiding this comment.
Overall this is an excellent PR which get's an increase speed, great work!
However before merging there are things that need to be addressed:
- Remove
numba_cache.ipynbfrom the repo and from the documentation. - Remove numba references from
README.mdnbs/docs/experiments/AmazonStatsForecast.ipynbnbs/docs/experiments/AutoArima_vs_Prophet.ipynbnbs/docs/getting-started/*nbs/docs/tutorials/MultipleSeasonalities.ipynb
- Decide what to do with the
experimetns/numba_removalfolder, my suggestion would be to remove it, but we could also add a proper experiment folder. - Decide what to do with the experiments that cite numba.
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
Saul (nasaul)
previously approved these changes
Feb 23, 2026
Saul (nasaul)
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Should we re run some of the experiments with this new improvement?
Contributor
Author
Which experiments? |
Olivier Sprangers (elephaint)
force-pushed
the
feat/deprecate_numba
branch
from
February 24, 2026 12:18
efa7b91 to
68314af
Compare
Saul (nasaul)
approved these changes
Feb 24, 2026
3 tasks
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR removes
numbaas a runtime dependency by migrating all@njit-decorated hot loops to C++ via pybind11 and Eigen. The affected modules are CES, GARCH, MFLES, SES (intermittent demand helpers), and TBATS. Each module gets its own.cppfile undersrc/, compiled into the existingstatsforecast._libextension. A Nelder-Mead correctness fix and several robustness improvements are included.Performance
The C++ implementations replace numba JIT compilation, eliminating:
numba(22.8 MB) andllvmlite(161.0 MB), saving ~184 MB of install size_lib.so(577 KB → 816 KB)Benchmark Results
See
experiments/numba_removal/benchmark.pyfor detailed comparisons.All benchmarks run on series of length 500 (seed=42). Output equivalence: 88/88 PASS across all functions and series lengths.
Hot-path speedups (n=500, numba JIT-warmed):
garch_sigma2garch_loglikget_basiscescalccalcFaster(TBATS)makeFMatrix(TBATS)siegel_mediansses_sseses_forecastexpand_demand/intervalsSES and expand functions show parity — the operations are too lightweight for C++ call overhead to pay off at n=500. GARCH and MFLES
get_basisshow the largest gains (15-20x).Full-pipeline speedups (optimizer + fitted values):
Scaling with series length (speedup at various n):
garch_sigma2garch_loglikcescalccalcFasterget_basissiegel_mediansses_sseGARCH speedup increases with series length (up to 20x at n=10K) due to reduced Python↔numba dispatch overhead amortized over more iterations.
get_basisshows the inverse: the numba JIT overhead dominates at small n (50x at n=50), while the algorithmic work converges at larger n. All scaling benchmarks pass equivalence checks (56/56).Breaking Changes
numbaremoved from production dependencies. All@njit-decorated functions inces.py,garch.py,mfles.py,models.py,tbats.py, andutils.pyhave been replaced with C++ (pybind11 + Eigen) implementations. Users whoimport numbatransitively through statsforecast will need to add it to their own dependencies.Removed public symbols from
statsforecast.utils:CACHE,NOGIL,restrict_to_bounds— these were numba infrastructure. Any downstream code importing them will break.Environment variables no longer recognized:
NIXTLA_NUMBA_RELEASE_GIL— previously controlled@njit(nogil=...). GIL release is now handled at the pybind11 binding level.NIXTLA_NUMBA_CACHE— previously controlled@njit(cache=...). No longer applicable; C++ is compiled at install time.Behavioral Changes
GARCH optimizer lower bounds changed from
0to1e-8. Ingarch.py, the SLSQP bounds were tightened from(0, None)to(1e-8, None). This prevents degenerate models where coefficients are exactly zero, but may produce slightly different fitted parameters for series where coefficients previously converged near zero.CES optimization now uses float64 initial parameters. In
ces.py,x0changed fromnp.float32tonp.float64. The Nelder-Mead optimizer now operates in double precision throughout, which may produce slightly different optimal parameters (generally more accurate).Nelder-Mead shrink step corrected. In
nelder_mead.h, the shrink step previously always skipped row 0 (for j in range(1, ...)), which was only correct when the best point happened to be at index 0. The fix skips the actualbest_idx. This is a correctness improvement that may change optimization results for any model using Nelder-Mead (CES, ETS, Theta).Numerical Precision Notes
CES results have small float32 rounding differences. The C++ compilation may reorder or fuse float32 operations differently from numba's LLVM backend (e.g. FMA instructions), producing diffs at the last bit of float32 precision. Measured on AirPassengers with fixed parameters:
The forecast diffs are amplified by the float64→float32 round-trip in the
cesforecastPython wrapper. All tests pass atdecimal=2or better.Test Coverage Gaps
The following C++ modules lack dedicated unit tests and are only exercised indirectly through integration tests:
src/garch.cpp— tested viatest_garch.py(11 tests, model-level)src/mfles.cpp— tested viatest_mfles.py(2 tests, model-level)src/ses.cpp— tested viatest_models.py(167 tests, model-level)src/tbats.cpp— tested viatest_tbats.py(1 test, model-level)The
experiments/numba_removal/benchmark.pycontains correctness checks comparing old numba vs new C++ output, but these don't run in CI.