TwoWayAttentionBlock forward
| 10440 | |
| 10441 | // TwoWayAttentionBlock forward |
| 10442 | static void sam3_twoway_block_forward( |
| 10443 | struct ggml_context* ctx, |
| 10444 | struct ggml_tensor*& queries, // [D, N_q, B] — modified in place |
| 10445 | struct ggml_tensor*& keys, // [D, N_kv, B] — modified in place |
| 10446 | struct ggml_tensor* query_pe, // [D, N_q, B] |
| 10447 | struct ggml_tensor* key_pe, // [D, N_kv, B] |
| 10448 | const sam3_twoway_block& blk, |
| 10449 | int n_heads, |
| 10450 | bool skip_first_layer_pe) { |
| 10451 | // 1. Self-attention on queries |
| 10452 | if (skip_first_layer_pe) { |
| 10453 | // Python: queries = self.self_attn(q=queries, k=queries, v=queries) |
| 10454 | // No residual connection when skipping first layer PE |
| 10455 | queries = sam3_sam_attention(ctx, queries, queries, queries, blk.self_attn, n_heads); |
| 10456 | } else { |
| 10457 | auto* q = ggml_add(ctx, queries, query_pe); |
| 10458 | auto* attn_out = sam3_sam_attention(ctx, q, q, queries, blk.self_attn, n_heads); |
| 10459 | queries = ggml_add(ctx, queries, attn_out); |
| 10460 | } |
| 10461 | queries = sam3_layer_norm(ctx, queries, blk.norm1_w, blk.norm1_b); |
| 10462 | if (skip_first_layer_pe) { |
| 10463 | ggml_set_name(queries, "dbg_twoway_skip_sa_norm"); |
| 10464 | ggml_set_output(queries); |
| 10465 | } |
| 10466 | |
| 10467 | // 2. Cross-attention: tokens attending to image |
| 10468 | { |
| 10469 | auto* q = ggml_add(ctx, queries, query_pe); |
| 10470 | auto* k = ggml_add(ctx, keys, key_pe); |
| 10471 | auto* attn_out = sam3_sam_attention(ctx, q, k, keys, blk.ca_tok2img, n_heads); |
| 10472 | queries = ggml_add(ctx, queries, attn_out); |
| 10473 | queries = sam3_layer_norm(ctx, queries, blk.norm2_w, blk.norm2_b); |
| 10474 | } |
| 10475 | if (skip_first_layer_pe) { |
| 10476 | ggml_set_name(queries, "dbg_twoway_skip_ca_tok2img"); |
| 10477 | ggml_set_output(queries); |
| 10478 | } |
| 10479 | |
| 10480 | // 3. MLP on queries (ReLU activation) |
| 10481 | { |
| 10482 | auto* mlp = ggml_mul_mat(ctx, blk.mlp_fc1_w, queries); |
| 10483 | mlp = ggml_add(ctx, mlp, blk.mlp_fc1_b); |
| 10484 | mlp = ggml_relu(ctx, mlp); |
| 10485 | mlp = ggml_mul_mat(ctx, blk.mlp_fc2_w, mlp); |
| 10486 | mlp = ggml_add(ctx, mlp, blk.mlp_fc2_b); |
| 10487 | queries = ggml_add(ctx, queries, mlp); |
| 10488 | queries = sam3_layer_norm(ctx, queries, blk.norm3_w, blk.norm3_b); |
| 10489 | } |
| 10490 | if (skip_first_layer_pe) { |
| 10491 | ggml_set_name(queries, "dbg_twoway_skip_mlp"); |
| 10492 | ggml_set_output(queries); |
| 10493 | } |
| 10494 | |
| 10495 | // 4. Cross-attention: image attending to tokens |
| 10496 | { |
| 10497 | auto* q = ggml_add(ctx, queries, query_pe); |
| 10498 | auto* k = ggml_add(ctx, keys, key_pe); |
| 10499 | // Note: q and k are swapped — image (k) attends to tokens (q) |
no test coverage detected