From 8145be410866dd0675038d92347aea34d24b84d5 Mon Sep 17 00:00:00 2001 From: WangXin93 Date: Mon, 17 Aug 2026 22:16:27 +0800 Subject: [PATCH] Add scripts for extracting EasyCom session features: `run_extract_easycom_direct.sh` for full session extraction and `run_smoke_easycom_direct.sh` for smoke testing on a single GPU. Both scripts utilize `streaming_turn_model_directly.py` for processing and include necessary configurations and logging. This enhances the EasyCom pipeline for better session management and feature extraction. --- run_extract_easycom_direct.sh | 134 ++++++++++++++++++++++++++++++++++ run_smoke_easycom_direct.sh | 66 +++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 run_extract_easycom_direct.sh create mode 100644 run_smoke_easycom_direct.sh diff --git a/run_extract_easycom_direct.sh b/run_extract_easycom_direct.sh new file mode 100644 index 0000000..c95d420 --- /dev/null +++ b/run_extract_easycom_direct.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# Extract open-stream Thinker states for all 12 EasyCom sessions via +# streaming_turn_model_directly.py (original clips, no prepared 2 FPS MP4). +# +# Recommended for full sessions: --memory-seconds 20 (bounded KV). +# Do not default to --memory-seconds 0 on multi-minute sessions. +set -euo pipefail + +PROJECT_ROOT="${PROJECT_ROOT:-/mnt/58462F4C462F29E8/Code/icassp2027-experiment}" +MODEL="${MODEL:-/mnt/58462F4C462F29E8/Models/Qwen2.5-Omni-3B}" +VIDEO_ROOT="${VIDEO_ROOT:-/mnt/58462F4C462F29E8/Datasets/easycom/Main/Video_Compressed}" +TARGET_ROOT="${TARGET_ROOT:-/mnt/58462F4C462F29E8/Code/EgoSpeak/dataset/EasyCom/target_perframe}" +FEATURE_ROOT="${FEATURE_ROOT:-${PROJECT_ROOT}/features/easycom_direct}" +LOG_ROOT="${LOG_ROOT:-${PROJECT_ROOT}/logs/easycom_direct}" + +MEMORY_SECONDS="${MEMORY_SECONDS:-20}" +NATIVE_BLOCK_SECONDS="${NATIVE_BLOCK_SECONDS:-2}" +VIDEO_FPS="${VIDEO_FPS:-2}" +MODE="${MODE:-open-stream-replay}" +DTYPE="${DTYPE:-bfloat16}" +# Space-separated host GPU ids, e.g. "0" or "0 1 2 3". One session per GPU at a time. +GPUS="${GPUS:-0}" +# Optional: only run selected session ids, e.g. SESSIONS="1 2 3" +SESSIONS="${SESSIONS:-1 2 3 4 5 6 7 8 9 10 11 12}" + +# StreamConfig requires memory / native_block to be an integer (e.g. 20/2=10). +# Values like 15 yield 7.5 and crash before loading the model. +python - "${MEMORY_SECONDS}" "${NATIVE_BLOCK_SECONDS}" <<'PY' +import sys +memory, block = float(sys.argv[1]), float(sys.argv[2]) +ratio = memory / block +if abs(ratio - round(ratio)) > 1e-6: + raise SystemExit( + f"MEMORY_SECONDS={memory} is invalid: memory/native_block={ratio} " + f"(native_block={block}). Use a multiple of {block:g}, e.g. 16, 18, 20." + ) +print(f"memory_seconds={memory:g} native_block={block:g} blocks={int(round(ratio))}") +PY + +mkdir -p "${FEATURE_ROOT}" "${LOG_ROOT}" +cd "${PROJECT_ROOT}" + +run_one() { + local gpu="$1" + local sid="$2" + local session="Session_${sid}" + local session_dir="${VIDEO_ROOT}/${session}" + local target="${TARGET_ROOT}/${session}.npy" + local output="${FEATURE_ROOT}/${session}.pt" + local log="${LOG_ROOT}/${session}.log" + + if [[ ! -d "${session_dir}" ]]; then + echo "Missing session dir: ${session_dir}" >&2 + return 1 + fi + if [[ ! -s "${target}" ]]; then + echo "Missing target: ${target}" >&2 + return 1 + fi + if [[ -s "${output}" ]]; then + echo "Skipping existing output: ${output}" + return 0 + fi + + { + echo "$(date): GPU ${gpu} starting ${session}" + echo "model=${MODEL}" + echo "session_dir=${session_dir}" + echo "target=${target}" + echo "output=${output}" + echo "memory_seconds=${MEMORY_SECONDS} video_fps=${VIDEO_FPS} mode=${MODE}" + + if ! CUDA_VISIBLE_DEVICES="${gpu}" PYTHONUNBUFFERED=1 \ + python streaming_turn_model_directly.py \ + --model-id "${MODEL}" \ + --easycom-session-dir "${session_dir}" \ + --target "${target}" \ + --use-audio-in-video \ + --mode "${MODE}" \ + --memory-seconds "${MEMORY_SECONDS}" \ + --native-block-seconds "${NATIVE_BLOCK_SECONDS}" \ + --video-fps "${VIDEO_FPS}" \ + --dtype "${DTYPE}" \ + --flash-attention-2 \ + --device cuda:0 \ + --output "${output}" + then + echo "$(date): GPU ${gpu} FAILED ${session}" + exit 1 + fi + + echo "$(date): GPU ${gpu} completed ${session}" + } >"${log}" 2>&1 +} + +# Round-robin sessions across GPUs. +mapfile -t GPU_ARR < <(echo "${GPUS}" | tr ' ' '\n' | sed '/^$/d') +mapfile -t SID_ARR < <(echo "${SESSIONS}" | tr ' ' '\n' | sed '/^$/d') + +declare -A WORKERS=() +for gpu in "${GPU_ARR[@]}"; do + WORKERS["${gpu}"]="" +done + +i=0 +for sid in "${SID_ARR[@]}"; do + gpu="${GPU_ARR[$((i % ${#GPU_ARR[@]}))]}" + WORKERS["${gpu}"]+="${sid} " + i=$((i + 1)) +done + +pids=() +status=0 +for gpu in "${GPU_ARR[@]}"; do + sids="${WORKERS[${gpu}]}" + [[ -z "${sids// }" ]] && continue + ( + for sid in ${sids}; do + run_one "${gpu}" "${sid}" || exit 1 + done + ) & + pids+=("$!") +done + +for pid in "${pids[@]}"; do + wait "${pid}" || status=1 +done + +if [[ "${status}" -ne 0 ]]; then + echo "At least one EasyCom direct extraction failed. Check ${LOG_ROOT}." >&2 + exit 1 +fi + +echo "ALL EasyCom direct extractions completed -> ${FEATURE_ROOT}" diff --git a/run_smoke_easycom_direct.sh b/run_smoke_easycom_direct.sh new file mode 100644 index 0000000..b140835 --- /dev/null +++ b/run_smoke_easycom_direct.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# Smoke: one EasyCom session on one GPU via streaming_turn_model_directly.py +# +# Short smoke (default): --end only, NO --target +# (passing both requires --end == full target duration) +# Full session: END= (empty) and --target is used +set -euo pipefail + +# Remote defaults (override as needed) +PROJECT_ROOT="${PROJECT_ROOT:-/data1/yfzx/wangx/Code/icassp2027-experiment}" +MODEL="${MODEL:-/data1/yfzx/wangx/Models/Qwen2.5-Omni-3B}" +VIDEO_ROOT="${VIDEO_ROOT:-/data1/yfzx/wangx/Datasets/easycom/extracted_easycom/Main/Video_Compressed}" +TARGET_ROOT="${TARGET_ROOT:-/data1/yfzx/wangx/Datasets/easycom/target_frame}" +FEATURE_ROOT="${FEATURE_ROOT:-${PROJECT_ROOT}/features/easycom_direct_smoke}" +LOG_ROOT="${LOG_ROOT:-${PROJECT_ROOT}/logs/easycom_direct_smoke}" + +SESSION_ID="${SESSION_ID:-1}" +GPU="${GPU:-0}" +# Short smoke: END=4. Full session smoke: END="" (empty). +END="${END:-4}" +MEMORY_SECONDS="${MEMORY_SECONDS:-20}" +VIDEO_FPS="${VIDEO_FPS:-2}" + +session="Session_${SESSION_ID}" +session_dir="${VIDEO_ROOT}/${session}" +target="${TARGET_ROOT}/${session}.npy" +output="${FEATURE_ROOT}/${session}_gpu${GPU}.pt" +log="${LOG_ROOT}/${session}_gpu${GPU}.log" + +mkdir -p "${FEATURE_ROOT}" "${LOG_ROOT}" +cd "${PROJECT_ROOT}" + +[[ -d "${session_dir}" ]] || { echo "Missing: ${session_dir}" >&2; exit 1; } + +extra_args=() +if [[ -n "${END}" ]]; then + # Bounded smoke: do not pass --target (length would conflict with --end). + extra_args+=(--end "${END}") + MEMORY_SECONDS=0 +else + [[ -s "${target}" ]] || { echo "Missing: ${target}" >&2; exit 1; } + extra_args+=(--target "${target}") +fi + +echo "GPU=${GPU} session=${session} end=${END:-full} memory=${MEMORY_SECONDS}" +echo "log -> ${log}" + +{ + echo "$(date): smoke start ${session} on GPU ${GPU}" + CUDA_VISIBLE_DEVICES="${GPU}" PYTHONUNBUFFERED=1 \ + python streaming_turn_model_directly.py \ + --model-id "${MODEL}" \ + --easycom-session-dir "${session_dir}" \ + --use-audio-in-video \ + --mode open-stream-replay \ + --memory-seconds "${MEMORY_SECONDS}" \ + --video-fps "${VIDEO_FPS}" \ + --dtype bfloat16 \ + --flash-attention-2 \ + --device cuda:0 \ + --verify-every 5 \ + --verify-continuous-every 5 \ + "${extra_args[@]}" \ + --output "${output}" + echo "$(date): smoke done -> ${output}" +} 2>&1 | tee "${log}"