66// types — ggml's ggml_mul_mat handles Q8_0 × F32 dequantization transparently.
77//
88// GGUF arch: "qwen35-dflash-draft" (from convert_dflash_to_gguf.py /
9- // quantize_draft_q8.py) or the newer "dflash-draft" export. Tensor naming
10- // convention:
9+ // quantize_draft_q8.py). Tensor naming convention:
1110//
12- // dflash.fc.weight / dflash_fc.weight [5*hidden, hidden] Q8_0 / F16
13- // dflash.hidden_norm.weight /
14- // dflash_hidden_norm.weight [hidden] F32
11+ // dflash.fc.weight [5*hidden, hidden] Q8_0 / F16
12+ // dflash.hidden_norm.weight [hidden] F32
1513// output_norm.weight [hidden] F32
1614// blk.<i>.attn_norm.weight [hidden] F32
1715// blk.<i>.ffn_norm.weight [hidden] F32
@@ -108,6 +106,14 @@ uint32_t get_u32_or(const gguf_context * g, const char * key, uint32_t fallback)
108106 return gguf_get_val_u32 (g, id);
109107}
110108
109+ int count_swa_layers (const DraftWeights & w) {
110+ int n_swa = 0 ;
111+ for (const DraftLayer & layer : w.layers ) {
112+ if (layer.is_swa ) n_swa++;
113+ }
114+ return n_swa;
115+ }
116+
111117} // namespace
112118
113119bool load_draft_gguf (const std::string & path,
@@ -126,6 +132,7 @@ bool load_draft_gguf(const std::string & path,
126132 }
127133
128134 // Validate arch
135+ std::string arch_s;
129136 {
130137 int64_t arch_id = gguf_find_key (gctx, " general.architecture" );
131138 if (arch_id < 0 ) {
@@ -134,8 +141,8 @@ bool load_draft_gguf(const std::string & path,
134141 return false ;
135142 }
136143 const char * arch = gguf_get_val_str (gctx, arch_id);
137- if ( std::string (arch) != " qwen35-dflash-draft " &&
138- std::string (arch) != " dflash-draft" ) {
144+ arch_s = arch;
145+ if (arch_s != " qwen35-dflash-draft " && arch_s != " dflash-draft" ) {
139146 set_last_error (std::string (" unexpected draft arch: " ) + arch +
140147 " (expected qwen35-dflash-draft or dflash-draft)" );
141148 gguf_free (gctx);
@@ -144,8 +151,7 @@ bool load_draft_gguf(const std::string & path,
144151 }
145152
146153 // Read dimensions from GGUF metadata
147- int64_t arch_id = gguf_find_key (gctx, " general.architecture" );
148- const char * A = gguf_get_val_str (gctx, arch_id);
154+ const char * A = arch_s.c_str ();
149155 char key[128 ];
150156
151157 auto read_u32 = [&](const char * suffix, uint32_t fallback) -> uint32_t {
@@ -162,16 +168,17 @@ bool load_draft_gguf(const std::string & path,
162168 const uint32_t block_sz = read_u32 (" dflash.block_size" , 0 );
163169 uint32_t n_tgt_lay = read_u32 (" dflash.n_target_layers" , 0 );
164170 if (n_tgt_lay == 0 ) {
165- const uint32_t n_tgt_feat = read_u32 (" dflash.n_target_features" , 0 );
166- if (n_tgt_feat != 0 && n_embd != 0 && (n_tgt_feat % n_embd) == 0 ) {
167- n_tgt_lay = n_tgt_feat / n_embd;
171+ std::snprintf (key, sizeof (key), " %s.%s" , A, " dflash.target_layer_ids" );
172+ const int64_t target_ids_id = gguf_find_key (gctx, key);
173+ if (target_ids_id >= 0 &&
174+ gguf_get_kv_type (gctx, target_ids_id) == GGUF_TYPE_ARRAY ) {
175+ n_tgt_lay = (uint32_t )gguf_get_arr_n (gctx, target_ids_id);
168176 }
169177 }
170- if (n_tgt_lay == 0 ) {
171- std::snprintf (key, sizeof (key), " %s.%s" , A, " dflash.target_layer_ids" );
172- int64_t id = gguf_find_key (gctx, key);
173- if (id >= 0 ) {
174- n_tgt_lay = (uint32_t )gguf_get_arr_n (gctx, id);
178+ if (n_tgt_lay == 0 && n_embd != 0 ) {
179+ const uint32_t n_target_features = read_u32 (" dflash.n_target_features" , 0 );
180+ if (n_target_features != 0 && (n_target_features % n_embd) == 0 ) {
181+ n_tgt_lay = n_target_features / n_embd;
175182 }
176183 }
177184
@@ -240,17 +247,17 @@ bool load_draft_gguf(const std::string & path,
240247 auto g = [&](const char * name) -> ggml_tensor * {
241248 return ggml_get_tensor (meta_ctx, name);
242249 };
243-
244- auto first = [] (ggml_tensor * a, ggml_tensor * b) -> ggml_tensor * {
245- return a ? a : b ;
250+ auto g_any = [&]( const char * a, const char * b) -> ggml_tensor * {
251+ if (ggml_tensor * t = g (a)) return t;
252+ return g (b) ;
246253 };
247254
248- out.fc = first ( g ( " dflash.fc.weight" ), g ( " dflash_fc.weight" ) );
249- out.hidden_norm = first ( g ( " dflash.hidden_norm.weight" ), g ( " dflash_hidden_norm.weight" ) );
255+ out.fc = g_any ( " dflash.fc.weight" , " dflash_fc.weight" );
256+ out.hidden_norm = g_any ( " dflash.hidden_norm.weight" , " dflash_hidden_norm.weight" );
250257 out.out_norm = g (" output_norm.weight" );
251258 if (!out.fc || !out.hidden_norm || !out.out_norm ) {
252259 set_last_error (" draft GGUF: missing top-level tensors "
253- " (dflash fc / dflash hidden norm / output_norm)" );
260+ " (dflash.fc|dflash_fc / dflash.hidden_norm|dflash_hidden_norm / output_norm)" );
254261 gguf_free (gctx);
255262 return false ;
256263 }
@@ -263,7 +270,8 @@ bool load_draft_gguf(const std::string & path,
263270 };
264271 DraftLayer & L = out.layers [il];
265272 L.attn_norm = fnd (" attn_norm.weight" );
266- L.ffn_norm = first (fnd (" ffn_norm.weight" ), fnd (" post_attention_norm.weight" ));
273+ L.ffn_norm = fnd (" ffn_norm.weight" );
274+ if (!L.ffn_norm ) L.ffn_norm = fnd (" post_attention_norm.weight" );
267275 L.wq = fnd (" attn_q.weight" );
268276 L.wk = fnd (" attn_k.weight" );
269277 L.wv = fnd (" attn_v.weight" );
@@ -283,6 +291,26 @@ bool load_draft_gguf(const std::string & path,
283291 }
284292 }
285293
294+ // GGUF Qwen3.6 drafters carry SWA metadata emitted by the converter:
295+ // dflash-draft.attention.sliding_window = 2048
296+ // dflash-draft.attention.sliding_window_pattern = [true,true,true,true,false]
297+ out.swa_window = (int )read_u32 (" attention.sliding_window" , 0 );
298+ std::snprintf (key, sizeof (key), " %s.%s" , A, " attention.sliding_window_pattern" );
299+ int64_t swp_id = gguf_find_key (gctx, key);
300+ if (swp_id >= 0 && gguf_get_kv_type (gctx, swp_id) == GGUF_TYPE_ARRAY &&
301+ gguf_get_arr_type (gctx, swp_id) == GGUF_TYPE_BOOL ) {
302+ const size_t n = gguf_get_arr_n (gctx, swp_id);
303+ const bool * pattern = static_cast <const bool *>(gguf_get_arr_data (gctx, swp_id));
304+ for (size_t il = 0 ; il < n && il < out.layers .size (); il++) {
305+ out.layers [il].is_swa = pattern[il];
306+ }
307+ }
308+ const int n_swa = count_swa_layers (out);
309+ if (n_swa > 0 ) {
310+ std::fprintf (stderr, " [draft GGUF] SWA layers: %d/%d (window=%d)\n " ,
311+ n_swa, out.n_layer , out.swa_window );
312+ }
313+
286314 // ── 3. Allocate CUDA buffer for all tensors ──────────────────────────
287315 out.buf = ggml_backend_alloc_ctx_tensors (meta_ctx, backend);
288316 if (!out.buf ) {
0 commit comments