Skip to content

feat: pair and similarity head with 0 layers have no layers - #383

Merged
stephantul merged 2 commits into
mainfrom
pair-head-without-layers
Sep 28, 2026
Merged

stephantul merged 2 commits into
mainfrom
pair-head-without-layers

Conversation

@stephantul

Copy link
Copy Markdown
Contributor

This PR adds an option to make models whose dimensionality matches their output targets have no head at all. This improves training, since we remove the linear layer after training anyway.

Here's the conditions:
for similarity, regression, and pairwise trainers, if you pass n_layers==0 AND the target and embedding dim are equal, we use no layer at all.

A pair similarity model with n_layers=0 whose output dimension equals the
embedding dimension now has an empty head, so the embeddings are trained
and used as is, and to_static_model gives the same embeddings as the
trained model. Classifiers and regressors always keep their linear layer.

MLPHead and the ONNX pipeline wrapper now pass the input through unchanged
when the head has no layers, instead of failing to unpack an empty list.
@stephantul
stephantul requested a review from Pringled September 27, 2026 18:05
@codecov

codecov Bot commented Sep 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
model2vec/inference/mlp.py 100.00% <100.00%> (ø)
model2vec/onnx.py 99.31% <100.00%> (+<0.01%) ⬆️
model2vec/train/base.py 99.55% <100.00%> (+<0.01%) ⬆️
model2vec/train/classifier.py 98.42% <100.00%> (+0.09%) ⬆️
model2vec/train/pairs.py 100.00% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Allows pair and similarity models to skip the head layer when dimensions match.

The PR should not merge until headless training handles the configuration where both embeddings and token weights are frozen.

Reviews (1) · Last reviewed commit: "make similarity not have a head if n_lay..."

Comment thread model2vec/train/base.py
Comment on lines +116 to +117
if self.n_layers == 0 and self.embed_dim == self.out_dim:
return nn.Sequential()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Headless training loses gradient path When n_layers=0, the dimensions match, and both freeze=True and freeze_weights=True, this empty head leaves nothing trainable. The training loop still calls loss.backward(), but the loss has no gradient path, so fitting fails. Previously, the linear head allowed this head-only training configuration to work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm user error? They would need to set all of these options explicitly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s fair for the new headless configuration: explicitly setting both freeze=True and freeze_weights=True means the caller has asked for every parameter to be frozen, so there is no meaningful optimization to perform. I’d still avoid letting this fail later at loss.backward() with an opaque “does not require grad” error, because this combination worked before when the linear head remained trainable. A small validation in the training path (or at initialization) that raises a clear error when the model has no trainable parameters would make the behavior intentional and actionable; otherwise this is reasonable to treat as a caller error rather than a problem with the empty head.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@stephantul
stephantul merged commit 59b5642 into main Sep 28, 2026
12 checks passed
@stephantul
stephantul deleted the pair-head-without-layers branch September 28, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants