fix(ceus): 降低长视频内存峰值,快照开跑即写,build 核对 CEUS 运行与交付包
- 内存:prepare_segmentation 改为流式解码,只留分屏和配准的抽样帧,绿框逐帧在两半上找; 分割那一半由 SegmentationInput.target_frames() 到用时再解码,segment_video 边读边写 jpg; MedSAM2 init_state 的读帧换成直接在存放设备上建张量(不改 MedSAM2 源码,结果逐位相同); 传播结果写进预分配数组。帧数最多的一段视频常驻内存峰值 11.2 GiB → 2.3 GiB,分辨率最大的 一段原代码被 OOM 杀掉、现为 4.2 GiB;两段的掩码和全部产物与改前逐字节相同,33 段视频的 第 1–2 步结果与改前一致,29 例配准与 review.csv 一致。 - 快照:ceus_quant 开跑时写 snapshot/(git、ceus.yaml、review.csv、uv.lock、segment.json), 配置和核对表从快照副本读;收尾由新函数 runs.finish_snapshot 只新建 finished.json。 build 与 ceus_align_review 同样改用 finish_snapshot 记结束时间。 - build:summary.json 加 video_sha256;装 CEUS 结果时核对快照里的 delivery_dir、逐例核对 视频 SHA-256 和推注时间,不同就整次停下;新字段做类型检查,不进 tic.json。 来源:主会话任务(问题 1–3 及补充的 delivery_dir 比对)。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,3 +93,36 @@ def test_segment_video_on_synthetic_clip() -> None:
|
||||
assert masks.shape == (frame_count, height, width)
|
||||
assert masks.dtype == np.bool_
|
||||
assert len(medsam2_commit(cfg.medsam2_dir)) == 40
|
||||
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.parametrize("offload_video_to_cpu", [False, True])
|
||||
def test_jpg_loader_matches_medsam2_loader_bitwise(
|
||||
tmp_path: Path, offload_video_to_cpu: bool
|
||||
) -> None:
|
||||
"""换上的读帧函数与 MedSAM2 原来的 `load_video_frames` 交出逐位相同的张量和原始尺寸。"""
|
||||
import torch
|
||||
from sam2.utils.misc import load_video_frames # pyright: ignore[reportUnknownVariableType]
|
||||
|
||||
from cadx.segment._medsam2 import (
|
||||
_load_jpg_frames, # pyright: ignore[reportPrivateUsage]
|
||||
_write_jpgs, # pyright: ignore[reportPrivateUsage]
|
||||
)
|
||||
|
||||
frames, _ = _moving_disc_video(12, 120, 200, radius=18)
|
||||
noise = np.random.default_rng(0).integers(0, 40, size=(12, 120, 200, 3), dtype=np.uint8)
|
||||
_write_jpgs([frame + n for frame, n in zip(frames, noise, strict=True)], tmp_path)
|
||||
kwargs: dict[str, Any] = {
|
||||
"video_path": str(tmp_path),
|
||||
"image_size": 512,
|
||||
"offload_video_to_cpu": offload_video_to_cpu,
|
||||
"async_loading_frames": False,
|
||||
"compute_device": torch.device("cuda"),
|
||||
}
|
||||
expected, expected_h, expected_w = load_video_frames(**kwargs) # pyright: ignore[reportUnknownVariableType]
|
||||
assert isinstance(expected, torch.Tensor) # 不异步读时原函数交出整段张量
|
||||
images, height, width = _load_jpg_frames(**kwargs)
|
||||
assert (height, width) == (expected_h, expected_w) == (120, 200)
|
||||
assert images.device == expected.device
|
||||
assert images.dtype == torch.float32
|
||||
assert torch.equal(images, expected)
|
||||
|
||||
Reference in New Issue
Block a user