Download pipelines/Tr006_V2/project/scripts/test_preprocess_segmentqa_fixed_frames.py from Gbone3176/interval: direct link, hf CLI and curl.
- Browser
- Download file 7.33 kB
-
https://huggingface.co/Gbone3176/interval/resolve/main/pipelines/Tr006_V2/project/scripts/test_preprocess_segmentqa_fixed_frames.py
- Command line
-
hf download hf://Gbone3176/interval/pipelines/Tr006_V2/project/scripts/test_preprocess_segmentqa_fixed_frames.py
-
curl -L -o test_preprocess_segmentqa_fixed_frames.py https://huggingface.co/Gbone3176/interval/resolve/main/pipelines/Tr006_V2/project/scripts/test_preprocess_segmentqa_fixed_frames.py
7.33 kB
| #!/usr/bin/env python3 | |
| """Unit and CPU smoke checks for fixed-frame SegmentQA preprocessing.""" | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| import av | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(PROJECT_ROOT / "scripts")) | |
| import preprocess_segmentqa_fixed_frames as prep # noqa: E402 | |
| PYTHON = "/cpfs01/projects-SSD/cfff-906dc71fafda_SSD/gbw_21307130160/conda-envs/medrl/bin/python" | |
| DATA_ROOT = "/cpfs01/projects-SSD/cfff-906dc71fafda_SSD/gbw_21307130160/dataset/challenge" | |
| OUT = PROJECT_ROOT / "tmp/segmentqa_fixed80_preprocess_smoke_20260826" | |
| def test_env() -> dict[str, str]: | |
| env = dict(os.environ) | |
| env["PYTHONPATH"] = str(PROJECT_ROOT / "ms-swift") | |
| return env | |
| def video_stats(path: Path) -> dict: | |
| with av.open(str(path)) as container: | |
| stream = container.streams.video[0] | |
| pts = [] | |
| dims = set() | |
| for frame in container.decode(stream): | |
| pts.append(float(frame.pts * frame.time_base)) | |
| dims.add((frame.width, frame.height)) | |
| return {"count": len(pts), "pts": pts, "dims": dims} | |
| def test_time_and_sampling_helpers() -> None: | |
| assert prep.parse_time("01:02:03") == 3723 | |
| assert prep.parse_time(12.5) == 12.5 | |
| targets = prep.target_times(10, 18, 4) | |
| assert targets == [11, 13, 15, 17] | |
| assert prep.metadata_from_pts([10.1234, 10.5678], 420, 224) == { | |
| "fps": 1000, | |
| "frames_indices": [10123, 10568], | |
| "total_num_frames": 10569, | |
| "width": 420, | |
| "height": 224, | |
| "duration": 10.569, | |
| "video_backend": "precomputed_absolute_pts", | |
| } | |
| def test_template_metadata_override_path() -> None: | |
| from swift.template.templates.qwen import _extract_precomputed_absolute_video_metadata as extract_metadata | |
| metadata = prep.metadata_from_pts([1.0, 2.0], 420, 224) | |
| video_inputs = {"video": "clip.mp4", "nframes": 80, "enable_thinking": False, "video_metadata": metadata} | |
| extracted = extract_metadata(video_inputs, 0) | |
| assert extracted == metadata | |
| assert video_inputs == {"video": "clip.mp4", "nframes": 80, "enable_thinking": False} | |
| legacy_inputs = {"video": "clip.mp4", "fps": 1.0, "min_frames": 16, "max_frames": 64} | |
| assert extract_metadata(legacy_inputs, 0) is None | |
| assert legacy_inputs == {"video": "clip.mp4", "fps": 1.0, "min_frames": 16, "max_frames": 64} | |
| def validate_qwen_fetch_video_path(record: dict) -> None: | |
| from qwen_vl_utils import fetch_video | |
| from swift.template.templates.qwen import _extract_precomputed_absolute_video_metadata | |
| from transformers.video_utils import VideoMetadata | |
| video_inputs = {"video": record["videos"][0], **record["chat_template_kwargs"]} | |
| metadata = _extract_precomputed_absolute_video_metadata(video_inputs, 0) | |
| assert metadata is not None | |
| assert "do_sample_frames" not in metadata | |
| VideoMetadata(**metadata) | |
| (video, fetched_metadata), sample_fps = fetch_video( | |
| video_inputs, return_video_sample_fps=True, return_video_metadata=True, image_patch_size=16) | |
| assert video.shape[0] == 80 | |
| assert video.shape[1] == 3 | |
| assert video.shape[-2] % 32 == 0 | |
| assert video.shape[-1] % 32 == 0 | |
| assert fetched_metadata["total_num_frames"] >= 80 | |
| assert sample_fps > 0 | |
| assert video_inputs == {"video": record["videos"][0], "nframes": 80, "enable_thinking": False} | |
| def assert_author_direct_segment_prompt(prompt: str) -> None: | |
| assert "timestamp in the source video" in prompt | |
| assert "<1234.5 seconds> is 00:20:34" in prompt | |
| assert "START OF THE VIDEO, not from the start of this" in prompt | |
| assert ( | |
| "The foreign object classes are exactly: Sponge, Clip, Specimen Bag, Silicone Loop, External Drain, " | |
| "Needle, Gallstone, Specimen, Mesh, Absorbable Hemostatic Agent." | |
| ) in prompt | |
| assert "Reply with the answer and nothing else -- no reasoning, no preamble, no" in prompt | |
| assert "A single short line." in prompt | |
| def test_cpu_smoke_preprocess_train() -> None: | |
| if OUT.exists(): | |
| shutil.rmtree(OUT) | |
| cmd = [ | |
| PYTHON, | |
| "scripts/preprocess_segmentqa_fixed_frames.py", | |
| "--data-root", | |
| DATA_ROOT, | |
| "--output-dir", | |
| str(OUT), | |
| "--splits", | |
| "train", | |
| "--frames", | |
| "80", | |
| "--width", | |
| "420", | |
| "--height", | |
| "224", | |
| "--workers", | |
| "1", | |
| "--limit", | |
| "2", | |
| ] | |
| result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True, text=True, capture_output=True, env=test_env()) | |
| summary = json.loads(result.stdout.strip().splitlines()[-1]) | |
| assert summary["segments"] == 2 | |
| assert summary["success"] == 2 | |
| assert summary["failed"] == 0 | |
| manifest = [json.loads(line) for line in (OUT / "segment_manifest.jsonl").read_text().splitlines()] | |
| assert {item["dataset"] for item in manifest} == set(prep.DATASET_NAMES) | |
| for item in manifest: | |
| stats = video_stats(OUT / item["relpath"]) | |
| assert stats["count"] == 80 | |
| assert stats["dims"] == {(420, 224)} | |
| assert item["verified_frame_count"] == 80 | |
| assert item["width"] == 420 | |
| assert item["height"] == 224 | |
| assert len(item["selected_source_pts"]) == 80 | |
| assert all(item["start_seconds"] <= pts < item["end_seconds"] for pts in item["selected_source_pts"]) | |
| assert item["video_metadata"]["fps"] == 1000 | |
| assert item["video_metadata"]["frames_indices"] == [round(pts * 1000) for pts in item["selected_source_pts"]] | |
| assert item["video_metadata"]["total_num_frames"] == max(item["video_metadata"]["frames_indices"]) + 1 | |
| assert item["video_metadata"]["video_backend"] == "precomputed_absolute_pts" | |
| assert "do_sample_frames" not in item["video_metadata"] | |
| train_rows = [json.loads(line) for line in (OUT / "train.jsonl").read_text().splitlines()] | |
| assert len(train_rows) >= 2 | |
| assert all(row["messages"][0]["role"] == "system" for row in train_rows) | |
| assert_author_direct_segment_prompt(train_rows[0]["messages"][0]["content"]) | |
| assert all(row["messages"][1]["content"].startswith("<video>\n") for row in train_rows) | |
| assert all(row["messages"][2]["role"] == "assistant" and row["messages"][2]["content"] for row in train_rows) | |
| assert all(row["chat_template_kwargs"]["nframes"] == 80 for row in train_rows) | |
| assert all(row["chat_template_kwargs"]["enable_thinking"] is False for row in train_rows) | |
| validate_qwen_fetch_video_path(train_rows[0]) | |
| assert not (OUT / "test_requests.jsonl").exists() | |
| report = json.loads((OUT / "validation_report.json").read_text()) | |
| assert report["status"] == "pass" | |
| assert report["success"] == report["segments"] == 2 | |
| before = {p: p.stat().st_mtime for p in OUT.glob("videos/train/*/*.mp4")} | |
| resume = subprocess.run(cmd + ["--resume"], cwd=PROJECT_ROOT, check=True, text=True, capture_output=True, env=test_env()) | |
| resume_summary = json.loads(resume.stdout.strip().splitlines()[-1]) | |
| assert resume_summary["success"] == 2 | |
| assert before == {p: p.stat().st_mtime for p in OUT.glob("videos/train/*/*.mp4")} | |
| if __name__ == "__main__": | |
| test_time_and_sampling_helpers() | |
| test_template_metadata_override_path() | |
| test_cpu_smoke_preprocess_train() | |