Open-source contributions

Fixes and features for the libraries I build on. Most start from reading their code, not from the issue tracker.

4 pull requests · 3 merged · 3 repositories

MergedNov 2026+19 −0

huggingface/transformers#50156

Apply final logit soft-capping in PaliGemma 2

Since transformers v4.52, PaliGemma 2 had been skipping Gemma 2's final logit soft-capping, so sampling, log-probabilities and the training loss no longer matched the original model. I found it by reading the code; the maintainer, zucchini-nlp, confirmed it against Google's big_vision and merged the fix.

  • Vision-language
  • Bug fix
What changed

PaliGemma 2 pairs a SigLIP vision encoder with Gemma 2. Gemma 2's config sets final_logit_softcapping=30, which passes the logits through tanh(x / 30) * 30 before the softmax. Up to v4.51, PaliGemma wrapped Gemma2ForCausalLM, which applied the cap. A refactor in v4.52 replaced it with the bare text model and a separate lm_head, and the cap was dropped. Greedy decoding does not change because tanh is monotonic, which is why the integration tests never caught it.

On the released paligemma2-3b-mix-224 checkpoint the logits never reach 30, but the cap still matters. The caption's log-probability goes from -5.83 to -7.93, and at T=1 the sampling distribution shifts by 13% (total variation distance). I opened the issue with a CPU reproduction; the maintainer checked big_vision and asked me for the PR.

The fix applies the cap after lm_head, as Gemma 3n does. It reads the cap with getattr, because PaliGemma 1's GemmaConfig has no such field. A new test sets a small cap and checks that no logit goes past it: it fails on main and passes with the fix. The maintainer ran the slow PaliGemma tests and merged it unchanged three days after it was opened.

View pull request
In reviewOct 2026+285 −28

huggingface/optimum-intel#2085

NemotronH support for OpenVINO

OpenVINO export and inference for NVIDIA's hybrid Mamba-2 / attention / MoE architecture (Nemotron-H, Nano v2, Nemotron 3). It reuses the existing Mamba-2 recurrent cell and adds experts without a gate. It also follows NVIDIA's own time-step clamp, which brings 16k-token perplexity from 2.14 down to 1.91.

  • OpenVINO
  • Mamba-2
  • MoE
What changed

NemotronH stacks Mamba-2, attention, MLP and mixture-of-experts layers, and is native in transformers. The export reuses optimum-intel's GraniteMoeHybrid support, so the Mamba-2 layers go through the same recurrent cell (an OpenVINO loop) and the same cache layout. What differs: each layer has a single mixer, picked by its block type, and the experts have no gate (up, relu², down). The shared experts patch now handles that case without changing the graph of gated models.

One choice is backed by measurements. transformers clamps the time step dt at time_step_min when it processes the prompt, but not when it decodes token by token. NVIDIA's original code, mamba_ssm and vLLM clamp with config.time_step_limit instead. In Nemotron 3 Nano 4B, 23% of the dt values sit below time_step_min, so the choice shows on long contexts: following NVIDIA, perplexity at 16k tokens is 1.91 instead of 2.14.

Exported to int4, Nano 4B takes 2.4 GB. Its hidden size (3136) is not a multiple of 128, so without --group-size-fallback adjust about half of the weights stay in bf16 and the model takes 5.0 GB.

View pull request
MergedOct 2026+21 −1

huggingface/optimum-intel#2084

Export local checkpoints in offline mode

With local_files_only or HF_HUB_OFFLINE=1, a local PyTorch folder was looked up in the Hub cache instead, so the OpenVINO export was silently skipped. Found by reading the code; fixed with a regression test.

  • OpenVINO
  • Bug fix
What changed

With local_files_only=True, which HF_HUB_OFFLINE=1 also forces, OVBaseModel.from_pretrained assumed the model id was a Hub id and read refs/main from the Hub cache to find the snapshot. For a local folder that file does not exist. The error was swallowed with a misleading warning, the export stayed off, and loading then failed looking for openvino_model.xml.

The fix only resolves the Hub cache when the model id is not a local directory, so loading cached Hub models offline works as before. A new test covers local_files_only and offline mode; both cases fail on main and pass with the fix. There was no issue for it: the bug came from reading the code.

View pull request
MergedOct 2026+5 −5

huggingface/sentence-transformers#4279

Strip left padding from token embeddings

Token embeddings only had trailing padding removed, so left-padding models like Qwen3-Embedding returned padding rows mixed in with real tokens. Each row is now cut from its first to its last real token. Merged within the hour.

  • Embeddings
  • Bug fix
What changed

encode(..., output_value="token_embeddings") cut each row at its last real token, which only handles right padding. The Qwen3-Embedding model cards recommend padding_side="left", and with it the shorter texts in a batch came back with their padding rows still attached. Anything built on the token embeddings, like mean pooling or late chunking, then included padding.

Each row is now sliced from its first to its last attended token, and right-padded outputs are unchanged. The existing test now runs with both padding sides; the left case failed before the fix. The maintainer merged it 54 minutes after it was opened.

View pull request
All my pull requests on GitHub
🤖

Ask me anything

AI trained on my background

Hey 👋 Want the story behind any of these pull requests? Ask away.
Ask me anything