Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/speculative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,7 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
GGML_ASSERT(lattice && "DFlash2 selector produced no lattice");

int32_t predecessor = 0;
for (int32_t i = 1; i < n_block_tokens; ++i) {
for (int32_t i = 1; i < (is_dflash2 ? n_block_tokens : params.n_max + 1); ++i) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh wait, what is this change here? We just merged lilicorr, right?

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.

Not sure why it wasn't caught earlier.

In the LiliCorr PR, LiliCorr calculates the entire candidate lattice even when n_draft < 7. The head's tensors are specifically made to run attention between 56 candidates, so it seemed inadvisable to slice it. In any case, not within in the already-burgeoning scope of this PR.

For that case, doing the loop from 1 to n_block_tokens is wrong; since that will always output 7 draft tokens, even when we have set n_draft to < 7.

That hits this assert later on in llama-context.cpp:2384

GGML_ASSERT(n_outputs_max <= cparams.n_outputs_max);

The change keeps us from passing more than n_max tokens even if the lattice is larger.

const float * row = lattice + (size_t) (beg + i) * n_embd_dec;
const int32_t top_k = is_dflash2 ? selector_top_k : lilicorr_top_k;
const float * scores = row + top_k + (size_t) predecessor * top_k;
Expand Down
1 change: 1 addition & 0 deletions conversion/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@
"MiniCPMV4_6ForConditionalGeneration": "minicpm",
"MiniCPMV4_7ForConditionalGeneration": "minicpm",
"Mistral3ForConditionalGeneration": "llava",
"NemotronH_Omni_Reasoning_V3": "nemotron",
"NemotronH_Nano_VL_V2": "nemotron",
"MuseGlimmerForConditionalGeneration": "muse_glimmer",
"PaddleOCRVisionModel": "ernie",
Expand Down
2 changes: 1 addition & 1 deletion conversion/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@
if weight_map is None or not isinstance(weight_map, dict):
raise ValueError(f"Can't load 'weight_map' from {index_name!r}")
tensor_names_from_index.update(weight_map.keys())
part_dict: dict[str, None] = dict.fromkeys(weight_map.values(), None) # ty: ignore[invalid-assignment]

Check warning on line 257 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:257:91: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
part_names = sorted(part_dict.keys())
else:
weight_map = {}
Expand Down Expand Up @@ -568,7 +568,7 @@
tensors_to_remove.append(base_name + "_zero_point")
else:
raise NotImplementedError(f"Quant format {quant_format!r} for method {quant_method!r} is not yet supported")
elif quant_method == "modelopt":
elif quant_method in ("modelopt", "modelopt_mixed"):
dequant_fp8()
elif quant_method is not None:
raise NotImplementedError(f"Quant method is not yet supported: {quant_method!r}")
Expand Down Expand Up @@ -1757,15 +1757,15 @@

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(self.dir_model)
vocab_size = self.hparams.get("vocab_size", len(tokenizer.vocab)) # ty: ignore[unresolved-attribute]

Check warning on line 1760 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1760:76: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
assert max(tokenizer.vocab.values()) < vocab_size # ty: ignore[unresolved-attribute]

Check warning on line 1761 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1761:60: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment

tokpre = self.get_vocab_base_pre(tokenizer)

reverse_vocab = {id_: encoded_tok for encoded_tok, id_ in tokenizer.vocab.items()} # ty: ignore[unresolved-attribute]

Check warning on line 1765 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1765:93: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
added_vocab = tokenizer.get_added_vocab() # ty: ignore[unresolved-attribute]

Check warning on line 1766 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1766:52: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment

added_tokens_decoder = tokenizer.added_tokens_decoder # ty: ignore[unresolved-attribute]

Check warning on line 1768 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1768:64: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment

for i in range(vocab_size):
if i not in reverse_vocab:
Expand All @@ -1778,7 +1778,7 @@
# To avoid unexpected issues - we make sure to normalize non-normalized tokens
if not added_tokens_decoder[i].normalized:
previous_token = token
token = tokenizer.decode(tokenizer.encode(token, add_special_tokens=False)) # ty: ignore[unresolved-attribute, invalid-assignment]

Check warning on line 1781 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:1781:102: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
if previous_token != token:
logger.info(f"{repr(previous_token)} is encoded and decoded back to {repr(token)} using AutoTokenizer")

Expand Down Expand Up @@ -2166,10 +2166,10 @@
def _set_vocab_hybriddna(self):
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(self.dir_model, trust_remote_code=True)
vocab_size = self.hparams.get("vocab_size", len(tokenizer.vocab)) # ty: ignore[unresolved-attribute]

Check warning on line 2169 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:2169:76: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
assert max(tokenizer.vocab.values()) < vocab_size # ty: ignore[unresolved-attribute]

Check warning on line 2170 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:2170:60: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment

reverse_vocab = {id_: encoded_tok for encoded_tok, id_ in tokenizer.vocab.items()} # ty: ignore[unresolved-attribute]

Check warning on line 2172 in conversion/base.py

View workflow job for this annotation

GitHub Actions / python type-check

ty (unused-ignore-comment)

conversion/base.py:2172:93: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
# k-mers can share text with a base-vocab BPE token (e.g. CCCCCC) and get
# dropped by get_vocab(); a reserved marker suffix (U+E000) keeps each
# k-mer's own id (llama.cpp strips it on detokenization)
Expand Down
144 changes: 132 additions & 12 deletions conversion/nemotron.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Any, Callable, Iterable, TYPE_CHECKING
from typing import Any, Callable, Iterable, Sequence, TYPE_CHECKING

import numpy as np
import torch
Expand Down Expand Up @@ -89,19 +89,22 @@ def set_gguf_parameters(self):
self.gguf_writer.add_lilicorr_vector_eps(float(dflash_config["lilicorr_vector_eps"]))
self.gguf_writer.add_lilicorr_logit_scale(float(dflash_config["lilicorr_logit_scale"]))

def map_tensor_name(self, name: str, try_suffixes: Sequence[str] = (".weight", ".bias")) -> str:
if name.startswith("model.lilicorr.layers."):
parts = name.split(".", 4)
if not parts[4].startswith("attn.in_proj."):
parts[3] = str(self.block_count + int(parts[3]))
name = ".".join(parts)
elif name.startswith("model.lilicorr.feature_norm."):
feature_bid = self.block_count + self.lilicorr_geometry["num_layers"]
name = name.replace("model.lilicorr.feature_norm.", f"model.lilicorr.feature_mlp.{feature_bid}.norm.")
elif name.startswith("model.lilicorr.feature_mlp."):
feature_bid = self.block_count + self.lilicorr_geometry["num_layers"]
name = name.replace("model.lilicorr.feature_mlp.", f"model.lilicorr.feature_mlp.{feature_bid}.")
return super().map_tensor_name(name, try_suffixes)

def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
if name.startswith("model.lilicorr."):
if name.startswith("model.lilicorr.layers."):
parts = name.split(".", 4)
if not parts[4].startswith("attn.in_proj."):
parts[3] = str(self.block_count + int(parts[3]))
name = ".".join(parts)
elif name.startswith("model.lilicorr.feature_norm."):
feature_bid = self.block_count + self.lilicorr_geometry["num_layers"]
name = name.replace("model.lilicorr.feature_norm.", f"model.lilicorr.feature_mlp.{feature_bid}.norm.")
elif name.startswith("model.lilicorr.feature_mlp."):
feature_bid = self.block_count + self.lilicorr_geometry["num_layers"]
name = name.replace("model.lilicorr.feature_mlp.", f"model.lilicorr.feature_mlp.{feature_bid}.")
yield self.map_tensor_name(name), data_torch
return
yield from super().modify_tensors(data_torch, name, bid)
Expand Down Expand Up @@ -251,6 +254,113 @@ def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iter
yield mapped_name, tensor


@ModelBase.register("NemotronH_Omni_Reasoning_V3")
class NemotronOmniVLModel(NemotronNanoV2VLModel):
_omni_tensor_prefixes = (
"vision_model.embeddings.",
"vision_model.encoder.layer.",
"vision_projector.mlp1.",
)

def get_vision_config(self) -> dict[str, Any] | None:
vision_config = dict(self.global_config["vision_config"])
vision_config["intermediate_size"] = int(vision_config["hidden_size"] * vision_config["mlp_ratio"])
vision_config["image_size"] = 512 # warmup only; the full position table is resized at runtime
return vision_config

def set_gguf_parameters(self):
preprocessor_config = self.preprocessor_config

preprocessor_config["image_mean"] = preprocessor_config["norm_mean"]
preprocessor_config["image_std"] = preprocessor_config["norm_std"]

MmprojModel.set_gguf_parameters(self)
self.gguf_writer.add_clip_projector_type(gguf.VisionProjectorType.NEMOTRON_OMNI)
self.gguf_writer.add_vision_attention_layernorm_eps(1e-6)
self.gguf_writer.add_vision_use_gelu(True)
downsample_ratio = self.global_config.get("downsample_ratio", 0.5)
self.gguf_writer.add_vision_projector_scale_factor(int(1.0 / downsample_ratio))
patch_area = self.hparams["patch_size"] ** 2
self.gguf_writer.add_vision_min_pixels(preprocessor_config["min_num_patches"] * patch_area)
self.gguf_writer.add_vision_max_pixels(preprocessor_config["max_num_patches"] * patch_area)

@classmethod
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
name, gen = item

# Transformers can rename RADIO and projector tensors in Omni checkpoints.
# Accept both checkpoint layouts.
if name == "vision_model.summary_idxs":
# This buffer is only used by RadioModel.summary. The multimodal
# projector consumes RadioModel.features for both images and video.
return None
if name.startswith(cls._omni_tensor_prefixes):
return name, gen

if "radio_model.model.patch_generator.video_embedder" in name or name.startswith("vision_projector.vision_final_layernorm."):
return MmprojModel.filter_tensors((name, gen))

return super().filter_tensors(item)

def tensor_force_quant(self, name, new_name, bid, n_dims):
if new_name in ("v.position_embd.weight", "v.class_embd"):
return gguf.GGMLQuantizationType.F32
return super().tensor_force_quant(name, new_name, bid, n_dims)

def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
if name.startswith(self._omni_tensor_prefixes):
if name == "vision_model.embeddings.video_patch_projection.weight":
data_torch = data_torch.reshape(
self.hparams["hidden_size"],
6,
self.hparams["patch_size"],
self.hparams["patch_size"],
)
yield gguf.TENSOR_NAMES[gguf.MODEL_TENSOR.V_ENC_EMBD_PATCH] + ".weight.1", data_torch
return

if name.startswith("vision_projector.mlp1."):
projector_mapping = {
"vision_projector.mlp1.norm.weight": "mlp1.0.weight",
"vision_projector.mlp1.linear1.weight": "mlp1.1.weight",
"vision_projector.mlp1.linear2.weight": "mlp1.3.weight",
}
name = projector_mapping[name]
elif name == "vision_model.embeddings.patch_projection.weight":
data_torch = data_torch.reshape(
self.hparams["hidden_size"],
3,
self.hparams["patch_size"],
self.hparams["patch_size"],
)
elif name == "vision_model.embeddings.position_embedding":
data_torch = data_torch.squeeze(0)
name += ".weight"
elif ".layer_scale" in name and name.endswith(".lambda1"):
name = name.removesuffix("lambda1") + "weight"

yield from MmprojModel.modify_tensors(self, data_torch, name, bid)
return

if "patch_generator.pos_embed" in name:
# Keep the full table for runtime interpolation.
yield from MmprojModel.modify_tensors(self, data_torch, name, bid)
return

if "patch_generator.video_embedder" in name:
patch_size = self.hparams["patch_size"]
n_embd = self.hparams["hidden_size"]
temporal_patch_size = self.global_config["video_temporal_patch_size"]
if temporal_patch_size != 2:
raise ValueError("Current implementation only supports a temporal patch size of 2")
data_torch = data_torch.reshape(n_embd, temporal_patch_size * 3, patch_size, patch_size)
new_name = gguf.TENSOR_NAMES[gguf.MODEL_TENSOR.V_ENC_EMBD_PATCH] + ".weight.1"
yield new_name, data_torch
return

yield from super().modify_tensors(data_torch, name, bid)


@ModelBase.register("NemotronForCausalLM")
@ModelBase.example("nvidia/Minitron-4B-Base")
class NemotronModel(TextModel):
Expand Down Expand Up @@ -382,6 +492,8 @@ def get_attn_layers(self):
@classmethod
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
name, gen = item
if name.startswith("language_model."):
name = name[len("language_model."):]
if name.startswith("mtp."):
# --no-mtp: drop the MTP head entirely
if cls.no_mtp:
Expand Down Expand Up @@ -531,6 +643,14 @@ def set_vocab(self):
"mtp.layers.1.final_layernorm.weight": "model.layers.{bid}.shared_head.norm.weight",
}

def _generate_nvfp4_tensors(self):
if self._mtp_bid is not None:
for name in list(self.model_tensors):
if name.startswith("mtp.layers.1.mixer"):
new_name = f"backbone.layers.{self._mtp_bid}.{name.split('.', 3)[3]}"
self.model_tensors[new_name] = self.model_tensors.pop(name)
super()._generate_nvfp4_tensors()

def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
# mtp.layers.0: NextN input fusion + attention
# mtp.layers.1: MoE + final head norm
Expand Down
1 change: 1 addition & 0 deletions gguf-py/gguf/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6238,6 +6238,7 @@ class VisionProjectorType:
GLM5V = "glm5v"
YOUTUVL = "youtuvl"
NEMOTRON_V2_VL = "nemotron_v2_vl"
NEMOTRON_OMNI = "nemotron_omni"
QWEN3TTS_SPKENC = "qwen3tts_spkenc" # audio: ECAPA-TDNN speaker encoder
QWEN3TTS_GEN = "qwen3tts_gen" # audio generation: code_predictor
POCKETTTS_SPKENC = "pockettts_spkenc" # audio: mimi encoder as voice-prompt encoder
Expand Down
14 changes: 14 additions & 0 deletions gguf-py/gguf/tensor_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,7 @@ class TensorNameMap:
"vision_model.class_embedding", # llama 4
"model.vision.patch_embedding.cls_embedding", # cogvlm
"vision_model.radio_model.model.patch_generator.cls_token.token", # Nemotron Nano v2 VL
"vision_model.embeddings.cls_register_token", # Nemotron Omni
"model.vision_model.embeddings.class_embedding", # Deepseek-OCR
),

Expand All @@ -1756,6 +1757,7 @@ class TensorNameMap:
"model.vision_model.embeddings.patch_embedding", # Deepseek-OCR CLIP
"siglip2.vision_model.embeddings.patch_embedding",
"vision_model.radio_model.model.patch_generator.embedder", # Nemotron Nano v2 VL
"vision_model.embeddings.patch_projection", # Nemotron Omni
"model.vision_tower.patch_embedder.input_proj", # gemma4
"vision_tower.patch_embed.patchifier.proj", # dots.ocr
"vision_encoder.patch_embed.proj", # dots3note
Expand Down Expand Up @@ -1788,6 +1790,7 @@ class TensorNameMap:
"model.vision.patch_embedding.position_embedding", # cogvlm
"visual.embeddings.position_embedding", # glm4v
"vision_model.radio_model.model.patch_generator.pos_embed", # Nemotron Nano v2 VL
"vision_model.embeddings.position_embedding", # Nemotron Omni
"model.vision_tower.patch_embedder.position_embedding_table", # gemma4
"vision_model.positional_embedding", # Step3-VL
"model.vision_embedder.pos_embedding", # gemma4 unified
Expand Down Expand Up @@ -1818,6 +1821,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_ATTN_Q: (
"vision_model.encoder.layer.{bid}.attention.attention.query", # Nemotron Omni
"model.vision_tower.vision_model.encoder.layers.{bid}.self_attn.q_proj", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.self_attn.q_proj",
"model.vision_tower.encoder.layers.{bid}.self_attn.q_proj", # minicpmv4_6
Expand Down Expand Up @@ -1846,6 +1850,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_ATTN_K: (
"vision_model.encoder.layer.{bid}.attention.attention.key", # Nemotron Omni
"model.vision_tower.vision_model.encoder.layers.{bid}.self_attn.k_proj", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.self_attn.k_proj",
"model.vision_tower.encoder.layers.{bid}.self_attn.k_proj", # minicpmv4_6
Expand Down Expand Up @@ -1874,6 +1879,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_ATTN_V: (
"vision_model.encoder.layer.{bid}.attention.attention.value", # Nemotron Omni
"model.vision_tower.vision_model.encoder.layers.{bid}.self_attn.v_proj", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.self_attn.v_proj",
"model.vision_tower.encoder.layers.{bid}.self_attn.v_proj", # minicpmv4_6
Expand All @@ -1894,6 +1900,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_INPUT_NORM: (
"vision_model.encoder.layer.{bid}.norm1", # Nemotron Omni
"vision.blocks.{bid}.norm1", # deepseek4v
"model.vision_tower.vision_model.encoder.layers.{bid}.layer_norm1", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.layer_norm1",
Expand All @@ -1920,6 +1927,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_ATTN_O: (
"vision_model.encoder.layer.{bid}.attention.output.dense", # Nemotron Omni
"vision.blocks.{bid}.attn.wo", # deepseek4v
"model.vision_tower.vision_model.encoder.layers.{bid}.self_attn.out_proj", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.self_attn.out_proj",
Expand Down Expand Up @@ -1952,6 +1960,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_POST_ATTN_NORM: (
"vision_model.encoder.layer.{bid}.norm2", # Nemotron Omni
"vision.blocks.{bid}.norm2", # deepseek4v
"model.vision_tower.vision_model.encoder.layers.{bid}.layer_norm2", # Granite4Vision
"vision_tower.vision_model.encoder.layers.{bid}.layer_norm2",
Expand Down Expand Up @@ -1979,6 +1988,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_FFN_UP: (
"vision_model.encoder.layer.{bid}.mlp.fc1", # Nemotron Omni
"vision.blocks.{bid}.mlp.w1_up", # deepseek4v (split from fused w1)
"vision_encoder.blocks.{bid}.mlp.fc3", # dots3note
"model.vision_tower.vision_model.encoder.layers.{bid}.mlp.fc1", # Granite4Vision
Expand Down Expand Up @@ -2016,6 +2026,7 @@ class TensorNameMap:
),

MODEL_TENSOR.V_ENC_FFN_DOWN: (
"vision_model.encoder.layer.{bid}.mlp.fc2", # Nemotron Omni
"vision.blocks.{bid}.mlp.w2", # deepseek4v
"vision_encoder.blocks.{bid}.mlp.fc2", # dots3note
"model.vision_tower.vision_model.encoder.layers.{bid}.mlp.fc2", # Granite4Vision
Expand Down Expand Up @@ -2074,12 +2085,14 @@ class TensorNameMap:
),

MODEL_TENSOR.V_LAYER_SCALE_1: (
"vision_model.encoder.layer.{bid}.layer_scale1", # Nemotron Omni
"vision_tower.vision_model.encoder.layers.{bid}.ls1", # InternVL
"model.vision_tower.encoder.layer.{bid}.lambda_1", # Intern-S1
"vision_model.transformer.resblocks.{bid}.ls_1", # Step3-VL
),

MODEL_TENSOR.V_LAYER_SCALE_2: (
"vision_model.encoder.layer.{bid}.layer_scale2", # Nemotron Omni
"vision_tower.vision_model.encoder.layers.{bid}.ls2", # InternVL
"model.vision_tower.encoder.layer.{bid}.lambda_2", # Intern-S1
"vision_model.transformer.resblocks.{bid}.ls_2", # Step3-VL
Expand Down Expand Up @@ -2114,6 +2127,7 @@ class TensorNameMap:
"siglip2.vision_model.post_layernorm",
"model.qwen2_model.model.model.norm", # Deepseek-OCR-2 qwen2
"model.vision_tower.ln_post", # muse-glimmer
"vision_projector.vision_final_layernorm", # Nemotron Omni Reasoning V3
),

MODEL_TENSOR.V_MM_POST_NORM: (
Expand Down
4 changes: 2 additions & 2 deletions src/models/dflash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ llama_model_dflash::graph<false>::graph(const llama_model & model, const llm_gra
res->t_inp_tokens = inp_tokens;

ggml_tensor * inp_anchor = nullptr;
if (model.lilicorr_pass_hidden_proj && ubatch.embd_state) {
if (model.lilicorr_pass_hidden_proj && ubatch.embd_state && n_tokens == (int64_t) hparams.dflash_block_size * ubatch.n_seqs_unq) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here as well.

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.

Again, not sure how it passed by earlier!

AFAIK before starting llama-server does a dummy pass with 2 tokens and directly calls the decoder; which causes the LiliCorr head to try to make the lattice with 2 tokens. It can only make the lattice for 8 tokens currently, since we have implemented it that way in #30506.

So the dummy pass fails this assert in (dflash.cpp:664), and the server stops -

GGML_ASSERT(tokens_per_block == block_size);

// LiliCorr sets inp_anchor to pass the context features to the lattice scorer
auto inp = std::make_unique<llm_graph_input_embd_h>(n_embd, n_embd);
inp->tokens = inp_tokens;
Expand Down Expand Up @@ -1100,7 +1100,7 @@ llama_model_dflash::graph<false>::graph(const llama_model & model, const llm_gra

if (model.dflash_selector_hidden) {
build_dflash2_selector(*this, model, inp_tokens);
} else if (model.lilicorr_pass_hidden_proj && ubatch.embd_state) {
} else if (model.lilicorr_pass_hidden_proj && ubatch.embd_state && n_tokens == (int64_t) hparams.dflash_block_size * ubatch.n_seqs_unq) {
build_lilicorr_scores(*this, model, tok_embd, inp_anchor);
}
}
Expand Down
Loading
Loading