Single fusion encoder layer. x: [D, N, B] image features (N=5184), prompt: [D, T, B] text/exemplar tokens, pos: [D, N, B] Returns: updated x [D, N, B]
| 8031 | // x: [D, N, B] image features (N=5184), prompt: [D, T, B] text/exemplar tokens, pos: [D, N, B] |
| 8032 | // Returns: updated x [D, N, B] |
| 8033 | static struct ggml_tensor* sam3_fenc_layer_forward( |
| 8034 | struct ggml_context* ctx, |
| 8035 | const sam3_fenc_layer& ly, |
| 8036 | struct ggml_tensor* x, |
| 8037 | struct ggml_tensor* prompt, |
| 8038 | struct ggml_tensor* pos, |
| 8039 | struct ggml_tensor* prompt_attn_bias, |
| 8040 | int n_heads) { |
| 8041 | // Self-attention: Q/K get positional encoding, V does not |
| 8042 | { |
| 8043 | auto* shortcut = x; |
| 8044 | auto* x_norm = sam3_layer_norm(ctx, x, ly.norm1_w, ly.norm1_b); |
| 8045 | auto* q_in = ggml_add(ctx, x_norm, pos); |
| 8046 | auto* k_in = ggml_add(ctx, x_norm, pos); |
| 8047 | |
| 8048 | const int64_t D = x->ne[0]; |
| 8049 | |
| 8050 | auto* q_w = ggml_view_2d(ctx, ly.sa_in_proj_w, D, D, ly.sa_in_proj_w->nb[1], 0); |
| 8051 | auto* k_w = ggml_view_2d(ctx, ly.sa_in_proj_w, D, D, ly.sa_in_proj_w->nb[1], D * ly.sa_in_proj_w->nb[1]); |
| 8052 | auto* v_w = ggml_view_2d(ctx, ly.sa_in_proj_w, D, D, ly.sa_in_proj_w->nb[1], 2 * D * ly.sa_in_proj_w->nb[1]); |
| 8053 | |
| 8054 | auto* q_b = ggml_view_1d(ctx, ly.sa_in_proj_b, D, 0); |
| 8055 | auto* k_b = ggml_view_1d(ctx, ly.sa_in_proj_b, D, D * sizeof(float)); |
| 8056 | auto* v_b = ggml_view_1d(ctx, ly.sa_in_proj_b, D, 2 * D * sizeof(float)); |
| 8057 | |
| 8058 | auto* Q = ggml_add(ctx, ggml_mul_mat(ctx, q_w, q_in), q_b); |
| 8059 | auto* K = ggml_add(ctx, ggml_mul_mat(ctx, k_w, k_in), k_b); |
| 8060 | auto* V = ggml_add(ctx, ggml_mul_mat(ctx, v_w, x_norm), v_b); |
| 8061 | |
| 8062 | const int64_t N = x->ne[1]; |
| 8063 | const int64_t B = x->ne[2]; |
| 8064 | const int64_t HD = D / n_heads; |
| 8065 | |
| 8066 | Q = ggml_reshape_4d(ctx, Q, HD, n_heads, N, B); |
| 8067 | Q = ggml_cont(ctx, ggml_permute(ctx, Q, 0, 2, 1, 3)); |
| 8068 | K = ggml_reshape_4d(ctx, K, HD, n_heads, N, B); |
| 8069 | K = ggml_cont(ctx, ggml_permute(ctx, K, 0, 2, 1, 3)); |
| 8070 | V = ggml_reshape_4d(ctx, V, HD, n_heads, N, B); |
| 8071 | V = ggml_permute(ctx, V, 0, 2, 1, 3); |
| 8072 | |
| 8073 | float scale = 1.0f / sqrtf((float)HD); |
| 8074 | auto* sa_out = ggml_flash_attn_ext(ctx, Q, K, V, nullptr, scale, 0.0f, 0.0f); |
| 8075 | sa_out = ggml_reshape_3d(ctx, sa_out, D, N, B); |
| 8076 | |
| 8077 | sa_out = ggml_mul_mat(ctx, ly.sa_out_proj_w, sa_out); |
| 8078 | sa_out = ggml_add(ctx, sa_out, ly.sa_out_proj_b); |
| 8079 | |
| 8080 | x = ggml_add(ctx, shortcut, sa_out); |
| 8081 | } |
| 8082 | |
| 8083 | // Cross-attention: Q from image features, K/V from prompt tokens. |
| 8084 | // ca_q_w stores fused [D, 3*D] weights split as Q-proj, K-proj, V-proj. |
| 8085 | { |
| 8086 | auto* shortcut = x; |
| 8087 | auto* x_norm = sam3_layer_norm(ctx, x, ly.norm2_w, ly.norm2_b); |
| 8088 | const int64_t D = x->ne[0]; |
| 8089 | |
| 8090 | auto* q_w = ggml_view_2d(ctx, ly.ca_q_w, D, D, ly.ca_q_w->nb[1], 0); |
no test coverage detected