zk-Armor's picture
download
raw
32.1 kB
#include "models.h"
#include <cstdlib>
#include <cstring>
// Noncausal block drafter: target tap features provide context K/V while draft
// tokens pass through the dense trunk and sequential correction/Markov head.
void llama_model_dspark::load_arch_hparams(llama_model_loader & ml) {
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
ml.get_key(LLM_KV_DSPARK_BLOCK_SIZE, hparams.dspark_block_size, true);
ml.get_key(LLM_KV_DSPARK_MASK_TOKEN_ID, hparams.dspark_mask_token_id, true);
ml.get_key(LLM_KV_DSPARK_MARKOV_RANK, hparams.dspark_markov_rank, false);
ml.get_key(LLM_KV_DSPARK_HIDDEN_CORRECTION, hparams.dspark_hidden_correction, false);
ml.get_key(LLM_KV_DSPARK_MARKOV_DEPLOY_EXPOSURE, hparams.dspark_markov_deploy_exposure, false);
if (hparams.dspark_hidden_correction) {
ml.get_key(LLM_KV_DSPARK_CORRECTION_SIZE, hparams.dspark_correction_size, true);
if (!hparams.dspark_markov_deploy_exposure || !hparams.dspark_correction_size || !hparams.dspark_markov_rank) {
throw std::runtime_error(
"DSpark hidden correction requires deploy-exposure Markov and positive dimensions");
}
} else if (hparams.dspark_markov_deploy_exposure) {
throw std::runtime_error("DSpark deploy-exposure without hidden correction is not implemented");
}
ml.get_key(LLM_KV_DSPARK_CONFIDENCE_HEAD, hparams.dspark_confidence_head, false);
ml.get_key(LLM_KV_DSPARK_CONFIDENCE_WITH_MARKOV, hparams.dspark_confidence_head_with_markov, false);
// Noise-level conditioning is optional; older checkpoints omit it.
ml.get_key(LLM_KV_DSPARK_LOG_SNR_CONDITIONING, hparams.dspark_log_snr_conditioning, false);
if (hparams.dspark_log_snr_conditioning) {
// required once the flag is set: silently defaulting either bound to 0.0f
// would collapse (max_snr - min_snr) to zero in the featurizer below and
// fill the conditioning input with NaNs instead of failing to load.
ml.get_key(LLM_KV_DSPARK_MIN_LOG_SNR, hparams.dspark_min_log_snr, true);
ml.get_key(LLM_KV_DSPARK_MAX_LOG_SNR, hparams.dspark_max_log_snr, true);
if (!std::isfinite(hparams.dspark_min_log_snr) || !std::isfinite(hparams.dspark_max_log_snr)) {
throw std::runtime_error("dspark log-SNR conditioning: min/max_log_snr must be finite");
}
if (!(hparams.dspark_max_log_snr > hparams.dspark_min_log_snr)) {
throw std::runtime_error("dspark log-SNR conditioning: max_log_snr must be greater than min_log_snr");
}
}
// ordered set of TARGET-model layer indices this drafter taps. note this
// indexes into the target's (large) layer count, not this drafter's own
// (tiny) n_layer -- get_arr_n first to learn the count, then get_arr to
// fill the fixed-capacity array (llama_hparams must stay trivially
// copyable, so a std::vector field isn't an option here).
ml.get_arr_n(LLM_KV_DSPARK_TARGET_LAYERS, hparams.n_dspark_target_layers, true);
ml.get_key_or_arr(LLM_KV_DSPARK_TARGET_LAYERS, hparams.dspark_target_layers, hparams.n_dspark_target_layers, true);
// the drafter trunk itself has no dedicated size bucket (it's always tiny
// relative to its target); leave it unclassified rather than overload an
// unrelated bucket.
type = LLM_TYPE_UNKNOWN;
}
void llama_model_dspark::load_arch_tensors(llama_model_loader & ml) {
LLAMA_LOAD_LOCALS;
const int64_t n_capture = hparams.n_dspark_target_layers;
const int64_t n_embd_cap = n_capture * n_embd;
const int64_t markov_rank = hparams.dspark_markov_rank;
// dspark ships no tokenizer of its own (converter calls _set_vocab_none():
// it ties to the TARGET model's vocab), so vocab.n_tokens() (LLAMA_LOAD_LOCALS'
// n_vocab) is 0 here. The real vocab width only exists as the token_embd
// tensor's own shape in the GGUF -- peek at it before creating anything.
ggml_tensor * tok_embd_meta = ml.get_tensor_meta(tn(LLM_TENSOR_TOKEN_EMBD, "weight").str().c_str());
const int64_t n_vocab_dspark = tok_embd_meta ? tok_embd_meta->ne[1] : n_vocab;
GGML_ASSERT(n_vocab_dspark > 0 && "dspark: could not determine vocab size from token_embd.weight");
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), { n_embd, n_vocab_dspark }, 0);
output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), { n_embd }, 0);
if (params.dspark_head_source) {
const auto & source = *params.dspark_head_source;
if (!source.output || source.output->ne[0] != n_embd || source.output->ne[1] != n_vocab_dspark ||
!source.output->buffer || source.output_s || source.output_in_s) {
throw std::runtime_error("DSpark shared head requires a loaded, dimension-matched, unscaled target head");
}
// Account for the local tensor without allocating or reading its weights.
create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), { n_embd, n_vocab_dspark }, TENSOR_NOT_REQUIRED | TENSOR_SKIP);
output = source.output;
hadamard_weight_blocks.erase("output.weight");
const auto rotation = source.hadamard_rotations.find(output);
if (rotation != source.hadamard_rotations.end()) {
hadamard_rotations.emplace(output, rotation->second);
}
} else {
output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), { n_embd, n_vocab_dspark }, TENSOR_NOT_REQUIRED);
if (!output) {
output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), { n_embd, n_vocab_dspark }, TENSOR_DUPLICATED);
}
}
// target-feature projection: [n_capture * n_embd -> n_embd], then RMSNorm.
dspark_fc = create_tensor(tn(LLM_TENSOR_DSPARK_FC, "weight"), { n_embd_cap, n_embd }, 0);
dspark_hidden_norm = create_tensor(tn(LLM_TENSOR_DSPARK_HIDDEN_NORM, "weight"), { n_embd }, 0);
// auxiliary heads: loaded so the GGUF's tensor inventory is fully mapped
if (hparams.dspark_hidden_correction) {
const int64_t width = hparams.dspark_correction_size;
if (hparams.dspark_mask_token_id >= n_vocab_dspark) {
throw std::runtime_error("DSpark mask token outside vocabulary");
}
dspark_corr_hnorm = create_tensor(tn(LLM_TENSOR_DSPARK_CORR_HNORM, "weight"), { n_embd }, 0);
dspark_corr_enorm = create_tensor(tn(LLM_TENSOR_DSPARK_CORR_ENORM, "weight"), { n_embd }, 0);
dspark_corr_gate = create_tensor(tn(LLM_TENSOR_DSPARK_CORR_GATE, "weight"), { 2 * n_embd, width }, 0);
dspark_corr_up = create_tensor(tn(LLM_TENSOR_DSPARK_CORR_UP, "weight"), { 2 * n_embd, width }, 0);
dspark_corr_down = create_tensor(tn(LLM_TENSOR_DSPARK_CORR_DOWN, "weight"), { width, n_embd }, 0);
}
// and available to a future Phase 2 host-side loop, but not built into
// this graph (see file header comment).
if (markov_rank > 0) {
const int flags = hparams.dspark_hidden_correction ? 0 : TENSOR_NOT_REQUIRED;
dspark_markov_head_a =
create_tensor(tn(LLM_TENSOR_DSPARK_MARKOV_HEAD_A, "weight"), { markov_rank, n_vocab_dspark }, flags);
dspark_markov_head_b =
create_tensor(tn(LLM_TENSOR_DSPARK_MARKOV_HEAD_B, "weight"), { markov_rank, n_vocab_dspark }, flags);
}
if (hparams.dspark_confidence_head) {
const int64_t conf_in = n_embd + (hparams.dspark_confidence_head_with_markov ? markov_rank : 0);
dspark_confidence_head =
create_tensor(tn(LLM_TENSOR_DSPARK_CONFIDENCE_HEAD, "weight"), { conf_in, 1 }, TENSOR_NOT_REQUIRED);
dspark_confidence_head_b =
create_tensor(tn(LLM_TENSOR_DSPARK_CONFIDENCE_HEAD, "bias"), { 1 }, TENSOR_NOT_REQUIRED);
}
dspark_mode_embedding =
create_tensor(tn(LLM_TENSOR_DSPARK_MODE_EMBEDDING, "bias"), { n_embd }, TENSOR_NOT_REQUIRED);
if (dspark_mode_embedding) {
LLAMA_LOG_INFO("dspark: mode embedding active on draft-token input only\n");
}
// GIDD log-SNR conditioning (LogSnrEmbed): unlike markov_head/confidence_head
// above, this IS built into this graph (graph::graph() below) -- it changes
// the draft embedding every forward pass, not a deferred host-side
// adjustment -- so if the GGUF says log_snr_conditioning is on, the weights
// are REQUIRED: a missing tensor here is a broken conversion, not something
// to silently degrade past.
if (hparams.dspark_log_snr_conditioning) {
const int64_t n_freq = 128; // matches LogSnrEmbed.NUM_FREQ_FEATURES in dspark_snr.py
dspark_log_snr_fc1_w = create_tensor(tn(LLM_TENSOR_DSPARK_PROD_LOG_SNR_FC1, "weight"), { n_freq, n_embd }, 0);
dspark_log_snr_fc1_b = create_tensor(tn(LLM_TENSOR_DSPARK_PROD_LOG_SNR_FC1, "bias"), { n_embd }, 0);
dspark_log_snr_fc2_w = create_tensor(tn(LLM_TENSOR_DSPARK_PROD_LOG_SNR_FC2, "weight"), { n_embd, n_embd }, 0);
dspark_log_snr_fc2_b = create_tensor(tn(LLM_TENSOR_DSPARK_PROD_LOG_SNR_FC2, "bias"), { n_embd }, 0);
}
for (int i = 0; i < n_layer; ++i) {
auto & layer = layers[i];
layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), { n_embd }, 0);
create_tensor_qkv(layer, i, n_embd, n_embd_head_k * n_head, n_embd_gqa, n_embd_gqa, 0);
layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), { n_embd_head_k * n_head, n_embd }, 0);
layer.attn_q_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_NORM, "weight", i), { n_embd_head_k }, 0);
layer.attn_k_norm = create_tensor(tn(LLM_TENSOR_ATTN_K_NORM, "weight", i), { n_embd_head_k }, 0);
layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), { n_embd }, 0);
layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), { n_embd, n_ff }, 0);
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), { n_ff, n_embd }, 0);
layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), { n_embd, n_ff }, 0);
}
}
std::unique_ptr<llm_graph_context> llama_model_dspark::build_arch_graph(const llm_graph_params & params) const {
return std::make_unique<graph>(*this, params);
}
llama_model_dspark::graph::graph(const llama_model & model, const llm_graph_params & params) :
llm_graph_context(params) {
const int64_t n_embd_head = hparams.n_embd_head_v();
GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
const int64_t n_embd_cap = (int64_t) hparams.n_dspark_target_layers * n_embd;
// --- stage the raw target-tap context window -----------------------------
// this is the piece that doesn't fit llama_batch.token/embd (different
// width, different row count than the draft block) -- see llama_dspark_ctx
// in llama-graph.h and llama_set_dspark_ctx() in llama-ext.h.
//
// llama_context builds trial graphs for compute-buffer sizing/warmup at
// several points, not just once before the very first decode(): the
// initial sched_reserve() at context-construction time, AND additional
// internal reserve passes triggered from inside decode() itself (e.g. a
// dummy single-token graph), using ubatch shapes that have nothing to do
// with whatever the caller most recently staged via llama_set_dspark_ctx().
// The only thing that reliably distinguishes "this graph build corresponds
// to the context I just staged" from "this is some other trial/reserve
// build" is shape consistency: the staged n_ctx_rows must actually fit
// inside *this* graph's n_tokens. When it doesn't, fall back to the same
// reserve-safe placeholder split used when nothing is staged at all --
// mirrors how llm_graph_context::build_inp_cross_embd falls back to
// hparams-derived sizes whenever llama_cross has no (matching) data.
const bool have_staged_ctx = params.dspark_ctx && !params.dspark_ctx->v_ctx_feat.empty() &&
params.dspark_ctx->n_ctx_rows > 0 && params.dspark_ctx->n_ctx_rows < n_tokens &&
n_tokens - params.dspark_ctx->n_ctx_rows <= hparams.dspark_block_size;
int64_t n_ctx_rows;
if (have_staged_ctx) {
n_ctx_rows = params.dspark_ctx->n_ctx_rows;
} else {
// reserve-time / shape-mismatched placeholder: leave exactly one row
// for the draft block so n_draft is always >= 1, and exercise the
// same concat/fc/hidden_norm topology as real usage whenever there's
// more than one token to split.
n_ctx_rows = std::max<int64_t>(n_tokens - hparams.dspark_block_size, 0);
}
const int64_t n_draft = n_tokens - n_ctx_rows;
GGML_ASSERT(n_draft > 0 && "dspark: no rows left for the draft block");
const char * reuse_env = std::getenv("LLAMA_DSPARK_REUSE_MASK");
if (reuse_env && std::strcmp(reuse_env, "0") && std::strcmp(reuse_env, "1")) {
throw std::runtime_error("LLAMA_DSPARK_REUSE_MASK must be 0 or 1");
}
const bool reuse_mask =
have_staged_ctx && hparams.dspark_hidden_correction && reuse_env && std::strcmp(reuse_env, "1") == 0;
ggml_tensor * target_ctx = nullptr;
llm_graph_input_dspark_ctx * staged_input = nullptr;
if (n_ctx_rows > 0) {
auto ctx_input = std::make_unique<llm_graph_input_dspark_ctx>(params.dspark_ctx);
staged_input = ctx_input.get();
if (reuse_mask) {
ctx_input->reuse_mask_id = hparams.dspark_mask_token_id;
}
ctx_input->ctx_feat = ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, n_embd_cap, n_ctx_rows);
ggml_set_input(ctx_input->ctx_feat);
ggml_set_name(ctx_input->ctx_feat, "dspark_ctx_feat");
ggml_tensor * raw_tap = ctx_input->ctx_feat;
res->add_input(std::move(ctx_input));
// fc + hidden_norm are applied ONCE for the whole call; the result is a
// fixed input re-projected fresh through each layer's own k_proj/v_proj
// below (it never itself passes through a layer's attn_norm/FFN).
target_ctx = build_lora_mm(model.dspark_fc, raw_tap);
cb(target_ctx, "dspark_fc", -1);
target_ctx = build_norm(target_ctx, model.dspark_hidden_norm, nullptr, LLM_NORM_RMS, -1);
cb(target_ctx, "dspark_hidden_norm", -1);
}
// --- draft-block token embeddings (the trunk residual stream) ------------
// built over the FULL n_tokens width (like any other arch) then sliced to
// the trailing n_draft columns: the leading n_ctx_rows columns would be
// embeddings of whatever placeholder token id the caller put there and are
// never used for anything.
ggml_tensor * inpL = build_inp_embd(model.tok_embd);
inpL = ggml_view_2d(ctx0, inpL, n_embd, n_draft, inpL->nb[1], inpL->nb[1] * n_ctx_rows);
cb(inpL, "dspark_draft_embd", -1);
// --- GIDD log-SNR conditioning (LogSnrEmbed, dspark_snr.py) --------------
// added to the draft noise embedding BEFORE the layer loop, matching
// Qwen3DSparkModelSnr._forward_backbone exactly. The per-position log-SNR
// pattern is the fixed round-1 inference convention: anchor position of
// each block (every block_size-th draft row, starting at 0) at
// max_log_snr, every other (masked) position at min_log_snr -- this
// drafter always operates on a full block_size-aligned draft block (see
// file header comment), so n_draft is a multiple of block_size in every
// real decode call.
if (hparams.dspark_log_snr_conditioning) {
const int64_t n_freq = 128;
const int64_t half = n_freq / 2;
const float min_snr = hparams.dspark_min_log_snr;
const float max_snr = hparams.dspark_max_log_snr;
const int64_t bsz = hparams.dspark_block_size > 0 ? hparams.dspark_block_size : n_draft;
// Opt-in until real-weight parity and backend-specific timing pass.
const char * compact_env = std::getenv("LLAMA_DSPARK_SNR_TWO_ROWS");
const bool compact_snr = compact_env && std::strcmp(compact_env, "1") == 0 && n_draft > 2 && n_draft <= bsz;
const int64_t snr_rows = compact_snr ? 2 : n_draft;
// host-side: exact port of LogSnrEmbed.forward's featurization fused
// with the anchor/mask pattern above. Both are pure functions of
// n_draft/block_size/min_log_snr/max_log_snr -- all known here, no
// runtime/ubatch data involved -- so precomputing on the host (rather
// than chaining ggml_arange/ggml_sin/ggml_cos in-graph) keeps this
// directly auditable line-for-line against the python reference.
std::vector<float> feat((size_t) (n_freq * snr_rows));
for (int64_t pos = 0; pos < snr_rows; ++pos) {
const float log_snr = (pos % bsz == 0) ? max_snr : min_snr;
const float t = (log_snr - min_snr) / (max_snr - min_snr) * 1000.0f;
for (int64_t i = 0; i < half; ++i) {
const float freq = expf(-logf(10000.0f) * (float) i / (float) half);
const float angle = t * freq;
feat[(size_t) (pos * n_freq + i)] = sinf(angle);
feat[(size_t) (pos * n_freq + half + i)] = cosf(angle);
}
}
auto logsnr_input = std::make_unique<llm_graph_input_dspark_logsnr>(std::move(feat));
logsnr_input->feat = ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, n_freq, snr_rows);
ggml_set_input(logsnr_input->feat);
ggml_set_name(logsnr_input->feat, "dspark_log_snr_feat");
ggml_tensor * snr_feat = logsnr_input->feat;
res->add_input(std::move(logsnr_input));
ggml_tensor * snr_hidden = build_lora_mm(model.dspark_log_snr_fc1_w, snr_feat);
snr_hidden = ggml_add(ctx0, snr_hidden, model.dspark_log_snr_fc1_b);
snr_hidden = ggml_silu(ctx0, snr_hidden);
cb(snr_hidden, "dspark_log_snr_fc1", -1);
ggml_tensor * snr_embed = build_lora_mm(model.dspark_log_snr_fc2_w, snr_hidden);
snr_embed = ggml_add(ctx0, snr_embed, model.dspark_log_snr_fc2_b);
cb(snr_embed, "dspark_log_snr_fc2", -1);
if (compact_snr) {
auto * high = ggml_view_2d(ctx0, snr_embed, n_embd, 1, snr_embed->nb[1], 0);
auto * low = ggml_view_2d(ctx0, snr_embed, n_embd, 1, snr_embed->nb[1], snr_embed->nb[1]);
auto * masks = ggml_repeat_4d(ctx0, low, n_embd, n_draft - 1, 1, 1);
snr_embed = ggml_concat(ctx0, high, masks, 1);
cb(snr_embed, "dspark_log_snr_expanded", -1);
}
inpL = ggml_add(ctx0, inpL, snr_embed);
cb(inpL, "dspark_draft_embd_snr", -1);
}
if (model.dspark_mode_embedding) {
inpL = ggml_add(ctx0, inpL, model.dspark_mode_embedding);
cb(inpL, "dspark_draft_embd_mode", -1);
}
ggml_tensor * inp_pos = build_inp_pos();
auto * inp_attn = build_attn_inp_kv();
const float kq_scale = 1.0f / sqrtf(float(n_embd_head));
ggml_tensor * cur;
for (int il = 0; il < n_layer; ++il) {
ggml_tensor * inpSA = inpL; // [n_embd, n_draft]
cur = build_norm(inpL, model.layers[il].attn_norm, nullptr, LLM_NORM_RMS, il);
cb(cur, "attn_norm", il);
// concat the static target-context feature (unchanged across layers)
// with this layer's normed draft residual, then project the WHOLE
// thing through this layer's own k_proj/v_proj/q_proj in one shot.
// nn.Linear has no cross-row terms, so k_proj(concat(A,B)) is exactly
// concat(k_proj(A), k_proj(B)) -- this is equivalent to the reference's
// separate-then-concat (k_ctx = k_proj(target); k_noise = k_proj(cur);
// cat) while letting us reuse build_qkv()/build_attn() unmodified.
// (target_ctx is null only in the degenerate n_ctx_rows == 0 case,
// which real decode calls never hit -- see the have_staged_ctx block
// above -- but can occur in llama_context's pre-decode buffer-reserve
// trial graphs.)
ggml_tensor * attn_in = target_ctx ? ggml_concat(ctx0, target_ctx, cur, 1) : cur;
cb(attn_in, "dspark_attn_in", il);
auto qkv = build_qkv(model.layers[il], attn_in, n_embd_head, n_head, n_head_kv, il);
ggml_tensor * Qcur = qkv.q;
ggml_tensor * Kcur = qkv.k;
ggml_tensor * Vcur = qkv.v;
Qcur = build_norm(Qcur, model.layers[il].attn_q_norm, nullptr, LLM_NORM_RMS, il);
cb(Qcur, "Qcur_normed", il);
Kcur = build_norm(Kcur, model.layers[il].attn_k_norm, nullptr, LLM_NORM_RMS, il);
cb(Kcur, "Kcur_normed", il);
Qcur = ggml_rope_ext(ctx0, Qcur, inp_pos, nullptr, n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
ext_factor, attn_factor, beta_fast, beta_slow);
Kcur = ggml_rope_ext(ctx0, Kcur, inp_pos, nullptr, n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
ext_factor, attn_factor, beta_fast, beta_slow);
cb(Qcur, "Qcur", il);
cb(Kcur, "Kcur", il);
cb(Vcur, "Vcur", il);
// real, persistent KV cache (build_attn_inp_kv(), not the no-cache
// path): writes n_ctx_rows + n_draft new rows this call, matching the
// reference's cache.update() growth. cparams.causal_attn must be set
// to false by the caller (llama_set_causal_attn(ctx, false)) so the
// mask built here is fully open (no hybrid causal/bidirectional
// complexity -- same masking style as build_attn_inp_no_cache() with
// causal_attn=false, just backed by a real growing cache instead).
cur = build_attn(inp_attn, model.layers[il].wo, model.layers[il].wo_b, model.layers[il].wo_s, Qcur, Kcur, Vcur,
nullptr, nullptr, nullptr, kq_scale, il);
cb(cur, "dspark_attn_out_full", il);
// discard the leading n_ctx_rows columns: those are attention output
// for "queries" that don't exist in the reference (the context rows
// never issue a query there). we computed them anyway because
// build_attn()'s cache-write/mask machinery is uniformly sized to
// n_tokens; dropping them here is provably harmless since attention
// output is row-independent (each row depends only on its own Q row
// against the shared K/V), so this is bit-identical to never having
// computed them.
cur = ggml_view_2d(ctx0, cur, n_embd, n_draft, cur->nb[1], cur->nb[1] * n_ctx_rows);
cb(cur, "dspark_attn_draft_only", il);
cur = ggml_add(ctx0, cur, inpSA);
cb(cur, "attn_residual", il);
ggml_tensor * ffn_inp = cur;
cur = build_norm(cur, model.layers[il].ffn_norm, nullptr, LLM_NORM_RMS, il);
cb(cur, "ffn_norm", il);
cur = build_ffn(cur, model.layers[il].ffn_up, nullptr, model.layers[il].ffn_up_s, model.layers[il].ffn_gate,
nullptr, model.layers[il].ffn_gate_s, model.layers[il].ffn_down, nullptr,
model.layers[il].ffn_down_s, nullptr, LLM_FFN_SILU, LLM_FFN_PAR, il);
cb(cur, "ffn_out", il);
cur = ggml_add(ctx0, cur, ffn_inp);
cur = build_cvec(cur, il);
cb(cur, "l_out", il);
inpL = cur;
}
cur = inpL;
cb(cur, "h_nextn", -1);
res->t_h_nextn = cur;
cur = build_norm(cur, model.output_norm, nullptr, LLM_NORM_RMS, -1);
cb(cur, "result_norm", -1);
res->t_embd = cur;
if (hparams.dspark_hidden_correction) {
ggml_tensor * trunk = cur;
ggml_tensor * chain = nullptr;
ggml_tensor * previous = nullptr;
ggml_tensor * markov_block = nullptr;
ggml_tensor * mask_markov = nullptr;
const char * assembly_env = std::getenv("LLAMA_DSPARK_BALANCED_OUTPUT");
const bool balanced_output = assembly_env && std::strcmp(assembly_env, "1") == 0;
std::vector<ggml_tensor *> output_rows;
const char * top_k_env = std::getenv("DSPARK_HEAD_TOP_K");
char * top_k_end = nullptr;
const int64_t top_k = top_k_env ? std::strtol(top_k_env, &top_k_end, 10) : 0;
if ((top_k_env && (top_k_end == top_k_env || *top_k_end != '\0')) || top_k < 0 || top_k > model.output->ne[1]) {
throw std::runtime_error("DSPARK_HEAD_TOP_K is outside the vocabulary");
}
if (top_k > 0 && model.hadamard_rotations.count(model.output)) {
throw std::runtime_error("DSpark restricted head does not support folded output weights");
}
if (top_k > 0 && (model.output_s || (loras && !loras->empty()))) {
throw std::runtime_error("DSpark candidate heads do not support output scales or LoRA adapters");
}
if (top_k > 0) {
auto ids = ggml_view_1d(ctx0, res->t_inp_tokens, n_draft, n_ctx_rows * sizeof(int32_t));
auto latent = ggml_get_rows(ctx0, model.dspark_markov_head_a, ids);
markov_block = build_lora_mm(model.dspark_markov_head_b, latent);
cb(markov_block, "dspark_markov_block", -1);
}
ggml_tensor * base_block = nullptr;
ggml_tensor * candidate_block = nullptr;
if (top_k > 0) {
base_block = build_lora_mm(model.output, trunk, model.output_s);
candidate_block = ggml_top_k(ctx0, ggml_add(ctx0, base_block, markov_block), top_k);
cb(candidate_block, "dspark_candidates", -1);
}
int64_t n_correct = n_draft;
if (const char * value = std::getenv("LLAMA_DSPARK_CORRECTION_PREFIX")) {
char * end = nullptr;
const long keep = std::strtol(value, &end, 10);
if (end == value || *end || keep < 1 || keep > hparams.dspark_block_size) {
throw std::runtime_error("Invalid DSpark correction prefix");
}
// Keep the full trunk and batched projections; later correction slots cannot affect this prefix.
n_correct = std::min<int64_t>(n_draft, keep);
if (staged_input) {
staged_input->correction_prefix_rows = n_correct;
}
}
for (int64_t slot = 0; slot < n_correct; ++slot) {
auto ids = ggml_view_1d(ctx0, res->t_inp_tokens, 1, (n_ctx_rows + slot) * sizeof(int32_t));
if (slot % hparams.dspark_block_size == 0) {
previous = ids;
}
auto hidden = ggml_view_2d(ctx0, trunk, n_embd, 1, trunk->nb[1], slot * trunk->nb[1]);
auto embedding = ggml_get_rows(ctx0, model.tok_embd, previous);
auto hn = build_norm(hidden, model.dspark_corr_hnorm, nullptr, LLM_NORM_RMS, -1);
auto en = build_norm(embedding, model.dspark_corr_enorm, nullptr, LLM_NORM_RMS, -1);
auto input = ggml_concat(ctx0, hn, en, 0);
cb(input, "dspark_corr_input", slot);
auto gate = ggml_silu(ctx0, build_lora_mm(model.dspark_corr_gate, input));
auto up = build_lora_mm(model.dspark_corr_up, input);
auto delta = build_lora_mm(model.dspark_corr_down, ggml_mul(ctx0, gate, up));
cb(delta, "dspark_corr_delta", slot);
auto corrected = ggml_add(ctx0, hidden, delta);
ggml_tensor * candidates = nullptr;
ggml_tensor * head = model.output;
if (candidate_block) {
const char * fuse_gather = std::getenv("GGML_METAL_FUSE_GATHER_MV");
if (fuse_gather && std::strcmp(fuse_gather, "1") == 0) {
ggml_build_forward_expand(gf, corrected);
}
candidates = ggml_view_1d(ctx0, candidate_block, top_k, slot * candidate_block->nb[1]);
head = ggml_get_rows(ctx0, model.output, candidates);
}
auto logits = candidate_block ? ggml_mul_mat(ctx0, head, corrected) :
build_lora_mm(model.output, corrected, model.output_s);
cb(logits, "dspark_corr_head", slot);
ggml_tensor * markov;
if (markov_block) {
markov = ggml_view_2d(ctx0, markov_block, markov_block->ne[0], 1, markov_block->nb[1],
slot * markov_block->nb[1]);
} else if (reuse_mask && slot > 1) {
markov = mask_markov;
} else {
auto latent = ggml_get_rows(ctx0, model.dspark_markov_head_a, ids);
cb(latent, "dspark_corr_markov", slot);
markov = build_lora_mm(model.dspark_markov_head_b, latent);
if (reuse_mask && slot == 1) {
mask_markov = markov;
}
}
if (candidates) {
auto selected_markov = ggml_get_rows(ctx0, ggml_reshape_2d(ctx0, markov, 1, markov->ne[0]), candidates);
logits = ggml_add(ctx0, logits, ggml_reshape_2d(ctx0, selected_markov, top_k, 1));
auto base =
ggml_view_2d(ctx0, base_block, base_block->ne[0], 1, base_block->nb[1], slot * base_block->nb[1]);
auto dense = ggml_reshape_2d(ctx0, ggml_scale_bias(ctx0, base, 0.0f, -1e6f), 1, base->ne[0]);
logits = ggml_reshape_2d(
ctx0, ggml_set_rows(ctx0, dense, ggml_reshape_2d(ctx0, logits, 1, top_k), candidates), base->ne[0],
1);
} else {
logits = ggml_add(ctx0, logits, markov);
}
cb(logits, "dspark_corr_unmasked", slot);
const size_t mask_offset = hparams.dspark_mask_token_id * logits->nb[0];
auto mask = ggml_clamp(ctx0, ggml_view_1d(ctx0, logits, 1, mask_offset), -1e6f, -1e6f);
// Keep mask suppression out-of-place. SET with a source view of its
// destination can corrupt the other logits on the Metal backend.
const int64_t mask_id = hparams.dspark_mask_token_id;
ggml_tensor * masked = mask;
if (mask_id > 0) {
masked = ggml_concat(ctx0, ggml_view_1d(ctx0, logits, mask_id, 0), masked, 0);
}
if (mask_id + 1 < logits->ne[0]) {
masked = ggml_concat(
ctx0, masked,
ggml_view_1d(ctx0, logits, logits->ne[0] - mask_id - 1, (mask_id + 1) * logits->nb[0]), 0);
}
logits = masked;
cb(logits, "dspark_corr_masked", slot);
previous = ggml_argmax(ctx0, logits);
res->t_dspark_greedy.push_back(previous);
if (balanced_output) {
output_rows.push_back(logits);
} else {
chain = chain ? ggml_concat(ctx0, chain, logits, 1) : logits;
}
}
// Preserve row order without copying the growing prefix at every slot.
while (output_rows.size() > 1) {
std::vector<ggml_tensor *> next;
for (size_t i = 0; i < output_rows.size(); i += 2) {
next.push_back(i + 1 < output_rows.size() ? ggml_concat(ctx0, output_rows[i], output_rows[i + 1], 1) :
output_rows[i]);
}
output_rows = std::move(next);
}
if (balanced_output) {
chain = output_rows.at(0);
cb(chain, "dspark_balanced_output", -1);
chain = ggml_view_2d(ctx0, chain, chain->ne[0], chain->ne[1], chain->nb[1], 0);
}
cur = chain;
} else {
cur = build_lora_mm(model.output, cur, model.output_s);
}
cb(cur, "result_output", -1);
res->t_logits = cur;
ggml_build_forward_expand(gf, cur);
}

Xet Storage Details

Size:
32.1 kB
·
Xet hash:
8f7c2c5fc088096d1b80858c8c6850889ddd8b5e97cfc0b0fd93be3ca13b2dc1

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.