動画・音声解析基盤 完全実装仕様書
[!NOTE] 最新の実装状況は 機能実装ステータス (Remaining Functionality) を参照してください。
目的: 本ドキュメントは evospikenet におけるマルチモーダル(映像+音声)時系列解析基盤を完全実装するための仕様書である。PoC ではなく、本番運用を想定した要件、アーキテクチャ、モジュール分割、性能目標、テスト基準、デプロイ要件、プライバシー/セキュリティ要件、および段階的実装計画を含む。
対象読者: 開発者、ML エンジニア、SRE、プロダクトオーナー
概略要件 - 処理対象: 単一/複数人物の動画(フレーム列)と同一録音トラック(wav)を入力とする。リアルタイム(ストリーミング)とバッチ両方に対応。 - 出力: 時系列イベント(トラックID, タイムスタンプ, アクションラベル, 信頼度)、ASR 字幕(タイムスタンプ付き)、マルチモーダル統合タイムライン、自然言語要約(短文) - 可用性: 99.5% (サービス SLA)、スケーラビリティ: 水平スケールで N ノード対応 - レイテンシ目標: 同期 API(小入力): - P95 < 2s(軽量 backends/fallback) - GPU 加速時 P95 < 300ms(小バッチ)
非機能要件 - モジュール化: 各処理(pose/tracking/action/asr/fusion/summary)はバックエンド差し替え可能なプラグイン形式 - リソース管理: GPU/CPU/メモリの割当制御、batching、バックプレッシャ対応 - 耐障害性: ジョブ再試行、inflight 再キュー、永続化ストア(Redis/SQLite/JSON フォールバック) - 可観測性: メトリクス(処理遅延、スループット、成功率)、トレース、ログ(構造化) - プライバシー: 顔/個人識別情報の匿名化オプション、データ保存ポリシー、同意管理
アーキテクチャ概観
- 入力層: アップロード/ストリーム受信(HTTP/GRPC)、受信時にメタデータ付与
- ワーカー層: ジョブキュー(Redis/Celery または VideoAnalysisJobStore)+ワーカー群(同期/非同期)
- バックエンド層: モデルランタイムプラグイン (Torch/TensorRT/ONNX Runtime/Python fallback)
- 集約層: EventFusionEngine + SummaryGenerator(LLM ラッパーまたはテンプレート)
- API 層: 同期分析エンドポイント(/api/video-analysis/analyze)、非同期ジョブ API(/api/video-analysis/submit/status/result)
- ストレージ: 入力アーティファクト(オプション)、結果キャッシュ、ジョブメタ(Redis/SQLite)
主要コンポーネント(機能項目) 各項は「完成実装」を目指す内容。優先度は P0/P1/P2 を併記。
1) データ受け入れ & 前処理(P0) - HTTP/GRPC/Multipart アップロードエンドポイント - ストリーミング ingestion(chunked フレーム/音声) - 入力検証(解像度、サンプルレート、長さ制限) - 前処理: フレーム正規化、音声正規化、サンプリング、切り出し
2) キーポイント抽出モジュール pose(P0)
- バックエンド: MoveNet / MediaPipe / ONNX MoveNet / TensorRT エクスポート
- API: estimate(frame) -> List[Pose](timestamp, keypoints(dict{name:[x,y,conf]}))
- 要件: バッチ/ストリーミング両対応、GPU 有無で最適化、deterministic な fallback
- 性能: 1080p で 30fps を継続処理できるスループット(GPU 時)
3) トラッキングモジュール tracking(P0)
- アルゴリズム: DeepSORT / IoU ベース トラッカー(選択可能)
- API: update(detections, timestamp) -> List[Tracked](track_id, bbox, keypoints)
- 再識別(ReID)プラグインをサポート
- ロバストネス: 遮蔽復帰、短期 ID 継続
4) 行為認識モジュール action_recognition(P0)
- モデル: ST-GCN / TCN / 軽量 3D-CNN をサポート
- API: classify(tracked_sequence) -> List[ActionEvent](track_id, start, end, label, score)
- スライディングウィンドウ推論、オンライン更新
5) ASR モジュール asr(P0)
- バックエンド: Whisper (small/medium), Kaldi/other、ONNX 等
- API: transcribe(audio_chunk) -> Transcript(segments with timestamps, confidence)
- スピーカーダイアリゼーション/重ね話対策(プラグイン)
6) イベント融合エンジン fusion(P0)
- タイムライン同期:映像イベントと ASR セグメントを統合
- トリガー抽出: 重要イベント抽出(しきい値、ルール、ML ベース)
- 出力フォーマット: timeline, summary_candidates, metrics
7) 要約生成 summary(P1)
- 軽量テンプレート要約 + LLM ベース要約プラグイン
- API: generate_summary(timeline, transcript) -> str(多言語サポート)
8) 永続化ジョブストア & ワーカー(P0) - 高信頼ジョブストア: Redis primary, SQLite persistent fallback, JSON fallback - ワーカープール: 再起動時の inflight 回復、ジョブ優先度、再試行ポリシー - モニタリング: queue length, worker health, processing_latency
9) バックエンド管理 & プラグインフレームワーク(P0)
- バックエンド登録 API: register_backend(name, capabilities)
- ランタイム切替: GPU/CPU/FP16/INT8 の選択、モデルキャッシュ
- ヘルスチェック / 自動フェイルオーバー
10) API 層(P0)
- 同期: /api/video-analysis/analyze(短時間バッチ)
- 非同期: /api/video-analysis/submit, /api/video-analysis/status/{id}, /api/video-analysis/result/{id}
- 認証: API Key / OAuth2 / RBAC
11) テスト & 評価(P0) - 単体テスト: 各モジュールの deterministic edge cases - 統合テスト: 小サンプル動画 end-to-end(mAP/IDF1/WER) - 性能テスト: スループット、レイテンシ、スケーリング試験 - データ品質テスト: ASR WER レポート、IDF1
12) プライバシー & セキュリティ(P0) - 顔/音声匿名化フィルタ(オプション) - 保管暗号化(DataAtRestEncryption)、転送時 TLS - 同意/削除 API、ログ最小化
13) デプロイ & オーケストレーション(P1) - Docker + Kubernetes マニフェスト、GPU ノード設定 - Horizontal Pod Autoscaler 用のメトリクス出力(custom metrics) - Canary / Blue-Green デプロイ戦略、モデルホットスワップ
14) 可視化 / フロントエンド(P1) - タイムライン可視化、トラック可視化、要約ビュー - WebSocket または SSE によるリアルタイム更新
受け入れ基準(例) - 単体テスト網羅率: モジュールごとに 90% 以上(重要ロジック) - 統合 E2E: サンプル動画で pipeline が成功し、IDF1 >= 0.60(簡易データ)、WER <= 0.30(雑音少) - レイテンシ: 軽量 fallback で P95 < 2s、GPU 環境で P95 < 300ms - セキュリティ: データ保存時に AES-256-GCM を使用、削除 API がリクエストで動作
段階的実装計画(短期→中期) Phase 1 (2週): 基本 API、ジョブキュー、pose fallback、job store、ユニットテスト Phase 2 (3週): トラッキング、簡易 action_recognition、ASR fallback、fusion, simple summary Phase 3 (4週): 本格モデル統合(MoveNet/Whisper/ST-GCN)、GPU 最適化、性能チューニング Phase 4 (継続): プライバシー強化、K8s デプロイ、監視・SLO 達成
開発・CI 要件
- requirements.txt に optional extras: video[torch], onnxruntime-gpu, whisper, opencv-python-headless, redis, fastapi[all] などを追加管理
- CI: GPU を必要とするテストはラベル付け、CPU フォールバックのテストは常時実行
ドキュメント配置
- 仕様書: Docs/VIDEO_AUDIO_ANALYSIS_SPEC.md(本ファイル)
- 実装チェックリスト: docs/implementation/video_analysis_checklist.md(実装進捗とファイル証跡を連携)
実装状況(2026-04-24 更新)
実装済みモジュール一覧
以下のモジュールがすべて evospikenet/video_analysis/ に実装済みです。
| モジュール | ファイル | フェーズ | 状態 |
|---|---|---|---|
| ポーズ推定 (fallback) | pose.py |
Phase 1 | ✅ 完了 |
| トラッキング (IoU) | tracking.py |
Phase 1 | ✅ 完了 |
| 行動認識 (位置差分) | action_recognition.py |
Phase 1 | ✅ 完了 |
| ASR ラッパー | asr.py + asr_policy.py |
Phase 1 | ✅ 完了 (fallback) |
| イベント融合 | fusion.py |
Phase 1 | ✅ 完了 |
| ジョブキュー | job_queue.py |
Phase 1 | ✅ 完了 |
| バックエンド管理 | backends.py + backends_real.py |
Phase 2 | ✅ 完了 |
| Celery ワーカー | worker.py |
Phase 2 | ✅ 完了 |
| プライバシー処理 | privacy.py |
Phase 2 | ✅ 完了 |
| 評価指標 | metrics.py + runtime_metrics.py |
Phase 2 | ✅ 完了 |
| 統一イベントスキーマ | event_schema.py |
Phase 3 | ✅ 2026-04-24 新規 |
| ショット境界検出 | shot_boundary_detector.py |
Phase 3 | ✅ 2026-04-24 新規 |
| VAD・話者分離 | vad.py |
Phase 3 | ✅ 2026-04-24 新規 |
| 単眼深度推定 | depth_estimation.py |
Phase 3 | ✅ 2026-04-24 新規 |
| 空間関係抽出 | spatial_relations.py |
Phase 3 | ✅ 2026-04-24 新規 |
| ナラティブ生成 | narrative_generator.py |
Phase 3 | ✅ 2026-04-24 新規 |
| 時系列行動ローカリゼーション | temporal_action_localizer.py |
Phase 3 | ✅ 2026-04-24 新規 |
| パイプライン統合 | pipeline.py (enable_extended) |
Phase 3 | ✅ 2026-04-24 更新 |
新規モジュール詳細
event_schema.py — 統一イベントスキーマ
Actor(id, type, attributes, bbox, keypoints, track_id)SpatialFrame(type, coords, depth_m, relation_desc)EventEvidence(detection_ids, transcript_snippet, frame_indices, pose_refs)Event— dict ベースファクトリ:from_vision_detection(det, timestamp),from_asr_segment(seg),from_scene_change(frame_idx, timestamp)AnalysisTimeline—sorted_events(),filter_by_type(),filter_by_confidence(),to_dict()
shot_boundary_detector.py — ショット境界検出
- 手法: ヒストグラム差分 / ピクセル差分 / 複合 (選択可能)
ShotBoundaryDetector(threshold, method, min_scene_len).detect(frames, fps) → [(frame_idx, timestamp), ...]detect_scores()でスコア付き出力も可能
vad.py — VAD・話者分離
VoiceActivityDetector(energy_threshold, frame_duration_ms, merge_gap_s, min_speech_s)detect(audio_wave, sample_rate) → [{"start", "end", "energy"}, ...]SpeakerDiarizer(max_speakers)— pyannote.audio 置換フック
depth_estimation.py — 単眼深度推定
- フォールバック: 輝度勾配ベース疑似深度マップ
- 本番フック:
torch.hub.load("intel-isl/MiDaS", "MiDaS_small") DepthEstimator.estimate(frame) → {"depth_map": ndarray(H,W), "depth_at_center": float, "backend": str}estimate_depth_at_bbox(frame, bbox) → float
spatial_relations.py — 空間関係抽出
get_spatial_relation(obj_a, obj_b, depth_a, depth_b) → str- 戻り値:
left_of / right_of / above / below / in_front_of / behind / near / touching / unknown extract_pairwise_relations(detections, depth_maps) → [{"subject_id", "object_id", "relation", "confidence"}, ...]MotionVectorEstimator— トラック履歴から速度ベクトル・方向を付加
narrative_generator.py — ナラティブ生成
NarrativeGenerator(use_lm, max_events, min_confidence).generate(timeline) → str- テンプレートモード(デフォルト):
"At {ts}s, {actor} is detected {action} (confidence {conf}%)" - LM モード:
NeuralLanguageAdapter経由で EvoSpikeNet LM を呼び出し、失敗時はテンプレートにフォールバック generate_shot_summary(shot_start, shot_end, events, relations) → str
temporal_action_localizer.py — 時系列行動ローカリゼーション
TemporalActionLocalizer(window_size, stride, min_confidence, nms_overlap_threshold)localize(frames, fps) → [{"start", "end", "action", "confidence"}, ...]localize_with_poses(frames, pose_results, fps) → [...]— キーポイント変化量ベース- Temporal IoU NMS で重複除去
VideoAnalysisPipeline 更新内容
pipeline = VideoAnalysisPipeline(
pose_backend="fallback",
action_backend="fallback",
asr_backend="fallback",
depth_backend="fallback",
)
result = pipeline.run(frames, audio_wave, fps=10.0, enable_extended=True)
# result には以下が追加:
# shot_boundaries, vad_segments, temporal_segments,
# depth_sample, spatial_relations, narrative
テスト状況
| テストファイル | テスト数 | 状態 |
|---|---|---|
tests/unit/test_video_analysis_new_modules.py |
62 | ✅ 全通過 |
tests/unit/test_video_analysis_components.py |
15 | ✅ 全通過 |
tests/unit/test_video_analysis_metrics.py |
1 | ✅ 全通過 |
tests/unit/test_video_analysis_backends.py |
1 | ✅ 全通過 |
| 合計 | 82 | ✅ |
EvoSpikeNet LM バックエンドへの切り替えガイド(2026-04-24)
パイプラインには 2 つの独立した LM 経路 があります。
経路 A: lm_summary(パイプライン全体の要約)
VideoAnalysisPipeline.run() が返す lm_summary キー。
EvoLMBackend → AutoModelSelector.get_model("text") → SpikingEvoTextLM を使用します。
制御方法
| 方法 | 設定例 | 効果 |
|---|---|---|
| コンストラクタ引数 | VideoAnalysisPipeline(lm_backend="evospikenet_lm") |
デフォルト。SpikingEvoTextLM を使用 |
| 環境変数で無効化 | VIDEO_ANALYSIS_ENABLE_LM=0 |
lm_summary="", lm_backend=None になる |
| 環境変数で有効化 | VIDEO_ANALYSIS_ENABLE_LM=1 (デフォルト) |
LM を起動して要約を生成 |
import os
os.environ["VIDEO_ANALYSIS_ENABLE_LM"] = "1" # または "0" で無効化
from evospikenet.video_analysis.pipeline import VideoAnalysisPipeline
pipeline = VideoAnalysisPipeline(lm_backend="evospikenet_lm")
result = pipeline.run(frames, audio_wave, fps=25.0)
print(result["lm_summary"]) # "人物が歩いています。" など
print(result["lm_backend"]) # "evospikenet_lm"
バックエンドスタック(経路 A)
pipeline.run()
└─ EvoLMBackend.generate(prompt, max_new_tokens=40, temperature=0.6)
└─ AutoModelSelector.get_model("text")
└─ SpikingEvoTextLM.generate(input_ids, max_new_tokens)
経路 B: narrative(時系列ナラティブ生成)
pipeline.run(enable_extended=True) 時の narrative キー。
NarrativeGenerator → _LMBridge → EvoLMBackend → SpikingEvoTextLM を使用します。
動作フロー
NarrativeGenerator.generate(timeline)
├─ テンプレート文を組み立て (事前計算)
├─ use_lm=True の場合: _LMBridge.generate(prompt, max_new_tokens=200)
│ └─ EvoLMBackend.generate(prompt, max_new_tokens=200)
│ └─ SpikingEvoTextLM.generate(...)
└─ LM 出力が 20 文字未満 or None → テンプレートフォールバック
制御方法
| 方法 | 設定例 | 効果 |
|---|---|---|
| デフォルト(推奨) | NarrativeGenerator(use_lm=True) |
LM 優先、失敗時テンプレート |
| LM 無効化 | NarrativeGenerator(use_lm=False) |
常にテンプレート |
| パイプライン経由 | VideoAnalysisPipeline() |
use_lm=True がデフォルト設定済み |
from evospikenet.video_analysis.narrative_generator import NarrativeGenerator
# LM を使ったナラティブ生成
gen = NarrativeGenerator(use_lm=True, max_events=15, min_confidence=0.3)
text = gen.generate(timeline)
print(text)
# ショット単位の要約
shot_text = gen.generate_shot_summary(
shot_start=0.0, shot_end=5.0,
events=timeline.filter_by_confidence(0.5),
relations=[{"subject_id": 0, "object_id": 1, "relation": "left_of", "confidence": 0.8}],
)
バックエンド可用性の確認
from evospikenet.video_analysis.backends import get_backend_status
status = get_backend_status()
print(status["lm"])
# {'evospikenet_lm': {'available': True, 'tier': 'real',
# 'note': 'local SpikingEvo models via AutoModelSelector'}}
よくある問題と対処
| 症状 | 原因 | 対処 |
|---|---|---|
lm_summary が空文字 |
VIDEO_ANALYSIS_ENABLE_LM=0 が設定されている |
環境変数を 1 に変更 |
narrative がテンプレート文になる |
_LMBridge のロード失敗 |
torch インストール確認 (pip install torch) |
lm_backend が None |
EvoLMBackend 初期化失敗(依存ライブラリ不足) |
pip install torch transformers |
| LM 出力が短すぎる/意味不明 | SpikingEvoTextLM が未学習状態 |
学習済みモデルで AutoModelSelector のウェイトを差し替える |
ウェイト差し替えとモデルカスタマイズ
SpikingEvoTextLM は AutoModelSelector.get_model("text") でロードされます。
学習済みウェイトを使いたい場合は tools/train_spiking_lm.py で事前学習してください。
# 学習
python tools/train_spiking_lm.py --node-type text --epochs 10
# 推論確認
python -c "
from evospikenet.llm_backend import EvoLMBackend
lm = EvoLMBackend(task_type='text')
print(lm.generate('Events: walking:3. 日本語で一文で要約してください。', max_new_tokens=40))
"
残課題(Phase 4)
| 機能 | 優先度 | 担当モジュール |
|---|---|---|
| ByteTrack/DeepSORT 本番 MOT | 高 | tracking.py / backends.py |
| MediaPipe/OpenPose 本番ポーズ | 高 | MoveNetRealPoseBackend |
| TimeSformer/SlowFast 実モデル | 高 | STGCNRealActionBackend |
| pyannote.audio 話者分離 | 中 | vad.py (SpeakerDiarizer) |
| SAM/Mask R-CNN セグメンテーション | 中 | 新規モジュール予定 |
| TensorRT/ONNX GPU 最適化 | 中 | backends.py |
| WebSocket リアルタイム API | 低 | video_analysis_api.py |
| アノテーション UI | 低 | 別ツール |
作成日: 2026-04-19 更新日: 2026-04-24 作成者: エンジニアリングチーム