Pre-compute geometry encoder input on CPU: box embeddings + CLS token. Reads model weights from GPU, computes embeddings, returns float vector. Layout: [D, N_geo] row-major where N_geo = n_boxes + 1 (CLS last).
| 7801 | // Reads model weights from GPU, computes embeddings, returns float vector. |
| 7802 | // Layout: [D, N_geo] row-major where N_geo = n_boxes + 1 (CLS last). |
| 7803 | static std::vector<float> sam3_precompute_geom_input( |
| 7804 | const sam3_model& model, |
| 7805 | const sam3_pcs_params& params, |
| 7806 | const float* img_feats_data, // [D, W, H] ggml-layout backbone features (nullable if no boxes) |
| 7807 | int W_feat, int H_feat) { |
| 7808 | const auto& ge = model.geom_enc; |
| 7809 | const int D = model.hparams.neck_dim; // 256 |
| 7810 | const int roi_size = 7; |
| 7811 | const int num_pos_feats = D / 2; // 128 |
| 7812 | |
| 7813 | // Collect all exemplar boxes |
| 7814 | struct box_info { |
| 7815 | float cx, cy, w, h; |
| 7816 | int label; |
| 7817 | }; |
| 7818 | std::vector<box_info> boxes; |
| 7819 | for (const auto& b : params.pos_exemplars) { |
| 7820 | // API provides XYXY in original image space — convert to normalized CxCyWH [0,1] |
| 7821 | float cx = (b.x0 + b.x1) * 0.5f; |
| 7822 | float cy = (b.y0 + b.y1) * 0.5f; |
| 7823 | float bw = b.x1 - b.x0; |
| 7824 | float bh = b.y1 - b.y0; |
| 7825 | boxes.push_back({cx, cy, bw, bh, 0}); // label 0 = positive |
| 7826 | } |
| 7827 | for (const auto& b : params.neg_exemplars) { |
| 7828 | float cx = (b.x0 + b.x1) * 0.5f; |
| 7829 | float cy = (b.y0 + b.y1) * 0.5f; |
| 7830 | float bw = b.x1 - b.x0; |
| 7831 | float bh = b.y1 - b.y0; |
| 7832 | boxes.push_back({cx, cy, bw, bh, 1}); // label 1 = negative |
| 7833 | } |
| 7834 | |
| 7835 | const int n_boxes = (int)boxes.size(); |
| 7836 | const int N_geo = n_boxes + 1; |
| 7837 | |
| 7838 | // Read needed weights from GPU |
| 7839 | std::vector<float> box_proj_w_data(4 * D), box_proj_b_data(D); |
| 7840 | std::vector<float> type_embed_data(D * 2); |
| 7841 | std::vector<float> cls_data(D); |
| 7842 | std::vector<float> box_pos_proj_w_data(258 * D), box_pos_proj_b_data(D); |
| 7843 | std::vector<float> box_pool_proj_w_data(7 * 7 * D * D), box_pool_proj_b_data(D); |
| 7844 | std::vector<float> img_pre_norm_w_data(D), img_pre_norm_b_data(D); |
| 7845 | |
| 7846 | auto read_f32 = [](struct ggml_tensor* t, float* dst, size_t n) { |
| 7847 | sam3_read_f32(t, dst, n); |
| 7848 | }; |
| 7849 | |
| 7850 | read_f32(ge.box_proj_w, box_proj_w_data.data(), 4 * D); |
| 7851 | read_f32(ge.box_proj_b, box_proj_b_data.data(), D); |
| 7852 | read_f32(ge.type_embed, type_embed_data.data(), D * 2); |
| 7853 | read_f32(ge.cls_token, cls_data.data(), D); |
| 7854 | read_f32(ge.box_pos_proj_w, box_pos_proj_w_data.data(), 258 * D); |
| 7855 | read_f32(ge.box_pos_proj_b, box_pos_proj_b_data.data(), D); |
| 7856 | |
| 7857 | if (n_boxes > 0) { |
| 7858 | read_f32(ge.box_pool_proj_w, box_pool_proj_w_data.data(), 7 * 7 * D * D); |
| 7859 | read_f32(ge.box_pool_proj_b, box_pool_proj_b_data.data(), D); |
| 7860 | read_f32(ge.img_pre_norm_w, img_pre_norm_w_data.data(), D); |
no test coverage detected