[Bugfix][MiniCPM-o] Align Daily-Omni offline loading and duplex soft-… (#6095)
Signed-off-by: amy-why-3459 <wuhaiyan17@huawei.com>
This commit is contained in:
1 parent
31384cb39c
commit
7cd826d28c
6 files changed
+327
-97
No files matched your search
@@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Offline Daily-Omni sources: local mirrors must not fall back to the Hub id."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm_omni.benchmarks.data_modules.daily_omni_dataset import (
|
||||
daily_omni_local_qa_json,
|
||||
daily_omni_local_videos_dir,
|
||||
resolve_daily_omni_local_root,
|
||||
)
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu, pytest.mark.benchmark]
|
||||
|
||||
|
||||
def _write_qa_json(root: Path) -> Path:
|
||||
qa = root / "qa.json"
|
||||
qa.write_text(json.dumps([{"Question": "q", "Answer": "A", "video_id": "vid0"}]), encoding="utf-8")
|
||||
return qa
|
||||
|
||||
|
||||
def test_resolve_local_root_returns_none_for_hub_id() -> None:
|
||||
assert resolve_daily_omni_local_root("liarliar/Daily-Omni") is None
|
||||
assert resolve_daily_omni_local_root("") is None
|
||||
assert resolve_daily_omni_local_root(None) is None
|
||||
|
||||
|
||||
def test_plain_local_mirror(tmp_path: Path) -> None:
|
||||
_write_qa_json(tmp_path)
|
||||
(tmp_path / "Videos" / "vid0").mkdir(parents=True)
|
||||
|
||||
root = resolve_daily_omni_local_root(str(tmp_path))
|
||||
assert root == tmp_path.resolve()
|
||||
assert daily_omni_local_qa_json(root) == (tmp_path / "qa.json").resolve()
|
||||
assert daily_omni_local_videos_dir(root) == root / "Videos"
|
||||
|
||||
|
||||
def test_hf_cache_dir_resolves_to_snapshot(tmp_path: Path) -> None:
|
||||
cache_dir = tmp_path / "datasets--liarliar--Daily-Omni"
|
||||
snapshot = cache_dir / "snapshots" / "deadbeef"
|
||||
snapshot.mkdir(parents=True)
|
||||
_write_qa_json(snapshot)
|
||||
(cache_dir / "refs").mkdir()
|
||||
(cache_dir / "refs" / "main").write_text("deadbeef", encoding="utf-8")
|
||||
|
||||
root = resolve_daily_omni_local_root(str(cache_dir))
|
||||
assert root == snapshot.resolve()
|
||||
assert daily_omni_local_qa_json(root) == (snapshot / "qa.json").resolve()
|
||||
|
||||
|
||||
def test_hf_cache_dir_without_refs_picks_newest_snapshot(tmp_path: Path) -> None:
|
||||
cache_dir = tmp_path / "datasets--liarliar--Daily-Omni"
|
||||
older = cache_dir / "snapshots" / "aaa"
|
||||
newer = cache_dir / "snapshots" / "bbb"
|
||||
older.mkdir(parents=True)
|
||||
newer.mkdir(parents=True)
|
||||
os.utime(older, (1, 1))
|
||||
os.utime(newer, (10, 10))
|
||||
|
||||
assert resolve_daily_omni_local_root(str(cache_dir)) == newer.resolve()
|
||||
|
||||
|
||||
def test_videos_tar_is_extracted(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("HF_HOME", str(tmp_path / "hf_home"))
|
||||
root = tmp_path / "mirror"
|
||||
(root / "Videos" / "vid0").mkdir(parents=True)
|
||||
(root / "Videos" / "vid0" / "vid0_video.mp4").write_bytes(b"fake")
|
||||
with tarfile.open(root / "Videos.tar", "w") as tf:
|
||||
tf.add(root / "Videos", arcname="Videos")
|
||||
# Only the tarball is left in the mirror.
|
||||
for child in (root / "Videos").rglob("*"):
|
||||
if child.is_file():
|
||||
child.unlink()
|
||||
(root / "Videos" / "vid0").rmdir()
|
||||
(root / "Videos").rmdir()
|
||||
|
||||
videos_dir = daily_omni_local_videos_dir(root)
|
||||
assert videos_dir is not None
|
||||
assert (videos_dir / "vid0" / "vid0_video.mp4").is_file()
|
||||
|
||||
# Second call reuses the extraction instead of redoing it.
|
||||
assert daily_omni_local_videos_dir(root) == videos_dir
|
||||
|
||||
|
||||
def test_missing_qa_json_reports_none(tmp_path: Path) -> None:
|
||||
root = resolve_daily_omni_local_root(str(tmp_path))
|
||||
assert daily_omni_local_qa_json(root) is None
|
||||
assert daily_omni_local_videos_dir(root) is None
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
The ``minicpm-interleave`` mode is an accuracy-critical protocol: MiniCPM-o only reaches
|
||||
OpenBMB's reported Daily-Omni score when frames and 1s audio segments arrive strictly
|
||||
interleaved, with ``max_slice_nums=1`` / ``use_image_id=False`` and an empty MiniCPM
|
||||
system message (not the Qwen system prompt). These tests pin that contract so a refactor
|
||||
cannot silently regress the score.
|
||||
interleaved, with ``max_slice_nums=1`` / ``use_image_id=False`` and no Qwen system prompt.
|
||||
These tests pin that contract so a refactor cannot silently regress the score.
|
||||
|
||||
vllm stubs are installed by tests/benchmarks/conftest.py before collection.
|
||||
"""
|
||||
@@ -99,22 +98,13 @@ def _stub_extract(monkeypatch, dataset: DailyOmniDataset, counter: list[int]) ->
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("n", "k"), [(10, 4), (100, 64), (1000, 64), (7, 7), (3, 5), (1, 1)])
|
||||
def test_uniform_sample_indices_matches_openbmb_midpoint(n: int, k: int) -> None:
|
||||
"""Pin OpenBMB midpoint-bin sampling (not np.linspace endpoints)."""
|
||||
@pytest.mark.parametrize(("n", "k"), [(10, 4), (100, 64), (7, 7), (3, 5), (1, 1)])
|
||||
def test_uniform_sample_indices_matches_numpy_linspace(n: int, k: int) -> None:
|
||||
got = _uniform_sample_indices(n, k)
|
||||
if n <= k:
|
||||
assert got == list(range(n))
|
||||
else:
|
||||
gap = n / k
|
||||
expected = [int(i * gap + gap / 2) for i in range(k)]
|
||||
assert got == expected
|
||||
# Endpoints differ from linspace for typical Daily-Omni downsample sizes.
|
||||
linspace = [int(i) for i in np.linspace(0, n - 1, k, dtype=int)]
|
||||
if n == 1000 and k == 64:
|
||||
assert got[0] == 7 and got[-1] == 992
|
||||
assert linspace[0] == 0 and linspace[-1] == 999
|
||||
assert got != linspace
|
||||
assert got == [int(i) for i in np.linspace(0, n - 1, k, dtype=int)]
|
||||
|
||||
|
||||
def test_uniform_sample_indices_non_positive_k() -> None:
|
||||
@@ -223,16 +213,14 @@ def test_minicpm_interleave_missing_local_video_returns_none(qa_json, tmp_path)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_minicpm_interleave_keeps_empty_system_message(monkeypatch, qa_json, video_dir) -> None:
|
||||
"""Official MiniCPM omni mode still sends role=system with empty content."""
|
||||
def test_minicpm_interleave_omits_qwen_system_message(monkeypatch, qa_json, video_dir) -> None:
|
||||
ds = _make_dataset(qa_json, video_dir, pack_mode="minicpm-interleave", input_mode="all")
|
||||
_stub_extract(monkeypatch, ds, [])
|
||||
parts, _extra, _position = ds._compose_daily_omni_multimodal(_VIDEO_ID, None)
|
||||
|
||||
messages = ds._build_daily_omni_openai_messages(parts, "q?", {"A": "a"})
|
||||
|
||||
assert [m["role"] for m in messages] == ["system", "user"]
|
||||
assert messages[0]["content"][0]["text"] == ""
|
||||
assert [m["role"] for m in messages] == ["user"]
|
||||
|
||||
|
||||
def test_qwen_pack_mode_keeps_system_message(qa_json, video_dir) -> None:
|
||||
|
||||
Reference in new issue
Block a user