Single ViT block forward: pre-norm → attn (window or global, with RoPE) → residual → pre-norm → MLP → residual x: [E, W, H, B] in ggml layout (following sam.cpp convention)
| 3712 | // Single ViT block forward: pre-norm → attn (window or global, with RoPE) → residual → pre-norm → MLP → residual |
| 3713 | // x: [E, W, H, B] in ggml layout (following sam.cpp convention) |
| 3714 | static struct ggml_tensor* sam3_vit_block_forward(struct ggml_context* ctx, |
| 3715 | struct ggml_tensor* x, |
| 3716 | const sam3_vit_block& blk, |
| 3717 | const sam3_hparams& hp, |
| 3718 | int block_idx) { |
| 3719 | const int E = hp.vit_embed_dim; // 1024 |
| 3720 | const int NH = hp.vit_num_heads; // 16 |
| 3721 | const int HD = hp.vit_head_dim(); // 64 |
| 3722 | const int WS = hp.vit_window_size; // 24 |
| 3723 | const bool is_global = hp.is_global_attn(block_idx); |
| 3724 | |
| 3725 | auto* shortcut = x; |
| 3726 | |
| 3727 | x = sam3_layer_norm(ctx, x, blk.norm1_w, blk.norm1_b); |
| 3728 | |
| 3729 | const int64_t w0 = x->ne[1]; |
| 3730 | const int64_t h0 = x->ne[2]; |
| 3731 | |
| 3732 | if (!is_global) { |
| 3733 | // Window partition: [E, W, H, B] → [E, WS, WS, B*num_windows] |
| 3734 | x = ggml_win_part(ctx, x, WS); |
| 3735 | } |
| 3736 | |
| 3737 | const int64_t W_cur = x->ne[1]; |
| 3738 | const int64_t H_cur = x->ne[2]; |
| 3739 | const int64_t B_cur = x->ne[3]; |
| 3740 | |
| 3741 | { |
| 3742 | auto* cur = ggml_mul_mat(ctx, blk.qkv_w, x); |
| 3743 | cur = ggml_add(ctx, cur, blk.qkv_b); |
| 3744 | // cur: [3*E, W_cur, H_cur, B_cur] |
| 3745 | |
| 3746 | // [3*E, W*H, B_cur] → [E, 3, W*H, B_cur] → permute → [E, W*H, B_cur, 3] |
| 3747 | cur = ggml_reshape_4d(ctx, cur, E, 3, W_cur * H_cur, B_cur); |
| 3748 | cur = ggml_cont(ctx, ggml_permute(ctx, cur, 0, 3, 1, 2)); |
| 3749 | // cur: [E, W*H, B_cur, 3] (ne[3]=3 separates Q/K/V) |
| 3750 | |
| 3751 | auto* Q = ggml_view_3d(ctx, cur, E, W_cur * H_cur, B_cur, |
| 3752 | cur->nb[1], cur->nb[2], 0); |
| 3753 | auto* K = ggml_view_3d(ctx, cur, E, W_cur * H_cur, B_cur, |
| 3754 | cur->nb[1], cur->nb[2], 1 * cur->nb[3]); |
| 3755 | auto* V = ggml_view_3d(ctx, cur, E, W_cur * H_cur, B_cur, |
| 3756 | cur->nb[1], cur->nb[2], 2 * cur->nb[3]); |
| 3757 | |
| 3758 | Q = ggml_reshape_4d(ctx, Q, HD, NH, W_cur * H_cur, B_cur); |
| 3759 | Q = ggml_cont(ctx, ggml_permute(ctx, Q, 0, 2, 1, 3)); |
| 3760 | Q = ggml_reshape_3d(ctx, Q, HD, W_cur * H_cur, NH * B_cur); |
| 3761 | |
| 3762 | K = ggml_reshape_4d(ctx, K, HD, NH, W_cur * H_cur, B_cur); |
| 3763 | K = ggml_cont(ctx, ggml_permute(ctx, K, 0, 2, 1, 3)); |
| 3764 | K = ggml_reshape_3d(ctx, K, HD, W_cur * H_cur, NH * B_cur); |
| 3765 | |
| 3766 | V = ggml_reshape_4d(ctx, V, HD, NH, W_cur * H_cur, B_cur); |
| 3767 | V = ggml_permute(ctx, V, 0, 2, 1, 3); // [HD, N, NH, B_cur] non-contiguous view; flash_attn uses strides |
| 3768 | |
| 3769 | if (blk.freqs_cis) { |
| 3770 | Q = sam3_apply_rope(ctx, Q, blk.freqs_cis); |
| 3771 | K = sam3_apply_rope(ctx, K, blk.freqs_cis); |
no test coverage detected