| 11173 | } |
| 11174 | |
| 11175 | static sam3_prop_output sam3_propagate_single( |
| 11176 | sam3_tracker& tracker, sam3_state& state, const sam3_model& model, |
| 11177 | const sam3_masklet& masklet, |
| 11178 | const std::vector<sam3_memory_slot>& mem_bank, |
| 11179 | const std::vector<std::pair<int, struct ggml_tensor*>>& ptr_bank) { |
| 11180 | sam3_prop_output output = {}; |
| 11181 | const auto& hp = model.hparams; |
| 11182 | const int D = hp.neck_dim, MD = hp.mem_out_dim; |
| 11183 | const int H = sam3_eff_feat_size(state, hp); |
| 11184 | const int N = H * H; |
| 11185 | |
| 11186 | auto sel = sam3_select_memory_frames(mem_bank, hp.num_maskmem); |
| 11187 | if (sel.empty()) return output; |
| 11188 | |
| 11189 | // ── Build prompt and prompt_pos via sam3_build_prompt_and_pos ───────── |
| 11190 | // EdgeTAM with perceiver: each slot has 512 tokens (not H*H). |
| 11191 | // Standard SAM2/SAM3: each slot has H*H tokens. |
| 11192 | const bool use_perceiver = hp.has_perceiver != 0; |
| 11193 | const int N_per_slot = use_perceiver ? (hp.perceiver_n_latents_1d + hp.perceiver_n_latents_2d) : N; |
| 11194 | |
| 11195 | int n_sel = (int)sel.size(); |
| 11196 | std::vector<std::vector<float>> slot_feats(n_sel), slot_pes(n_sel); |
| 11197 | std::vector<int> spatial_tpos(n_sel, 1); // default t_pos=1 for non-cond |
| 11198 | for (int s = 0; s < n_sel; ++s) { |
| 11199 | slot_feats[s].resize(MD * N_per_slot); |
| 11200 | ggml_backend_tensor_get(mem_bank[sel[s]].spatial_feats, |
| 11201 | slot_feats[s].data(), 0, MD * N_per_slot * sizeof(float)); |
| 11202 | slot_pes[s].resize(MD * N_per_slot); |
| 11203 | if (mem_bank[sel[s]].spatial_pe) { |
| 11204 | ggml_backend_tensor_get(mem_bank[sel[s]].spatial_pe, |
| 11205 | slot_pes[s].data(), 0, MD * N_per_slot * sizeof(float)); |
| 11206 | } else { |
| 11207 | sam3_ensure_tracker_pe_caches(tracker, hp, H); |
| 11208 | if (use_perceiver) { |
| 11209 | // For perceiver: zeros for 1D tokens, sinusoidal for 2D tokens |
| 11210 | const int N_1d = hp.perceiver_n_latents_1d; |
| 11211 | const int N_2d = hp.perceiver_n_latents_2d; |
| 11212 | memset(slot_pes[s].data(), 0, MD * N_1d * sizeof(float)); |
| 11213 | auto pe_2d = sam3_sinusoidal_pe_2d(16, 16, MD); |
| 11214 | memcpy(slot_pes[s].data() + MD * N_1d, pe_2d.data(), MD * N_2d * sizeof(float)); |
| 11215 | } else { |
| 11216 | slot_pes[s] = tracker.cached_sinpe_64; |
| 11217 | } |
| 11218 | } |
| 11219 | spatial_tpos[s] = mem_bank[sel[s]].is_cond_frame ? 0 : (n_sel - s); |
| 11220 | } |
| 11221 | |
| 11222 | int P = std::min((int)ptr_bank.size(), hp.max_obj_ptrs); |
| 11223 | std::vector<std::vector<float>> obj_ptrs(P); |
| 11224 | std::vector<int> ptr_tpos(P); |
| 11225 | int cur_frame = tracker.frame_index; |
| 11226 | for (int p = 0; p < P; ++p) { |
| 11227 | obj_ptrs[p].resize(D); |
| 11228 | ggml_backend_tensor_get(ptr_bank[p].second, obj_ptrs[p].data(), 0, D * sizeof(float)); |
| 11229 | // Use actual frame distance (matches Python: abs(frame_idx - t)) |
| 11230 | ptr_tpos[p] = std::abs(cur_frame - ptr_bank[p].first); |
| 11231 | if (ptr_tpos[p] < 1) ptr_tpos[p] = 1; // minimum distance of 1 |
| 11232 | } |
no test coverage detected