ViSS-8B / code /scripts /run_recent4_single_benchmark.sh
mis2's picture
Release ViSS-8B weights, processors and source code
78ac017 verified
Raw History Blame Contribute Delete
15.9 kB
#!/usr/bin/env bash
set -euo pipefail
# Run one half of the locked recent4_full_v1 evaluation. Two independent
# invocations may therefore evaluate StreamingBench and OVO concurrently on
# disjoint GPU sets while retaining the exact common runner and official
# scorers used by the serial baseline launcher.
if [[ $# -ne 8 ]]; then
echo "usage: $0 REPO MODEL MODEL_MANIFEST OUTPUT PYTHON BENCHMARK GPU_CSV MODEL_ID" >&2
exit 2
fi
REPO=$1
MODEL=$2
MODEL_MANIFEST=$3
OUTPUT=$4
PYTHON=$5
BENCHMARK=$6
GPU_CSV=$7
MODEL_ID=$8
PROCESSOR=${STREAMEVA_PROCESSOR:-$MODEL}
EVAL_BATCH_SIZE=${STREAMEVA_EVAL_BATCH_SIZE:-16}
DECODE_PREFETCH_BATCHES=${STREAMEVA_DECODE_PREFETCH_BATCHES:-2}
FLUSH_EVERY_BATCHES=${STREAMEVA_EVAL_FLUSH_EVERY_BATCHES:-16}
RECORD_CHOICE_CONFIDENCE=${STREAMEVA_RECORD_CHOICE_CONFIDENCE:-1}
FRAME_POLICY=${STREAMEVA_FRAME_POLICY:-recent4}
VISUAL_INPUT_MODE=${STREAMEVA_VISUAL_INPUT_MODE:-image-list}
ALLOW_SHARED_GPU=${STREAMEVA_ALLOW_SHARED_GPU:-0}
MIN_FREE_MIB=${STREAMEVA_MIN_FREE_MIB:-35840}
PROTOCOL=$REPO/configs/evaluation/recent4_full_v1.json
RUNNER=${STREAMEVA_EVALUATOR_ENTRYPOINT:-$REPO/experiments/evaluate_qwen3vl_recent4_full.py}
MODEL_IDENTITY_SHA256=${STREAMEVA_MODEL_IDENTITY_SHA256:-}
# Keep non-login tmux jobs aligned with the CUDA wheel runtime used by
# training. In particular, libcusparse from the wheel requires the matching
# bundled nvJitLink library to precede system CUDA libraries.
PYTHON_SITE=$($PYTHON -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')
NVIDIA_LIB_DIRS=$(find "$PYTHON_SITE/nvidia" -mindepth 2 -maxdepth 2 \
-type d -name lib -print 2>/dev/null | LC_ALL=C sort | paste -sd: -)
if [[ -n $NVIDIA_LIB_DIRS ]]; then
export LD_LIBRARY_PATH="$NVIDIA_LIB_DIRS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
fi
[[ $EVAL_BATCH_SIZE =~ ^[1-9][0-9]*$ ]]
[[ $DECODE_PREFETCH_BATCHES =~ ^[0-9]+$ ]]
[[ $FLUSH_EVERY_BATCHES =~ ^[1-9][0-9]*$ ]]
[[ $RECORD_CHOICE_CONFIDENCE =~ ^[01]$ ]]
[[ $FRAME_POLICY =~ ^(recent4|wide8|wide12|wide16|prefix8|prefix16|prefix32|prefix64|causalbudget20)$ ]]
[[ $VISUAL_INPUT_MODE =~ ^(image-list|native-video|hybrid-history-video-recent-images)$ ]]
[[ $ALLOW_SHARED_GPU =~ ^[01]$ ]]
[[ $MIN_FREE_MIB =~ ^[1-9][0-9]*$ ]]
case "$BENCHMARK" in
streamingbench)
ANNOTATION=${STREAM_ANNOTATION:?Set STREAM_ANNOTATION to the StreamingBench annotation file}
SAMPLES=${STREAM_SAMPLES:?Set STREAM_SAMPLES to the frozen StreamingBench query export}
VIDEO_ROOT=${STREAM_VIDEO_ROOT:?Set STREAM_VIDEO_ROOT to authorized benchmark media}
OFFICIAL_ROOT=${STREAM_OFFICIAL_ROOT:?Set STREAM_OFFICIAL_ROOT to the official scorer}
EXPECTED=2495
SMOKE_UIDS=(streaming_0_0 streaming_8_0 streaming_61_4)
;;
ovo)
OVO_ROOT=${OVO_ROOT:?Set OVO_ROOT to authorized OVO runtime assets}
ANNOTATION=${OVO_ANNOTATION:-$OVO_ROOT/data/ovo_bench_new.json}
OVO_RUNTIME_REPORT=${OVO_RUNTIME_REPORT:-$OVO_ROOT/data/runtime_assets.json}
SAMPLES=${OVO_SAMPLES:?Set OVO_SAMPLES to the frozen OVO query export}
VIDEO_ROOT=${OVO_VIDEO_ROOT:-$OVO_ROOT}
OFFICIAL_ROOT=${OVO_OFFICIAL_ROOT:-$OVO_ROOT}
EXPECTED=3035
SMOKE_UIDS=(ovo_0 ovo_1117 ovo_1468_0 ovo_1516_0 ovo_1558_0)
;;
*) echo "BENCHMARK must be streamingbench or ovo" >&2; exit 2 ;;
esac
IFS=, read -r -a GPUS <<<"$GPU_CSV"
[[ ${#GPUS[@]} -gt 0 ]] || exit 2
declare -A SEEN=()
for gpu in "${GPUS[@]}"; do
[[ $gpu =~ ^[0-7]$ || $gpu =~ ^GPU-[0-9A-Fa-f-]{36}$ ]] || {
echo "GPU_CSV must contain local indices or GPU UUIDs" >&2
exit 2
}
if [[ -n ${SEEN[$gpu]:-} && $ALLOW_SHARED_GPU -eq 0 ]]; then
echo "GPU_CSV may repeat an index only with STREAMEVA_ALLOW_SHARED_GPU=1" >&2
exit 2
fi
SEEN[$gpu]=1
done
[[ $MODEL_ID =~ ^[A-Za-z0-9._-]+$ ]] || exit 2
for path in "$MODEL/config.json" \
"$PROCESSOR/preprocessor_config.json" "$PROTOCOL" "$RUNNER" \
"$ANNOTATION" "$SAMPLES" "$VIDEO_ROOT" "$OFFICIAL_ROOT"; do
test -e "$path"
done
if [[ $MODEL_MANIFEST == none ]]; then
[[ $MODEL_IDENTITY_SHA256 =~ ^[0-9a-f]{64}$ ]] || {
echo "manifest-free evaluation requires STREAMEVA_MODEL_IDENTITY_SHA256" >&2
exit 2
}
MODEL_IDENTITY_ARGS=(--model-identity-sha256 "$MODEL_IDENTITY_SHA256")
else
test -s "$MODEL_MANIFEST"
MODEL_IDENTITY_ARGS=(--model-manifest "$MODEL_MANIFEST")
fi
if [[ $BENCHMARK == ovo ]]; then
test -s "$OVO_RUNTIME_REPORT"
ANNOTATION_SHA256=$(sha256sum "$ANNOTATION" | cut -d' ' -f1)
FROZEN_EXPORT_SHA256=$(sha256sum "$SAMPLES" | cut -d' ' -f1)
jq -e --arg annotation_sha256 "$ANNOTATION_SHA256" \
--arg frozen_export_sha256 "$FROZEN_EXPORT_SHA256" '
.status == "pass"
and .expanded_queries == 3035
and .covered_queries == 3035
and .coverage == 1
and .missing_videos == 0
and .annotation_sha256 == $annotation_sha256
and .frozen_export_sha256 == $frozen_export_sha256
' "$OVO_RUNTIME_REPORT" >/dev/null
fi
test -x "$PYTHON"
export PYTHONPATH=$REPO${PYTHONPATH:+:$PYTHONPATH}
if [[ ${PREFLIGHT_ONLY:-0} == 1 ]]; then
"$PYTHON" -c 'import PIL, qwen_vl_utils, torch, transformers'
printf '{"status":"cpu_preflight_pass","benchmark":"%s","protocol":"recent4_full_v1","batch_size":%s,"decode_prefetch_batches":%s}\n' \
"$BENCHMARK" "$EVAL_BATCH_SIZE" "$DECODE_PREFETCH_BATCHES"
exit 0
fi
mkdir -p "$OUTPUT/logs" "$OUTPUT/$BENCHMARK"
if [[ -e $OUTPUT/$BENCHMARK/complete ]]; then
echo "$BENCHMARK is already complete"
exit 0
fi
if [[ $MODEL_MANIFEST == none ]]; then
:
elif [[ -n ${PREVERIFIED_MODEL_MANIFEST_SHA256:-} ]]; then
[[ $PREVERIFIED_MODEL_MANIFEST_SHA256 =~ ^[0-9a-f]{64}$ ]] || exit 2
[[ $(sha256sum "$MODEL_MANIFEST" | cut -d' ' -f1) == \
"$PREVERIFIED_MODEL_MANIFEST_SHA256" ]] || {
echo "preverified model manifest hash mismatch" >&2
exit 3
}
else
(cd "$MODEL" && sha256sum --quiet -c SHA256SUMS)
fi
if [[ $MODEL_MANIFEST != none ]]; then
MODEL_IDENTITY_SHA256=$(sha256sum "$MODEL_MANIFEST" | cut -d' ' -f1)
fi
"$PYTHON" "$REPO/scripts/validate_evaluation_protocol.py" --protocol "$PROTOCOL" \
>"$OUTPUT/$BENCHMARK/protocol_validation.json"
wait_gpu_free() {
local gpu=$1 pids used free
while true; do
pids=$(nvidia-smi -i "$gpu" --query-compute-apps=pid \
--format=csv,noheader,nounits 2>/dev/null | tr -d '[:space:]')
used=$(nvidia-smi -i "$gpu" --query-gpu=memory.used \
--format=csv,noheader,nounits 2>/dev/null | tr -d '[:space:]')
free=$(nvidia-smi -i "$gpu" --query-gpu=memory.free \
--format=csv,noheader,nounits 2>/dev/null | tr -d '[:space:]')
if [[ $ALLOW_SHARED_GPU -eq 0 ]]; then
if [[ -z $pids && ${used:-999999} -le 16 ]]; then return 0; fi
elif [[ ${free:-0} -ge $MIN_FREE_MIB ]]; then
return 0
fi
echo "$(date -u +%FT%TZ) waiting for GPU $gpu (used=${used:-unknown} MiB free=${free:-unknown} MiB shared=$ALLOW_SHARED_GPU minimum_free=$MIN_FREE_MIB MiB)"
sleep 20
done
}
validate_result() {
"$PYTHON" - "$1" "$2" "$FRAME_POLICY" "$VISUAL_INPUT_MODE" "$RECORD_CHOICE_CONFIDENCE" <<'PY'
import json, sys
x = json.load(open(sys.argv[1], encoding="utf-8"))
assert x["evaluation_protocol"] == "recent4_full_v1"
assert x["num_samples"] == int(sys.argv[2])
assert x["num_errors"] == 0
assert all(str(row.get("prediction") or "").strip() for row in x["rows"])
requested_policy = sys.argv[3]
visual_input_mode = sys.argv[4]
record_choice_confidence = bool(int(sys.argv[5]))
assert x["processor_geometry"]["visual_input_mode"] == visual_input_mode
assert x["comparable_under_locked_recent4_protocol"] == (
requested_policy == "recent4" and visual_input_mode == "image-list"
)
for row in x["rows"]:
sampling = row["sampling"]
if requested_policy == "prefix8":
assert sampling["num_sampled_frames"] == 8
elif requested_policy == "prefix16":
assert sampling["num_sampled_frames"] == 16
elif requested_policy == "prefix32":
assert sampling["num_sampled_frames"] == 32
elif requested_policy == "prefix64":
assert sampling["num_sampled_frames"] == 64
elif requested_policy == "causalbudget20":
assert 1 <= sampling["num_sampled_frames"] <= 20
assert sampling["controller"]["benchmark_task_or_group_router"] is False
assert sampling["controller"]["future_frame_violations"] == 0
else:
assert sampling["num_sampled_frames"] == 4
assert max(sampling["frame_timestamps"]) <= row["query_time"] + 1e-3
assert row["visual_input_mode"] == visual_input_mode
assert bool(row.get("generation_confidence")) == record_choice_confidence
assert bool(row["video_grid_thw"]) == (
visual_input_mode in {"native-video", "hybrid-history-video-recent-images"}
and bool(row.get("native_video_metadata"))
)
PY
}
CONFIDENCE_ARGS=()
if [[ $RECORD_CHOICE_CONFIDENCE -eq 1 ]]; then
CONFIDENCE_ARGS+=(--record-choice-confidence)
fi
SMOKE_OUTPUT=$OUTPUT/$BENCHMARK/smoke.json
if ! test -s "$SMOKE_OUTPUT" \
|| ! validate_result "$SMOKE_OUTPUT" "${#SMOKE_UIDS[@]}"; then
wait_gpu_free "${GPUS[0]}"
smoke_batch=$EVAL_BATCH_SIZE
smoke_rc=1
for smoke_attempt in 1 2 3; do
smoke_rc=0
CUDA_VISIBLE_DEVICES=${GPUS[0]} PYTHONPATH=$REPO PYTHONUNBUFFERED=1 \
TOKENIZERS_PARALLELISM=false OMP_NUM_THREADS=1 \
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
"$PYTHON" "$RUNNER" --benchmark "$BENCHMARK" \
--annotation "$ANNOTATION" --samples "$SAMPLES" \
--video-root "$VIDEO_ROOT" --model "$MODEL" --processor "$PROCESSOR" \
"${MODEL_IDENTITY_ARGS[@]}" --protocol "$PROTOCOL" \
--output "$SMOKE_OUTPUT" --uids "${SMOKE_UIDS[@]}" \
--frame-policy "$FRAME_POLICY" \
--visual-input-mode "$VISUAL_INPUT_MODE" \
--batch-size "$smoke_batch" \
--decode-prefetch-batches "$DECODE_PREFETCH_BATCHES" \
--flush-every-batches "$FLUSH_EVERY_BATCHES" \
"${CONFIDENCE_ARGS[@]}" \
--resume --retry-errors >>"$OUTPUT/logs/${BENCHMARK}_smoke.log" 2>&1 || smoke_rc=$?
if validate_result "$SMOKE_OUTPUT" "${#SMOKE_UIDS[@]}"; then break; fi
echo "warning: $BENCHMARK smoke attempt=$smoke_attempt batch=$smoke_batch failed rc=$smoke_rc" >&2
if (( smoke_batch > 1 )); then smoke_batch=$(( (smoke_batch + 1) / 2 )); fi
done
if validate_result "$SMOKE_OUTPUT" "${#SMOKE_UIDS[@]}"; then
if [[ $smoke_rc -ne 0 ]]; then
echo "warning: $BENCHMARK smoke exited rc=$smoke_rc after writing a complete validated result" >&2
fi
else
echo "$BENCHMARK smoke failed validation after runner rc=$smoke_rc" >&2
if [[ $smoke_rc -eq 0 ]]; then smoke_rc=1; fi
exit "$smoke_rc"
fi
fi
SHARD_UID_ROOT=$OUTPUT/$BENCHMARK/shard_uids
mkdir -p "$SHARD_UID_ROOT"
"$PYTHON" - "$SAMPLES" "$SHARD_UID_ROOT" "${#GPUS[@]}" <<'PY'
import json, sys
from pathlib import Path
source, output, count = Path(sys.argv[1]), Path(sys.argv[2]), int(sys.argv[3])
uids = [str(json.loads(line)["uid"]) for line in source.read_text().splitlines() if line]
assert len(uids) == len(set(uids))
for index in range(count):
shard = uids[index::count]
(output / f"shard{index}.uids").write_text("\n".join(shard) + "\n")
assert sum(1 for path in output.glob("shard*.uids") for line in path.read_text().splitlines() if line) == len(uids)
PY
run_shard() {
local index=$1 gpu=$2 uid_file=$3 expected=$4 output log attempt runner_rc attempt_batch
output=$OUTPUT/$BENCHMARK/shard${index}.json
log=$OUTPUT/logs/${BENCHMARK}_shard${index}.log
wait_gpu_free "$gpu"
attempt_batch=$EVAL_BATCH_SIZE
for attempt in 1 2 3; do
runner_rc=0
CUDA_VISIBLE_DEVICES=$gpu PYTHONPATH=$REPO PYTHONUNBUFFERED=1 \
TOKENIZERS_PARALLELISM=false OMP_NUM_THREADS=1 \
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
"$PYTHON" "$RUNNER" --benchmark "$BENCHMARK" \
--annotation "$ANNOTATION" --samples "$SAMPLES" \
--video-root "$VIDEO_ROOT" --model "$MODEL" --processor "$PROCESSOR" \
"${MODEL_IDENTITY_ARGS[@]}" --protocol "$PROTOCOL" \
--output "$output" --uids-file "$uid_file" \
--frame-policy "$FRAME_POLICY" \
--visual-input-mode "$VISUAL_INPUT_MODE" \
--batch-size "$attempt_batch" \
--decode-prefetch-batches "$DECODE_PREFETCH_BATCHES" \
--flush-every-batches "$FLUSH_EVERY_BATCHES" \
"${CONFIDENCE_ARGS[@]}" \
--resume --retry-errors >>"$log" 2>&1 || runner_rc=$?
if validate_result "$output" "$expected"; then
if [[ $runner_rc -ne 0 ]]; then
echo "warning: $BENCHMARK shard$index exited rc=$runner_rc after writing a complete validated result" >&2
fi
return 0
fi
echo "warning: $BENCHMARK shard$index attempt=$attempt batch=$attempt_batch failed validation after runner rc=$runner_rc" >&2
if (( attempt_batch > 1 )); then attempt_batch=$(( (attempt_batch + 1) / 2 )); fi
done
return 1
}
pids=()
shards=()
for index in "${!GPUS[@]}"; do
uid_file=$SHARD_UID_ROOT/shard${index}.uids
expected=$(awk 'NF {count++} END {print count+0}' "$uid_file")
shards+=("$OUTPUT/$BENCHMARK/shard${index}.json")
run_shard "$index" "${GPUS[$index]}" "$uid_file" "$expected" &
pids+=("$!")
done
failed=0
for index in "${!pids[@]}"; do
pid=${pids[$index]}
if wait "$pid"; then
echo "$(date -u +%FT%TZ) $BENCHMARK shard$index exited rc=0"
else
rc=$?
echo "$(date -u +%FT%TZ) $BENCHMARK shard$index exited rc=$rc" >&2
failed=1
fi
done
[[ $failed -eq 0 ]]
"$PYTHON" "$REPO/scripts/merge_eval_shards.py" --inputs "${shards[@]}" \
--output "$OUTPUT/$BENCHMARK/full.json" --expected-count "$EXPECTED" \
--expected-uids "$SAMPLES"
validate_result "$OUTPUT/$BENCHMARK/full.json" "$EXPECTED"
"$PYTHON" "$REPO/scripts/score_official_benchmark_predictions.py" \
--benchmark "$BENCHMARK" --official-root "$OFFICIAL_ROOT" \
--annotation "$ANNOTATION" --predictions "$OUTPUT/$BENCHMARK/full.json" \
--output-json "$OUTPUT/$BENCHMARK/official_score.json" \
--official-input-json "$OUTPUT/$BENCHMARK/official_input.json" \
>"$OUTPUT/logs/${BENCHMARK}_official_score.log" 2>&1
RUNTIME_REPORT_ARG=${OVO_RUNTIME_REPORT:-}
"$PYTHON" - "$OUTPUT/$BENCHMARK" "$MODEL_IDENTITY_SHA256" "$PROTOCOL" \
"$MODEL_ID" "$BENCHMARK" "$PROCESSOR" "$RUNTIME_REPORT_ARG" <<'PY'
import hashlib, json, sys
from datetime import datetime, timezone
from pathlib import Path
out, model_identity, protocol = Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3])
model_id, benchmark, processor = sys.argv[4:7]
processor = Path(processor)
runtime_report = Path(sys.argv[7]) if sys.argv[7] else None
score = json.loads((out / "official_score.json").read_text())
full = json.loads((out / "full.json").read_text())
sha = lambda p: hashlib.sha256(Path(p).read_bytes()).hexdigest()
summary = {
"format": "iclr_video.single_benchmark.v2",
"benchmark": benchmark,
"model_id": model_id,
"protocol_id": "recent4_full_v1",
"inference_policy": full["inference_policy"],
"inference_policy_hash": full["inference_policy_hash"],
"policy_config": full["policy_config"],
"comparable_under_locked_recent4_protocol": full.get(
"comparable_under_locked_recent4_protocol"
),
"model_identity_sha256": model_identity,
"processor_path": str(processor),
"processor_config_sha256": sha(processor / "preprocessor_config.json"),
"processor_manifest_sha256": (
sha(processor / "SHA256SUMS")
if (processor / "SHA256SUMS").is_file()
else None
),
"protocol_sha256": sha(protocol),
"benchmark_runtime_assets_sha256": (
sha(runtime_report) if runtime_report is not None else None
),
"completed_at": datetime.now(timezone.utc).isoformat(),
"official_score": score,
}
(out / "summary.json").write_text(json.dumps(summary, indent=2, sort_keys=True) + "\n")
PY
touch "$OUTPUT/$BENCHMARK/complete"
echo "$(date -u +%FT%TZ) completed $BENCHMARK for $MODEL_ID"