-
Notifications
You must be signed in to change notification settings - Fork 2.4k
[Model] Support Qwen3ForSequenceClassification for Qwen3-Embed Model #7957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @nysa-liu, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly expands the model capabilities by integrating the Qwen3-embed series for sequence classification. It provides a dedicated implementation for this new model type and ensures it's properly documented, allowing users to leverage Qwen3 for embedding-based classification tasks.
Highlights
- New Model Support: I've identified that this pull request introduces support for the newly released Qwen3-embed series models, specifically enabling their use for sequence classification tasks.
- Dedicated Classification Class: A new Python file,
qwen3_classification.py
, has been added to defineQwen3ForSequenceClassification
. This class is built upon the existing Qwen3 script andQwen2ForSequenceClassification
patterns, handling the model's forward pass, scoring, and pooling for embedding output. - Documentation Update: The
docs/supported_models/embedding_models.md
file has been updated to include Qwen3-embed in the list of officially supported embedding models, providing an example HuggingFace identifier and a brief description. - Specialized Weight Loading: The
Qwen3ForSequenceClassification
includes a customload_weights
method that specifically filters outlm_head
weights, which is crucial for models primarily used for embedding rather than causal language modeling.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
The PR adds support for Qwen3-embed models by implementing Qwen3ForSequenceClassification
. The review identifies a critical bug in weight loading for the new model class and suggests a fix. It also points out a documentation ambiguity.
def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]): | ||
# Filter out lm_head weights of Qwen3ForCausalLM | ||
filtered_weights = [ | ||
(name, w) for name, w in weights if not name.startswith("lm_head") | ||
] | ||
return Qwen3ForCausalLM.load_weights(self, filtered_weights) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of load_weights
reuses Qwen3ForCausalLM.load_weights
. However, the weight loading logic in Qwen3ForCausalLM
has a special case for "Embedding" models that prefixes all weights with model.
. This is incorrect for the score
layer in Qwen3ForSequenceClassification
, which is a top-level attribute, not part of the model
submodule. As a result, the weights for the classification head will fail to load, leading to a model that produces incorrect outputs.
To fix this, implement a custom load_weights
implementation that correctly handles the weight paths for the score
layer.
def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]):
# HACK: Temporarily modify config to avoid incorrect prefixing in Qwen3ForCausalLM.load_weights
# for the 'score' layer, which is not under the 'model' submodule.
original_name_or_path = self.config.name_or_path
try:
self.config.name_or_path = "" # Disable the "Embedding" check in the reused loader
prefixed_weights = []
for name, w in weights:
if name.startswith("lm_head"):
continue
if not name.startswith("score."):
prefixed_weights.append((f"model.{name}", w))
else:
prefixed_weights.append((name, w))
return Qwen3ForCausalLM.load_weights(self, prefixed_weights)
finally:
# Restore config
self.config.name_or_path = original_name_or_path
| ------------------------------------------ | -------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| **Llama/Mistral based (E5EmbeddingModel)** | `intfloat/e5-mistral-7b-instruct` | N/A | Mistral/Llama-based embedding model fine‑tuned for high‑quality text embeddings (top‑ranked on the MTEB benchmark). | | ||
| **GTE (QwenEmbeddingModel)** | `Alibaba-NLP/gte-Qwen2-7B-instruct` | N/A | Alibaba’s general text embedding model (7B), achieving state‑of‑the‑art multilingual performance in English and Chinese. | | ||
| **Qwen3 (QwenEmbeddingModel)** | `Qwen/Qwen3-Embedding-4B` | N/A | Qwen3-based text embedding model (4B), compatible with QwenEmbeddingModel interface; designed for accurate and efficient semantic representation. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The model class in parenthesis (QwenEmbeddingModel)
and the description "compatible with QwenEmbeddingModel interface" may be misleading for the new Qwen3
model. The actual class implemented is Qwen3ForSequenceClassification
. To improve clarity for users, update the model class and description to accurately reflect the new implementation.
| **Qwen3 (QwenEmbeddingModel)** | `Qwen/Qwen3-Embedding-4B` | N/A | Qwen3-based text embedding model (4B), compatible with QwenEmbeddingModel interface; designed for accurate and efficient semantic representation. | | |
| **Qwen3 (Qwen3ForSequenceClassification)** | `Qwen/Qwen3-Embedding-4B` | N/A | Qwen3-based text embedding model (4B), using `Qwen3ForSequenceClassification`; designed for accurate and efficient semantic representation. | |
config, quant_config=quant_config, prefix=add_prefix("model", prefix) | ||
) | ||
self.score = nn.Linear(config.hidden_size, config.num_labels) | ||
# Use normalize=True for qwen3 embedding based on official implementation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you give a reference here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the reference request on lines 38-44:
Thank you for the feedback. I've added a specific reference to the official Qwen3-Embedding implementation:
# Use normalize=True for qwen3 embedding based on official implementation
# Reference: https://github.com/QwenLM/Qwen3-Embedding/blob/main/examples/qwen3_embedding_transformers.py#L55
# Official code: output = F.normalize(output, p=2, dim=1)
This references the official transformers implementation where they use F.normalize(output, p=2, dim=1)
for L2 normalization, which corresponds to our normalize=True
setting in the pooler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this logic depends on whether we use embedding model
or rerank model
. This logic is right for embedding model
, it looks like in rerank model
it uses softmax in pooler, could we change pooler normalize
or softmax
according to model architectures?
|
||
EntryClass = [ | ||
Qwen3ForSequenceClassification, | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we add ut in test_embedding_models.py
as Qwen2ForSequenceClassification
does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For adding Qwen3ForSequenceClassification to is_generation_model unit tests:
I've made the following changes:
- Added unit tests: Added
("Qwen/Qwen3-Embedding-8B", 1, 1e-5)
to the MODELS list intest/srt/models/test_embedding_models.py
, following the same pattern as Qwen2ForSequenceClassification models.
| **Qwen3 (QwenEmbeddingModel)** | `Qwen/Qwen3-Embedding-4B` | N/A | Qwen3-based text embedding model (4B), compatible with QwenEmbeddingModel interface; designed for accurate and efficient semantic representation. | | ||
| **GME (MultimodalEmbedModel)** | `Alibaba-NLP/gme-Qwen2-VL-2B-Instruct` | `gme-qwen2-vl` | Multimodal embedding model (2B) based on Qwen2‑VL, encoding image + text into a unified vector space for cross‑modal retrieval. | | ||
| **CLIP (CLIPEmbeddingModel)** | `openai/clip-vit-large-patch14-336` | N/A | OpenAI’s CLIP model (ViT‑L/14) for embedding images (and text) into a joint latent space; widely used for image similarity search. | | ||
| **BGE (BgeEmbeddingModel)** | `BAAI/bge-large-en-v1.5` | N/A | Currently only support `attention-backend` `triton` and `torch_native`. BAAI's BGE embedding models optimized for retrieval and reranking tasks. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you provide more details about how to use Qwen3ForSequenceClassification
as vllm-project/vllm#19260 does?
…eClassification - Added an inline reference to the official Qwen3-Embedding implementation using F.normalize() for L2 normalization. - Extended is_generation_model logic to treat Qwen3ForSequenceClassification as a non-generative model. - Added unit test for Qwen3-Reranker-0.6B-seq-cls to test_embedding_models.py to verify classification compatibility. This aligns Qwen3 support with existing Qwen2 sequence classification logic and improves clarity on normalization behavior.
Thanks for the feedback. I've updated the implementation accordingly. Please help take another look 🙏 @yizhang2077 |
Sorry for late reply. Instead of changing other model's descriptions in doc, I think we only need add Qwen3-Embedding part? |
@nysa-liu is it a dense mode ? |
Motivation
Support the newly released Qwen3-embed series models by extending the classification capabilities of Qwen3.
To this end, I implemented
Qwen3ForSequenceClassification
based on the existing Qwen3 script andQwen2ForSequenceClassification
. This enables users to perform sequence classification tasks with Qwen3-embed models.Modifications
qwen3_classification.py
to defineQwen3ForSequenceClassification
.docs/supported_models/embedding_models.md
to include relevant documentation for Qwen3-embed classification support.Checklist