Skip to content

Conversation

@CISC
Copy link
Collaborator

@CISC CISC commented Nov 1, 2025

Required for proper handling of Qwen3-VL DeepStack embeds.

May change more than currently necessary for future use, f.ex. in llama-context (or maybe even not enough), please review carefully!

Fixes #16908

@65a
Copy link
Contributor

65a commented Nov 1, 2025

The hidden state size (e.g. for embeddings, control vectors) for Qwen3VL under Transformers is 5120, not 20480. It may be relevant here? I don't fully get what is supposed to happen with DeepStack embeds, but they aren't used during inference for normal embeddings, I think?

Tested this. It works correctly with a 1d cvector of the size 5120, and for basic MTMD use cases. Thanks!

@ngxson

This comment was marked as outdated.

@ngxson
Copy link
Collaborator

ngxson commented Nov 2, 2025

Hmm, please ignore what I said earlier.

Indeed, I think there is currently a misunderstanding here. The n_embd_full refer to the length of the input embedding, not the output. For example, I can have an input of n_embd_full = n_embd*4, but the model will always return n_embd as output. Therefore, this naming can be quite confusing.

I would suggest calling it n_embd_inp instead. Just need to pay attention to use n_embd when dealing with batch output.

@CISC CISC changed the title hparams : add n_embd_full to support extended embed hparams : add n_embd_inp() to support extended embed Nov 3, 2025
@CISC CISC requested review from ggerganov and ngxson November 3, 2025 21:16
Comment on lines +6671 to +6673
const int n_embd_inp = hparams.n_embd_inp();
ggml_tensor * cur = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n_embd_inp);
ggml_tensor * layer_dir = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n_embd_inp);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not 100% sure if n_embd_inp is correct here.

As far as I can understand, the cur is the output of the current layer. That means it should use the internal embedding length n_embd. CC @65a in case you know this part.

Copy link
Contributor

@65a 65a Nov 4, 2025

Choose a reason for hiding this comment

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

So I just know what I learned from trying to make cvectors for Qwen3VL, so with that in mind:

  1. The Transformers hiddenstate (and output embedding, being last_hidden_state) size of that model is 5120 (n_embd) and not 20480 (n_embd_inp). But I didn't use multimodal, and not sure if it changes.
  2. I think the deepstack layers are only used for multimodal

This at least is called from llama-adapter.cpp for cvectors, but the check in cvector is hardcoded against n_embd, so it will still pass regardless (was wondering why my cvector worked with this code change). I assume since the cvector is for the language model, it doesn't matter if the other ones are empty so much so long as they are zeroed.

It seems like the answer might be use n_embd here unless there is somewhere multimodal where this is used, or multimodal cvectors are a thing, or this is called from other contexts that need the "rest" of it?

}

return embd + j*model.hparams.n_embd;
return embd + j*model.hparams.n_embd_inp();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Technically this should be n_embd_out (aka currently n_embd), right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could be, I wasn't entirely sure.

const int n_embd = hparams.n_embd;
ggml_tensor * b = ggml_new_tensor_4d(ctx, GGML_TYPE_F32, n_embd, w->ne[1], 1, 1);
const int n_embd_inp = hparams.n_embd_inp();
ggml_tensor * b = ggml_new_tensor_4d(ctx, GGML_TYPE_F32, n_embd_inp, w->ne[1], 1, 1);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm unsure if this is correct as well...

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think either n_embd_inp or n_embd should not be very important. at least for now, models that use this ops will have n_embd_inp == n_embd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eval bug: Control vectors for Qwen3VL fail due to n_embd size

5 participants