| 10546 | }; |
| 10547 | |
| 10548 | static sam3_dec_result sam3_build_sam_dec_graph( |
| 10549 | struct ggml_context* ctx, |
| 10550 | const sam3_model& model, |
| 10551 | struct ggml_tensor* image_feats, // [D, H, H, 1] |
| 10552 | struct ggml_tensor* image_pe, // [D, H, H, 1] |
| 10553 | struct ggml_tensor* sparse_emb, // [D, N_pts, 1] |
| 10554 | struct ggml_tensor* dense_emb, // [D, H, H, 1] |
| 10555 | struct ggml_tensor* feat_s0, // [D, H*4, H*4, 1] high-res |
| 10556 | struct ggml_tensor* feat_s1, // [D, H*2, H*2, 1] mid-res |
| 10557 | int eff_feat_size = 0) |
| 10558 | { |
| 10559 | const auto& dec = model.sam_dec; |
| 10560 | const auto& hp = model.hparams; |
| 10561 | const int D = hp.sam_embed_dim; // 256 |
| 10562 | const int H = (eff_feat_size > 0) ? eff_feat_size : hp.feat_size(); |
| 10563 | const int N_pts = (int)sparse_emb->ne[1]; |
| 10564 | const int n_heads = 8; // SAM uses 8 heads |
| 10565 | const int num_mask_tokens = hp.sam_n_multimask + 1; // 4 |
| 10566 | |
| 10567 | // ── Concatenate output tokens ──────────────────────────────────────── |
| 10568 | // When pred_obj_scores=True: [obj_score(1,D), iou(1,D), masks(4,D)] = 6 tokens |
| 10569 | // When pred_obj_scores=False: [iou(1,D), masks(4,D)] = 5 tokens (older SAM2) |
| 10570 | const bool has_obj_score = (dec.obj_score_token != nullptr); |
| 10571 | const int n_special = (has_obj_score ? 6 : 5); |
| 10572 | |
| 10573 | struct ggml_tensor* output_tokens; |
| 10574 | if (has_obj_score) { |
| 10575 | output_tokens = ggml_concat(ctx, dec.obj_score_token, dec.iou_token, 1); |
| 10576 | } else { |
| 10577 | output_tokens = ggml_reshape_2d(ctx, dec.iou_token, D, 1); |
| 10578 | } |
| 10579 | output_tokens = ggml_concat(ctx, output_tokens, dec.mask_tokens, 1); |
| 10580 | output_tokens = ggml_reshape_3d(ctx, output_tokens, D, n_special, 1); |
| 10581 | auto* tokens = ggml_concat(ctx, output_tokens, sparse_emb, 1); |
| 10582 | ggml_set_name(tokens, "sam_dec_tokens_initial"); |
| 10583 | ggml_set_output(tokens); |
| 10584 | |
| 10585 | const int N_tok = 6 + N_pts; |
| 10586 | |
| 10587 | auto* src = ggml_add(ctx, image_feats, dense_emb); |
| 10588 | src = ggml_reshape_3d(ctx, src, D, H * H, 1); |
| 10589 | auto* pos_src = ggml_reshape_3d(ctx, image_pe, D, H * H, 1); |
| 10590 | |
| 10591 | auto* queries = tokens; |
| 10592 | auto* keys = src; |
| 10593 | auto* query_pe = tokens; // query PE = initial point embedding |
| 10594 | auto* key_pe = pos_src; |
| 10595 | |
| 10596 | for (int i = 0; i < hp.sam_dec_depth; ++i) { |
| 10597 | sam3_twoway_block_forward(ctx, queries, keys, query_pe, key_pe, |
| 10598 | dec.twoway_blocks[i], n_heads, |
| 10599 | /*skip_first_layer_pe=*/(i == 0)); |
| 10600 | sam3_name_tensorf(queries, "sam_dec_block%d_queries", i); |
| 10601 | ggml_set_output(queries); |
| 10602 | sam3_name_tensorf(keys, "sam_dec_block%d_keys", i); |
| 10603 | ggml_set_output(keys); |
| 10604 | } |
| 10605 |
no test coverage detected