Port Vowpal Wabbit to the python bindings and upgrade to vowpalwabbit 9 - #2373
Open
miguelgfierro wants to merge 49 commits into
Open
Port Vowpal Wabbit to the python bindings and upgrade to vowpalwabbit 9#2373miguelgfierro wants to merge 49 commits into
miguelgfierro wants to merge 49 commits into
Conversation
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
…led in CI Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
miguelgfierro
requested review from
SimonYansenZhao,
anargyri,
loomlike and
wav8k
as code owners
September 4, 2026 17:40
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
miguelgfierro
marked this pull request as draft
September 4, 2026 17:59
…mend_k_items Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
…tems Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
…e at the end Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
…metrics for every model Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
…arning Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
miguelgfierro
marked this pull request as ready for review
September 4, 2026 21:16
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
miguelgfierro
marked this pull request as draft
September 5, 2026 06:10
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
Signed-off-by: miguelgfierro <miguelgfierro@users.noreply.github.com>
miguelgfierro
marked this pull request as ready for review
September 5, 2026 08:08
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.
Description
Moves
vowpalwabbit>=9.9.0,<10from theexperimentalextra to the core dependencies, ports theVWwrapper inrecommenders/models/vowpal_wabbit/vw.pyfrom a subprocess call to the python bindings, and rewrites vowpal_wabbit_deep_dive.ipynb around that class so it reads like the other model notebooks, with tuned parameters for every model.The notebook was broken on pandas 2 (
DataFrame.appendno longer exists) and the pinned VW 8.x has no wheels for Python 3.10 or 3.11. TheVWclass existed to demonstrate usage in the notebooks but the notebook never used it, and it shelled out to avwbinary the pip package does not ship.vowpalwabbit 9.11.2 ships wheels for CPython 3.10 to 3.14 on Linux x86_64 and aarch64, macOS and Windows, declares no runtime dependencies and is BSD-3 licensed, so it does not hold back the Python versions the package can support.
VWclassvowpalwabbit.Workspace, novwexecutable needed. Parameters are the vw command line options as keyword arguments, soVW(q="ui", b=26)isvw -q ui -b 26. The training parameters are arguments offit(df, epochs, learning_rate, l2), and train-only options such asqare not passed to prediction. Predictions are bit-identical to the executable.recommend_k_items(test, top_k, remove_seen)with the same signature as SAR: scores every user in the test set against every item seen during training and keeps the top k.save(path)andload(path): the model is trained into a temporary directory that goes away with the object, so this is what lets a trained model be persisted and served elsewhere. vw keeps the training options in the model file, so a loaded model predicts with its own interactions, rank or oaa settings.n_jobs: prediction splits the rows in chunks scored by a process pool, each process writing and scoring its own chunk with the C++ driver. Results are identical ton_jobs=1. Scoring 21.5M candidate pairs at 1m takes about 3 minutes single process, most of it VW parsing text examples; with 8 processes the whole 1m notebook runs in about 6.5 minutes instead of 20.loss_function="logistic"withoaakeeps the rating labels the multiclass model needs.to_vw_file()builds the input file with vectorized string operations instead of a row loop; byte-identical output, about 17x faster.KeyError: 'index'.Notebook
EPOCHS = 20andN_JOBS = 8are exposed at the top. Each of the six models ismodel = VW(...)with its own options,model.fit(train, epochs=EPOCHS, learning_rate=..., l2=...)with its own learning rate and L2,model.predict(test),model.recommend_k_items(test, top_k=TOP_K, remove_seen=True), followed by the rating metrics (rmse,mae,rsquared,exp_var) and the ranking metrics (map_at_k,ndcg_at_k,precision_at_k,recall_at_k) computed inline; the six results are compared in one table at the end. Theto_vw,run_vw, temp directory, file path, candidate set and separate scoring cells are gone. The markdown explaining-q,-b,--oaa,--rankand--lrqis kept since those are now the constructor arguments.Tuning
The parameters come from a grid search on MovieLens 100k with the notebook's split, about 1,500 fits: epochs {1, 5, 10, 20} x learning rate {0.5 to 0.005} x L2 {0 to 1e-4} for every model, the model options
b,rank,lrqandlrqdropoutcrossed with the same training grid, and an extension down to learning rate 0.001 and up to L2 1e-3 once the optimum reached the grid edge. Models are ordered by NDCG@10. The number of epochs is shared by all models and is the value with the best mean NDCG across them (20). The learning rate, L2 and options are chosen per model as the best NDCG subject to rmse <= 1.10: without that guard the regression models reach a slightly higher NDCG at L2 = 1e-3 by shrinking every prediction to a constant (rmse 2.77), which is not a usable rating model.b=28oaa=5rank=20lrq="ui3",lrqdropout=True"Before" is 5 epochs, learning rate 0.02 and L2 0 for every model.
Tests
tests/unit/recommenders/models/test_vowpal_wabbit.py: the six tests registered inpr_gatekeep their names. New tests train real models:fit/predict,save/loadround trip,recommend_k_itemswithremove_seen, logistic predictions in [0, 1], multiple epochs, andn_jobsproducing the same recommendations as a single process; the multiclass label handling and the training parameters beingfit()arguments are covered without training.test_vw_deep_dive_smoketest_vw_deep_dive_smoketest_vw_deep_dive_functionaltest_vw_deep_dive_functionalThe parameters were tuned on 100k only. On 1m they raise NDCG from 0.183 to 0.198 but cost rating accuracy (rmse 0.998 to 1.148, R2 below zero), so the 1m expectations record that trade-off rather than a 1m optimum.
All the VW tests now run in CI. The
experimentalmarker and the skip markers are gone, and the eleven new unit tests are registered intests/test_groups.yml; the three notebook tests were already listed there. No workflow or Dockerfile changes.Benefit
The VW model and its deep dive work again with
pip install recommenderson Python 3.10 to 3.14, with no extra or manual binary install. The wrapper is a real model class with the repository's standard interface, including top-k recommendations, parallel scoring and a trained model that can be saved and loaded back, and the notebook shows that interface, the metric calls and a tuned configuration for each model rather than file plumbing.Risk
The VW deep dive now runs in the PR gate, which adds about 84 s to
group_cpu_sparkon a 4 core runner, and the 1m functional test adds about 9 min to the nightly. The unit tests are toy sized and add under a second.vowpalwabbitis a compiled dependency whose wheels for new CPython versions have historically arrived late (3.11 to 3.13 only got wheels in 9.11.x, March 2026). Support for Python versions after 3.14 in the core package will depend on upstream publishing wheels for them.Checklist:
stagingbranch AND NOT TOmainBRANCH.