| 294 | // ═══════════════════════════════════════════════════════════════════════════════ |
| 295 | |
| 296 | static bool test_encode_image(const std::string & model_path, |
| 297 | const std::string & image_path, |
| 298 | const std::string & ref_dir) { |
| 299 | fprintf(stderr, "\n=== Test: Full Image Encoding ===\n"); |
| 300 | |
| 301 | sam3_params params; |
| 302 | params.model_path = model_path; |
| 303 | params.use_gpu = false; // CPU for determinism |
| 304 | params.n_threads = 4; |
| 305 | |
| 306 | auto model = sam3_load_model(params); |
| 307 | if (!model) { |
| 308 | fprintf(stderr, " Failed to load model\n"); |
| 309 | return false; |
| 310 | } |
| 311 | |
| 312 | auto state = sam3_create_state(*model, params); |
| 313 | if (!state) { |
| 314 | fprintf(stderr, " Failed to create state\n"); |
| 315 | return false; |
| 316 | } |
| 317 | |
| 318 | auto img = sam3_load_image(image_path); |
| 319 | if (img.data.empty()) { |
| 320 | fprintf(stderr, " Failed to load image\n"); |
| 321 | return false; |
| 322 | } |
| 323 | |
| 324 | bool ok = sam3_encode_image(*state, *model, img); |
| 325 | if (!ok) { |
| 326 | fprintf(stderr, " sam3_encode_image failed\n"); |
| 327 | return false; |
| 328 | } |
| 329 | |
| 330 | fprintf(stderr, " Image encoding completed\n"); |
| 331 | |
| 332 | int n_fail_enc = 0; |
| 333 | std::string dump_dir = ref_dir + "/cpp_out"; |
| 334 | { |
| 335 | // Create dump dir |
| 336 | std::string cmd = "mkdir -p " + dump_dir; |
| 337 | (void)system(cmd.c_str()); |
| 338 | } |
| 339 | |
| 340 | // Helper to compare intermediate tensors. |
| 341 | // ggml layout [E, W, H], Python ref is [1, H, W, E] (NHWC) |
| 342 | auto compare_nhwc = [&](const std::string & cpp_name, const std::string & ref_name, float tol) { |
| 343 | sam3_dump_state_tensor(*state, cpp_name, dump_dir + "/" + cpp_name); |
| 344 | auto ref_t = load_ref(ref_dir + "/" + ref_name); |
| 345 | auto cpp_t = load_ref(dump_dir + "/" + cpp_name); |
| 346 | if (ref_t.data.empty() || cpp_t.data.empty()) return; |
| 347 | int E = cpp_t.shape[0], nW = cpp_t.shape[1], nH = cpp_t.shape.size() > 2 ? cpp_t.shape[2] : 1; |
| 348 | std::vector<float> transposed(cpp_t.numel()); |
| 349 | for (int e = 0; e < E; ++e) |
| 350 | for (int w = 0; w < nW; ++w) |
| 351 | for (int h = 0; h < nH; ++h) |
| 352 | transposed[h * nW * E + w * E + e] = cpp_t.data[e + w * E + h * E * nW]; |
| 353 | float md = compare_tensors(transposed.data(), ref_t.data.data(), |
no test coverage detected