Skip to content

Commit ed2fd21

Browse files
committed
chore: Notion 동기화 2026-06-27 16:00
1 parent a165d34 commit ed2fd21

3 files changed

Lines changed: 35 additions & 61 deletions

docs/poc/.notion-sync.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
},
99
"368e15b4-0359-81cb-9b9b-d555dbfd19e3": {
1010
"file": "docs/poc/vision-bench/1편-멀티모달-llm-한국-방송-6초-클립-영상-이해-벤치마크파이프라인-구축.md",
11-
"last_edited": "2026-06-27T05:55:00.000Z",
12-
"content_hash": "47d97cc8dc108d05b0a9c10df76cb496fbff8205644f067f068c869f11f75b24",
11+
"last_edited": "2026-06-27T06:49:00.000Z",
12+
"content_hash": "6873f38cc9e3d56537b3fdb1b967f3476f4b972bef160bf3010b6266a5915971",
1313
"order": 1,
1414
"parent_id": "vision-bench"
1515
},
@@ -29,8 +29,8 @@
2929
},
3030
"373e15b4-0359-8150-88f3-eedc5ebd727b": {
3131
"file": "docs/poc/vision-bench/2편-추론-파라미터-튜닝-qwen3-omni-6초-클립-분석-ofat-스윕.md",
32-
"last_edited": "2026-06-10T17:05:00.000Z",
33-
"content_hash": "130babd1d227d3dd415989b016818f5ecb2a24bb89b384d7b73bdf3e799cf961",
32+
"last_edited": "2026-06-27T07:00:00.000Z",
33+
"content_hash": "57c5e64f3006b49dae24789b3f2d0c19423be9718c9a108b515d12e449c37c08",
3434
"order": 3,
3535
"parent_id": "vision-bench"
3636
},

docs/poc/vision-bench/1편-멀티모달-llm-한국-방송-6초-클립-영상-이해-벤치마크파이프라인-구축.md

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ done
185185
```bash
186186
cd "$(git rev-parse --show-toplevel)"
187187
TARGETS=(
188+
"baseball baseball.mp4"
188189
"docu docu.mp4"
189190
"drama drama.mp4"
190191
"entertain entertain.mp4"
@@ -211,8 +212,6 @@ done
211212
:::note
212213
**한 번에 실행**
213214

214-
- 위 작업을 자동화한 스크립트
215-
216215
`./script/prepare_data.sh <카테고리> <파일명>`
217216

218217
- 이미 확보한 `data/raw` 원본을 대상으로 클립 분할·블랙아웃만 수행(원본은 손대지 않음).
@@ -230,7 +229,7 @@ done
230229
| `drama` | 현대 드라마 | 100 | 720×480 | 29.97 | 1.10 MB | 인물 대사 + BGM |
231230
| `hist_drama` | 사극 | 100 | 1920×1080 | 29.97 | 1.23 MB | 시대 의상·소품 + 문어체 대사 |
232231
| `esports` | e스포츠 | 100 | 1920×1080 | **60** | 1.35 MB | 게임 UI 오버레이 + 캐스터 + 게임음 |
233-
| **합계** | | **700** | | | ≈ 1.25 MB | 원본 영상 7편 (장르당 1편, 10분 윈도우 100 등분) |
232+
| **합계** | - | **700** | - | - | ≈ 1.25 MB | 원본 영상 7편 (장르당 1편, 10분 윈도우 100 등분) |
234233

235234
:::warning
236235
🔒 **데이터 취급 원칙**
@@ -271,22 +270,26 @@ done
271270

272271
| **** | **기본** | **역할** |
273272
| --- | --- | --- |
274-
| `VLLM_BASE_URL` | | vLLM `/v1` 엔드포인트 |
273+
| `VLLM_BASE_URL` | - | vLLM `/v1` 엔드포인트 |
275274
| `VLLM_CONCURRENCY` | 4 | 동시 호출 상한(Semaphore). 권장 1\~8 |
276275
| `MAX_BATCH_ITEMS` | 128 | `/chat/batch` 한 요청의 최대 items |
277276
| `VLLM_TIMEOUT_SECONDS` | 600s | 업스트림 호출 타임아웃 |
278-
| `VLLM_ACQUIRE_TIMEOUT_SECONDS` | 300s | 세마포어 퍼밋 획득 최대 대기(초). 초과 시 그 요청만 실패 처리 → 퍼밋 누수·half-open(끊긴 클라 FIN 미수신)으로 인한 데드락 백스톱 |
277+
| `VLLM_ACQUIRE_TIMEOUT_SECONDS` | 300s | 세마포어 퍼밋 획득 최대 대기(초). 초과 시 그 요청만 실패 처리. |
279278

280279
#### 3.2.3. 배치 NDJSON 스트리밍
281280

282-
- `/chat/batch` 는 다건을 받아 fan-out(`asyncio.create_task` ) 후 **완료 순서** (`asyncio.wait(..., return_when=FIRST_COMPLETED)` )로 한 줄씩 흘린다(`application/x-ndjson` , chunked). 입력 순서가 아니므로 `id` 로 매칭하며, 한두 건이 실패해도 나머지는 계속 진행한다(각 라인의 `status` 로 판단).
283-
- **백프레셔·데드락 하드닝:** 스트리밍 루프는 0.5초마다 `request.is_disconnected()` 로 클라 생존을 확인해, 클라가 끊기면(FIN 수신) in-flight task 를 전부 cancel 하고 세마포어 퍼밋을 즉시 반납한다. half-open(FIN 미수신)처럼 끊김을 못 잡는 경우는 `client.chat()`**퍼밋 획득 타임아웃** (`VLLM_ACQUIRE_TIMEOUT_SECONDS` , 기본 300s)이 되어 그 요청만 실패 처리한다 → 끊긴 런이 퍼밋을 영구 점유해 게이트웨이가 멈추는 데드락 방지.
281+
- `/chat/batch` 는 다건을 받아 fan-out 후 **완료 순서** 로 한 줄씩 흘린다.
282+
- 입력 순서가 아니므로 `id` 로 매칭하며, 한두 건이 실패해도 나머지는 계속 진행한다.
283+
- 백프레셔, 데드락 방지 : 동시 처리 수는 세마포어 퍼밋으로 제한한다. 퍼밋이 다 차면 새 요청은 빌 때까지 대기한다. 끊긴 요청이 퍼밋을 붙든 채 남으면 게이트웨이가 멈출 수 있어, 두 단계로 회수한다:
284+
1. 스트리밍 루프가 0.5초마다 request.is_disconnected()로 연결을 확인 → 끊기면 진행 중 작업을 취소하고 퍼밋을 즉시 반납한다.
285+
286+
1. 끊김 신호가 안 오는 half-open 연결은 퍼밋 획득 타임아웃(`VLLM_ACQUIRE_TIMEOUT_SECONDS` , 기본 300초)으로 해당 요청만 실패시켜 퍼밋을 회수한다.
284287

285288
요청 본문:
286289

287290
```json
288291
{"items": [
289-
{"id": "0001_0600-0606", "body": {<vLLM chat.completions body /chat 와 동일>}},
292+
{"id": "0001_0600-0606", "body": {<vLLM chat.completions body - /chat 와 동일>}},
290293
{"id": "0002_0606-0612", "body": {<...>}}
291294
]}
292295
```
@@ -309,7 +312,7 @@ done
309312

310313
#### 3.2.4. 서버 실행
311314

312-
게이트웨이는 `script/service.sh` 로 관리한다.
315+
서버는 `script/service.sh` 로 관리한다.
313316

314317
```bash
315318
./script/service.sh start # 백그라운드 기동 (healthz OK 까지 대기)
@@ -319,15 +322,14 @@ done
319322
```
320323

321324
- 직접 실행: `PYTHONPATH=src uv run uvicorn app:app --host 0.0.0.0 --port 8001`
322-
- vLLM 연결·동시성은 `.env` (→ 3.2.2). 대화형 문서: `/docs` (Swagger)
323325

324326
#### 3.2.5. API 입출력 예시
325327

326328
| **Method** | **Path** | **역할** | **비고** |
327329
| --- | --- | --- | --- |
328330
| GET | `/healthz` | 헬스체크 | lifespan 통과 후 항상 200. 업스트림 도달 여부는 검사 X |
329331
| POST | `/chat` | 단건 passthrough | vLLM body 그대로 → 응답 그대로. 업스트림 도달 불가 시 502 |
330-
| POST | `/chat/batch` | 다건 NDJSON 스트리밍 | 완료 순서로 라인별 흘림 (상세 3.2.3) |
332+
| POST | `/chat/batch` | 다건 NDJSON 스트리밍 | 완료 순서로 라인별 흘림 |
331333

332334
1. `/healthz`
333335

@@ -336,7 +338,7 @@ done
336338
```
337339

338340
2. `/chat` (단건)
339-
- 입력: 클라가 조립한 vLLM body (base64 영상 + 프롬프트 + strict schema). 멀티모달 옵션은 **두 키로 분리** 프레임 샘플링은 `media_io_kwargs.video` (`fps` 또는 `num_frames` , vLLM I/O 로더), 오디오 통합은 `mm_processor_kwargs.use_audio_in_video` (HF 프로세서).
341+
- 입력: 클라가 조립한 vLLM body (base64 영상 + 프롬프트 + strict schema). 멀티모달 옵션은 **두 키로 분리.** 프레임 샘플링은 `media_io_kwargs.video` (`fps` 또는 `num_frames` , vLLM I/O 로더), 오디오 통합은 `mm_processor_kwargs.use_audio_in_video` .
340342

341343
```json
342344
{
@@ -353,7 +355,7 @@ done
353355
}
354356
```
355357

356-
- 출력: vLLM 응답 그대로 `choices[0].message.content` 에 strict JSON 문자열:
358+
- 출력: vLLM 응답 그대로 `choices[0].message.content` 에 strict JSON 문자열:
357359

358360
```json
359361
{
@@ -364,7 +366,7 @@ done
364366

365367
> 실행: `./script/curl_examples.sh chat`
366368
367-
3. `/chat/batch` (다건) 입력: `{items:[{id, body}, …]}` (각 body = ②와 동일)
369+
3. `/chat/batch` (다건) 입력: `{items:[{id, body}, …]}` (각 body = ②와 동일)
368370

369371
```json
370372
{"items": [
@@ -373,7 +375,7 @@ done
373375
]}
374376
```
375377

376-
출력: `application/x-ndjson` 완료 순서로 한 줄씩 (필드 상세 3.2.3):
378+
출력: `application/x-ndjson` 완료 순서로 한 줄씩 (필드 상세 3.2.3):
377379

378380
```javascript
379381
{"id":"0001_0600-0606","status":200,"elapsed_ms":3104,"body":{<vLLM 응답>}}
@@ -400,8 +402,6 @@ x-request-id: 6da1b40a
400402
{"ok":true}
401403
```
402404

403-
**PASS** — 서버 기동·라우팅 정상, 모든 응답에 `X-Request-Id` 부여 확인.
404-
405405
#### 3.3.2. 단일 추론 (`POST /chat` )
406406

407407
1. **텍스트추론**
@@ -543,7 +543,7 @@ x-request-id: 6da1b40a
543543
544544
</details>
545545
546-
3. **블랙아웃 영상 + 프롬프트** (통제 실험 — 화면만 검게, 오디오 유지)
546+
3. **블랙아웃 영상 + 프롬프트** (화면만 검게, 오디오 유지)
547547
<details>
548548
<summary>요청 (curl)</summary>
549549
@@ -624,7 +624,7 @@ x-request-id: 6da1b40a
624624
<summary>재현 요약 코드 (<code>batch_throughput.py</code> 핵심부)</summary>
625625
626626
```python
627-
# experiments/01_pipeline/batch_throughput.py 핵심부 (같은 items 로 순차 vs 배치 비교)
627+
# experiments/01_pipeline/batch_throughput.py 핵심부 (같은 items 로 순차 vs 배치 비교)
628628
import os, base64, json, time, httpx
629629
from pathlib import Path
630630
@@ -673,7 +673,7 @@ print(f"순차 {seq_ms}ms · 배치 {batch_ms}ms · {seq_ms / batch_ms:.2f}×")
673673
| 순차 (한 건씩 `/chat` ) | 37536ms | 12/12 |
674674
| 배치 (`/chat/batch` 일괄) | 22603ms | 12/12 |
675675
676-
배치가 순차보다 빠름(약 **1.7배** , 게이트웨이 동시성 `VLLM_CONCURRENCY=4` 만큼 fan-out 병렬 빈출력/폭주 jitter 로 실행마다 배수는 변동). 도착 순서 ≠ 입력 순서(**완료순 스트리밍** ), `X-Batch-Total=12` . 다건 1요청·완료순 스트리밍·각 건 독립 `status` 모두 정상.
676+
배치가 순차보다 빠름(약 **1.7배** , 게이트웨이 동시성 `VLLM_CONCURRENCY=4` 만큼 fan-out 병렬. 빈출력/폭주 jitter 로 실행마다 배수는 변동). 도착 순서 ≠ 입력 순서(**완료순 스트리밍** ), `X-Batch-Total=12` . 다건 1요청·완료순 스트리밍·각 건 독립 `status` 모두 정상.
677677
678678
#### 3.3.4. 요약
679679
@@ -710,26 +710,3 @@ print(f"순차 {seq_ms}ms · 배치 {batch_ms}ms · {seq_ms / batch_ms:.2f}×")
710710
- [Qwen3-Omni vLLM 서빙 가이드](https://docs.vllm.ai/projects/vllm-omni/en/latest/user_guide/examples/online_serving/qwen3_omni/) — `vllm serve` 옵션 (`--max-model-len` 등)
711711
- [vLLM — OpenAI-Compatible Server](https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html) — `/v1/chat/completions` 규약·`response_format` ·extra body(`mm_processor_kwargs` ·`chat_template_kwargs` ). 게이트웨이가 이 본문을 그대로 패스
712712
713-
## 처리할 대상: "카테고리 원본명" 쌍을 줄마다 하나씩
714-
715-
TARGETS=(
716-
"news kbs9"
717-
"drama sample1"
718-
"baseball game3"
719-
)
720-
721-
for target in "${TARGETS[@]}"; do
722-
read -r CAT NAME <<< "$target"
723-
SRC="data/raw/$CAT/$NAME.mp4"
724-
OUT="data/clips/$CAT/$NAME"; mkdir -p "$OUT"
725-
726-
echo "▶ $CAT/NAME 분할 시작"
727-
for i in (seq 0 99); do
728-
start=((600 + i*6)); end=((start + 6)) # 절대초 600,606,…,1194
729-
name=(printf "%04d_%04d-%04d"((i+1)) "$start" "$end") # 0001_0600-0606
730-
ffmpeg -nostdin -ss "$start" -i "$SRC" -t 6 \
731-
-c:v libopenh264 -b:v 1500k -c:a aac -movflags +faststart \
732-
"$OUT/$name.mp4"
733-
done
734-
done
735-

docs/poc/vision-bench/2편-추론-파라미터-튜닝-qwen3-omni-6초-클립-분석-ofat-스윕.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,40 @@
11
---
22
id: 2편-추론-파라미터-튜닝-qwen3-omni-6초-클립-분석-ofat-스윕
3-
title: "[2편] 추론 파라미터 튜닝 Qwen3-Omni 6초 클립 분석 (OFAT 스윕)"
3+
title: "[2편] 추론 파라미터 튜닝 Qwen3-Omni 6초 클립 분석 (OFAT 스윕)"
44
sidebar_position: 3
55
slug: "3"
66
last_update:
7-
date: 2026-06-10
7+
date: 2026-06-27
88
---
99

1010
## 1. 들어가며
1111

12-
SceneMaker의 클립 영상 분석은 영상에 포함된 **시각·청각 정보를 안정적으로 생성** 해내는 것을 목표로 한다. 6초 클립 하나를 입력 받아 세 갈래의 정보를 `{summary, objects, ocr, actions, bgm, sfx}` 6필드 JSON으로 구조화한다.
12+
SceneMaker의 클립 영상 분석은 영상에 포함된 **시각·청각 정보를 안정적으로 생성** 해내는 것을 목표로 한다. 6초 클립을 입력 받아 시청각 정보를 `{summary, ocr, actions, sounds}` json 형식의 4필드로 구조화한다.
1313

1414
- **종합 분석**
1515
- `summary` : 시각·청각을 종합한 한 문장 요약
1616

1717
- **시각 분석**
18-
- `objects` (핵심 객체·인물)
19-
2018
- `ocr` (화면 텍스트: 자막·로고)
2119

22-
- `actions` (행동·움직임·장면 전환)
20+
- `actions` (행동·움직임)
2321

2422
- **청각 분석**
25-
- `bgm` (배경음·음악·분위기)
26-
27-
- `sfx` (효과음: 박수·타이핑 등)
23+
- `sounds` (효과음: 박수·타이핑 등)
2824

29-
여기서 관건은 **안정성** 이다. 700개 클립을 일괄 처리하는 벤치마크에서 같은 클립·같은 프롬프트인데도 실행마다 출력이 흔들리거나 무너지면 품질 점수 자체를 신뢰할 수 없다. 1편(파이프라인 구축) 검증 과정에서 네 가지 품질저하 패턴이 간헐적으로 식별됐다.
25+
**관건은 안정성** 이다. 출력이 흔들리면 품질 점수를 믿을 수 없다. 1편 검증에서 이를 위협하는 네 가지 품질저하 패턴이 간헐적으로 발견됐다.
3026

3127
1. **조기 종료 (Premature EOS)** : 첫 토큰부터 EOS(문장 종료)를 출력해 content가 빈 문자열로 끝난다. strict JSON schema의 과도한 압박 등으로 모델이 "할 말 없이" 바로 닫아버리는 경우.
3228
2. **붕괴 (Text Degeneration)** : 정상 확률분포를 잃고 이종문자·시스템 토큰을 쏟아내다 JSON을 완성 못 하고 터진다(Gibberish Generation).
3329
3. **반복 (Repetition Loop)** : 같은 단어·항목·JSON 구조를 확률 갇힘으로 맴돌며 반복 생성한다.
3430
4. **추론 시간 편차 (Latency Jitter)** : 붕괴·반복이 정상 EOS를 막아 출력이 `max_tokens` 까지 늘어지는 탈주 생성(Runaway Generation) 때문에, 클립당 추론 시간의 최소\~최대 격차가 극심하다.
3531

36-
이 패턴들은 1편에서 **관찰·식별** 됐을 뿐, 추론 파라미터로 **통제 가능한지는 다루지 않았다** . 본 편(2편)은 출력을 strict JSON Schema로 고정한 상태를 전제로 한다. 그 위에서 두드러지는 **반복·degeneration 등** 이 추론 파라미터로 통제되는지를 한 번에 하나씩(OFAT, one-factor-at-a-time) 크게 흔들어 규명한 **1단계 스크리닝** 의 기록이다.
32+
본 편은 그 패턴들이 추론 파라미터로 통제되는지를 규명한다. 1편에서는 네 패턴을 관찰·식별했을 뿐, 파라미터로 잡을 수 있는지는 다루지 않았기 때문이다.
33+
전제는 출력을 strict JSON Schema로 고정한 상태다. 그 위에서도 두드러지는 반복·degeneration 등을 대상으로, 파라미터를 한 번에 하나씩(OFAT) 크게 흔들어 어느 것이 통제에 듣는지 1차로 굵게 거르는 단계다.
3734

3835
## 2. 실험 환경
3936

40-
벤치마크와 **동일한 모델·서빙·호출 경로** 에서 수행했다. 파라미터 효과를 그 환경 그대로 관찰하기 위함이다. 환경 구성의 상세는 1편 「멀티모달 LLM 한국 방송 6초 클립 영상 이해 벤치마크 파이프라인 구축」 에 있으므로, 여기서는 핵심 요약과 본 실험의 **튜닝 대상 파라미터** 만 다룬다.
37+
벤치마크와 **동일한 모델·서빙·호출 경로** 에서 수행했다. 파라미터 효과를 그 환경 그대로 관찰하기 위함이다. 환경 구성의 상세는 1편 「멀티모달 LLM 한국 방송 6초 클립 영상 이해 벤치마크 파이프라인 구축」에 있으므로, 여기서는 핵심 요약과 본 실험의 **튜닝 대상 파라미터** 만 다룬다.
4138

4239
### 2.1. 환경 요약
4340

@@ -62,9 +59,9 @@ SceneMaker의 클립 영상 분석은 영상에 포함된 **시각·청각 정
6259

6360
### 2.2. 튜닝 대상 파라미터
6461

65-
추론 매개변수는 서버 설정이 아니라 **클라이언트가 요청 본문에 직접 명시** 한다. 파라미터는 작동 레이어에 따라 두 갈래로 나뉜다 **vLLM 입력 처리** (미디어를 모델에 넣기 전 준비)와 **Qwen3-Omni 생성 샘플링** (모델이 출력을 뽑는 디코딩). 본 실험의 OFAT 스윕은 *생성 샘플링* 그룹만 한 번에 하나씩(변동) 흔들고, 나머지는 전 구간 고정한다.
62+
추론 매개변수는 서버 설정이 아니라 **클라이언트가 요청 본문에 직접 명시** 한다. 파라미터는 작동 레이어에 따라 두 갈래로 나뉜다. **vLLM 입력 처리** (미디어를 모델에 넣기 전 준비)와 **Qwen3-Omni 생성 샘플링** (모델이 출력을 뽑는 디코딩). 본 실험의 OFAT 스윕은 *생성 샘플링* 그룹만 한 번에 하나씩(변동) 흔들고, 나머지는 전 구간 고정한다.
6663

67-
**1. Qwen3-Omni 생성 샘플링 파라미터** (*Autoregressive Decoding · Sampling Strategies* ) OFAT 변동
64+
**1. Qwen3-Omni 생성 샘플링 파라미터** (*Autoregressive Decoding · Sampling Strategies* ). OFAT 변동
6865

6966
| **파라미터** | **역할** | **값 범위** | **본 실험** |
7067
| --- | --- | --- | --- |

0 commit comments

Comments
 (0)