| 11508 | } |
| 11509 | |
| 11510 | static bool sam3_encode_memory( |
| 11511 | sam3_tracker& tracker, sam3_state& state, const sam3_model& model, |
| 11512 | int inst_id, const float* mask_logits, int mask_h, int mask_w, |
| 11513 | int frame_idx, bool is_cond, float obj_score) { |
| 11514 | const auto& hp = model.hparams; |
| 11515 | const int D = hp.neck_dim, MD = hp.mem_out_dim; |
| 11516 | const int H = sam3_eff_feat_size(state, hp); |
| 11517 | const int HIGH_RES = sam3_eff_img_size(state, hp); |
| 11518 | const int INTERPOL = H * 16; |
| 11519 | |
| 11520 | // Mask preprocessing: mask_logits → HIGH_RES → sigmoid → scale/bias → INTERPOL |
| 11521 | auto m_hires = sam3_bilinear_interpolate(mask_logits, mask_w, mask_h, HIGH_RES, HIGH_RES); |
| 11522 | const float sig_scale = hp.sigmoid_scale(), sig_bias = hp.sigmoid_bias(); |
| 11523 | for (auto& v : m_hires) { float s = 1.0f / (1.0f + expf(-v)); v = s * sig_scale + sig_bias; } |
| 11524 | auto m_interp = sam3_bilinear_interpolate(m_hires.data(), HIGH_RES, HIGH_RES, INTERPOL, INTERPOL); |
| 11525 | |
| 11526 | const size_t bs = ggml_tensor_overhead() * 16384 + ggml_graph_overhead(); |
| 11527 | struct ggml_init_params gp = {bs, nullptr, true}; |
| 11528 | auto* ctx0 = ggml_init(gp); |
| 11529 | if (!ctx0) return false; |
| 11530 | |
| 11531 | auto* mask_in = ggml_new_tensor_4d(ctx0, GGML_TYPE_F32, INTERPOL, INTERPOL, 1, 1); |
| 11532 | ggml_set_name(mask_in, "mem_mask"); |
| 11533 | ggml_set_input(mask_in); |
| 11534 | |
| 11535 | // Learned mask downsampler: 4 stages conv+LN+GELU + final 1×1 |
| 11536 | // Conv output is in ggml "conv" layout. permute(1,2,0,3) converts to "internal" layout |
| 11537 | // where ne[0]=channel for LN2d. permute(2,0,1,3) converts back to "conv" layout. |
| 11538 | auto* ds = mask_in; |
| 11539 | for (int s = 0; s < 4; ++s) { |
| 11540 | int out_ch = (int)model.mem_enc.ds_conv_w[s]->ne[3]; |
| 11541 | ds = ggml_conv_2d(ctx0, model.mem_enc.ds_conv_w[s], ds, 2, 2, 1, 1, 1, 1); |
| 11542 | ds = ggml_add(ctx0, ds, ggml_reshape_4d(ctx0, model.mem_enc.ds_conv_b[s], 1, 1, out_ch, 1)); |
| 11543 | ds = ggml_cont(ctx0, ggml_permute(ctx0, ds, 1, 2, 0, 3)); // conv→internal (ne[0]=channel) |
| 11544 | ds = sam3_layer_norm_2d(ctx0, ds, model.mem_enc.ds_norm_w[s], model.mem_enc.ds_norm_b[s]); |
| 11545 | ds = ggml_gelu(ctx0, ds); |
| 11546 | ds = ggml_cont(ctx0, ggml_permute(ctx0, ds, 2, 0, 1, 3)); // internal→conv |
| 11547 | } |
| 11548 | ds = ggml_conv_2d(ctx0, model.mem_enc.ds_conv_w[4], ds, 1, 1, 0, 0, 1, 1); |
| 11549 | ds = ggml_add(ctx0, ds, ggml_reshape_4d(ctx0, model.mem_enc.ds_conv_b[4], 1, 1, D, 1)); |
| 11550 | ds = ggml_cont(ctx0, ggml_permute(ctx0, ds, 1, 2, 0, 3)); // conv→internal [D, ...] |
| 11551 | |
| 11552 | // Pixel projection — use fresh input tensor to avoid pulling in the |
| 11553 | // entire ViT+neck recomputation from state.neck_trk[2]'s dependency tree |
| 11554 | auto* pix_in_raw = ggml_new_tensor_4d(ctx0, GGML_TYPE_F32, D, H, H, 1); |
| 11555 | ggml_set_name(pix_in_raw, "mem_pix_feat"); |
| 11556 | ggml_set_input(pix_in_raw); |
| 11557 | auto* pix_in = ggml_cont(ctx0, ggml_permute(ctx0, pix_in_raw, 2, 0, 1, 3)); |
| 11558 | auto* pix = ggml_conv_2d(ctx0, model.mem_enc.pix_proj_w, pix_in, 1, 1, 0, 0, 1, 1); |
| 11559 | pix = ggml_add(ctx0, pix, ggml_reshape_4d(ctx0, model.mem_enc.pix_proj_b, 1, 1, D, 1)); |
| 11560 | pix = ggml_cont(ctx0, ggml_permute(ctx0, pix, 1, 2, 0, 3)); |
| 11561 | |
| 11562 | // Fusion: ADD (not multiply) |
| 11563 | auto* fused = ggml_add(ctx0, pix, ds); |
| 11564 | for (int i = 0; i < 2; ++i) |
| 11565 | fused = sam3_cxblock_forward(ctx0, fused, |
| 11566 | model.mem_enc.fuser_dw_w[i], model.mem_enc.fuser_dw_b[i], |
| 11567 | model.mem_enc.fuser_norm_w[i], model.mem_enc.fuser_norm_b[i], |
no test coverage detected