Skip to content

Commit 97704a6

Browse files
cchuterclaude
andcommitted
ggml: add DeepSeek V4 hyperconnection + KV ops (CPU)
Adds the five DeepSeek-V4-Flash-specific ggml ops with CPU reference implementations and test-backend-ops coverage: - GGML_OP_DSV4_HC_SPLIT_SINKHORN hyperconnection mix split + Sinkhorn - GGML_OP_DSV4_HC_WEIGHTED_SUM hyperconnection weighted residual sum - GGML_OP_DSV4_HC_EXPAND hyperconnection stream expand - GGML_OP_DSV4_FP8_KV_QUANTIZE e4m3 FP8 KV-cache quantize/dequantize - GGML_OP_DSV4_ROPE_TAIL V4 partial-RoPE tail rotation CPU-only, per the maintainer guidance to land new model ops with a CPU implementation first and add accelerator backends in separate per-backend PRs. No CUDA/Metal code. No model/arch wiring (separate PR). No DeepSeek Sparse Attention / lightning-indexer / flash-attn-top_k changes — V4 does not use those. GGML_OP_COUNT goes 96 -> 101 (5 new ops). The CPU implementations are the numerical reference; test-backend-ops compares backend ops against the CPU backend, so on a CPU-only build the new cases register but are inert (CPU is the reference). They are exercised once a GPU backend implementing them is built (follow-up per-backend PR). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 18d1717 commit 97704a6

6 files changed

Lines changed: 1047 additions & 2 deletions

File tree

ggml/include/ggml.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,11 @@ extern "C" {
567567
GGML_OP_RWKV_WKV7,
568568
GGML_OP_SOLVE_TRI,
569569
GGML_OP_GATED_DELTA_NET,
570+
GGML_OP_DSV4_HC_SPLIT_SINKHORN,
571+
GGML_OP_DSV4_HC_WEIGHTED_SUM,
572+
GGML_OP_DSV4_HC_EXPAND,
573+
GGML_OP_DSV4_FP8_KV_QUANTIZE,
574+
GGML_OP_DSV4_ROPE_TAIL,
570575

571576
GGML_OP_UNARY,
572577

@@ -2550,6 +2555,61 @@ extern "C" {
25502555
struct ggml_tensor * beta,
25512556
struct ggml_tensor * state);
25522557

2558+
// DeepSeek V4 hyperconnection helper.
2559+
// Splits [mix, tokens] into pre/post/comb regions and applies the
2560+
// Sinkhorn normalization used by the reference implementation.
2561+
GGML_API struct ggml_tensor * ggml_dsv4_hc_split_sinkhorn(
2562+
struct ggml_context * ctx,
2563+
struct ggml_tensor * mixes,
2564+
struct ggml_tensor * scale,
2565+
struct ggml_tensor * base,
2566+
int n_hc,
2567+
int sinkhorn_iters,
2568+
float eps);
2569+
2570+
// DeepSeek V4 hyperconnection weighted-sum helper.
2571+
// Computes sum_hc weights[hc, token] * x[embd, hc, token].
2572+
GGML_API struct ggml_tensor * ggml_dsv4_hc_weighted_sum(
2573+
struct ggml_context * ctx,
2574+
struct ggml_tensor * x,
2575+
struct ggml_tensor * weights);
2576+
2577+
// DeepSeek V4 hyperconnection expand helper.
2578+
// Computes post * block_out + comb^T @ residual for each token.
2579+
GGML_API struct ggml_tensor * ggml_dsv4_hc_expand(
2580+
struct ggml_context * ctx,
2581+
struct ggml_tensor * block_out,
2582+
struct ggml_tensor * residual,
2583+
struct ggml_tensor * post,
2584+
struct ggml_tensor * comb);
2585+
2586+
// DeepSeek V4 FP8 KV-cache simulation helper.
2587+
// Quantizes/dequantizes the non-RoPE prefix in E4M3FN blocks and leaves
2588+
// the RoPE tail unchanged, matching the reference inference path.
2589+
GGML_API struct ggml_tensor * ggml_dsv4_fp8_kv_quantize(
2590+
struct ggml_context * ctx,
2591+
struct ggml_tensor * a,
2592+
int n_rot);
2593+
2594+
// DeepSeek V4 partial RoPE helper.
2595+
// Leaves the non-RoPE prefix unchanged and applies RoPE to the tail,
2596+
// matching ggml_concat(prefix, ggml_rope_ext(tail)).
2597+
GGML_API struct ggml_tensor * ggml_dsv4_rope_tail(
2598+
struct ggml_context * ctx,
2599+
struct ggml_tensor * a,
2600+
struct ggml_tensor * pos,
2601+
struct ggml_tensor * freq_factors,
2602+
int n_dims,
2603+
int mode,
2604+
int n_ctx_orig,
2605+
float freq_base,
2606+
float freq_scale,
2607+
float ext_factor,
2608+
float attn_factor,
2609+
float beta_fast,
2610+
float beta_slow,
2611+
bool inverse);
2612+
25532613
// custom operators
25542614

25552615
typedef void (*ggml_custom1_op_t)(struct ggml_tensor * dst , const struct ggml_tensor * a, int ith, int nth, void * userdata);

ggml/src/ggml-cpu/ggml-cpu.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,26 @@ static void ggml_compute_forward(struct ggml_compute_params * params, struct ggm
20472047
{
20482048
ggml_compute_forward_gated_delta_net(params, tensor);
20492049
} break;
2050+
case GGML_OP_DSV4_HC_SPLIT_SINKHORN:
2051+
{
2052+
ggml_compute_forward_dsv4_hc_split_sinkhorn(params, tensor);
2053+
} break;
2054+
case GGML_OP_DSV4_HC_WEIGHTED_SUM:
2055+
{
2056+
ggml_compute_forward_dsv4_hc_weighted_sum(params, tensor);
2057+
} break;
2058+
case GGML_OP_DSV4_HC_EXPAND:
2059+
{
2060+
ggml_compute_forward_dsv4_hc_expand(params, tensor);
2061+
} break;
2062+
case GGML_OP_DSV4_FP8_KV_QUANTIZE:
2063+
{
2064+
ggml_compute_forward_dsv4_fp8_kv_quantize(params, tensor);
2065+
} break;
2066+
case GGML_OP_DSV4_ROPE_TAIL:
2067+
{
2068+
ggml_compute_forward_dsv4_rope_tail(params, tensor);
2069+
} break;
20502070
case GGML_OP_MAP_CUSTOM1:
20512071
{
20522072
ggml_compute_forward_map_custom1(params, tensor);
@@ -2227,6 +2247,11 @@ static int ggml_get_n_tasks(struct ggml_tensor * node, int n_threads) {
22272247
case GGML_OP_COUNT_EQUAL:
22282248
case GGML_OP_SOLVE_TRI:
22292249
case GGML_OP_GATED_DELTA_NET:
2250+
case GGML_OP_DSV4_HC_SPLIT_SINKHORN:
2251+
case GGML_OP_DSV4_HC_WEIGHTED_SUM:
2252+
case GGML_OP_DSV4_HC_EXPAND:
2253+
case GGML_OP_DSV4_FP8_KV_QUANTIZE:
2254+
case GGML_OP_DSV4_ROPE_TAIL:
22302255
{
22312256
n_tasks = n_threads;
22322257
} break;
@@ -2847,6 +2872,7 @@ struct ggml_cplan ggml_graph_plan(
28472872
case GGML_OP_SOFT_MAX:
28482873
case GGML_OP_ROPE:
28492874
case GGML_OP_ROPE_BACK:
2875+
case GGML_OP_DSV4_ROPE_TAIL:
28502876
{
28512877
cur = ggml_type_size(GGML_TYPE_F32) * node->ne[0] * n_tasks;
28522878
} break;

0 commit comments

Comments
 (0)