Add: DGX Spark GUI操作動画解析システム記事
All checks were successful
Deploy Docusaurus Site / deploy (push) Successful in 30s
All checks were successful
Deploy Docusaurus Site / deploy (push) Successful in 30s
This commit is contained in:
parent
ff80970be0
commit
4ed1849c3a
295
docs-tech/dgx-spark-video-analyzer/index.md
Normal file
295
docs-tech/dgx-spark-video-analyzer/index.md
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: DGX SparkでGUI操作動画解析システムを作る
|
||||||
|
description: NVIDIA DGX SparkでQwen3-VLとLanceDBを使ったGUI操作動画解析システムの構築方法
|
||||||
|
hide_table_of_contents: false
|
||||||
|
displayed_sidebar: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# DGX Sparkで作る!GUI操作動画解析システム
|
||||||
|
|
||||||
|
Qwen3-VL + LanceDBでサーバー設定作業を自動ドキュメント化
|
||||||
|
|
||||||
|
## はじめに
|
||||||
|
|
||||||
|
サーバーの設定作業をGUIで行う場面、意外と多いですよね。WebUIでの管理画面操作、設定ウィザードの実行...。後から「あの時どう設定したっけ?」と振り返りたいことがあります。
|
||||||
|
|
||||||
|
この記事では、**NVIDIA DGX Spark**を使って、GUI操作の録画動画から設定内容を自動抽出し、検索・マニュアル生成ができるシステムを構築します。
|
||||||
|
|
||||||
|
### 作るもの
|
||||||
|
|
||||||
|
- **入力**: GUI操作を録画したMP4動画
|
||||||
|
- **処理**: フレーム抽出 → VLMで画面解析 → ベクトルDB格納
|
||||||
|
- **出力**: 設定値の検索、操作手順のマニュアル生成
|
||||||
|
|
||||||
|
### 使用技術
|
||||||
|
|
||||||
|
| コンポーネント | 技術 |
|
||||||
|
|---------------|------|
|
||||||
|
| ハードウェア | NVIDIA DGX Spark (128GB統合メモリ) |
|
||||||
|
| VLM | Qwen3-VL 8B (Ollama) |
|
||||||
|
| フレーム抽出 | OpenCV + SSIM |
|
||||||
|
| ベクトルDB | LanceDB |
|
||||||
|
| WebUI | Gradio |
|
||||||
|
|
||||||
|
## DGX Sparkとは
|
||||||
|
|
||||||
|
NVIDIA DGX Sparkは、デスクトップサイズの「AIスーパーコンピュータ」です。
|
||||||
|
|
||||||
|
### スペック
|
||||||
|
|
||||||
|
| 項目 | 仕様 |
|
||||||
|
|------|------|
|
||||||
|
| CPU | ARM64 20コア (Cortex-X925 x10 + Cortex-A725 x10) |
|
||||||
|
| GPU | NVIDIA GB10 (Blackwell) - 6144 CUDA Cores |
|
||||||
|
| メモリ | 128GB 統合メモリ (CPU/GPU共有) |
|
||||||
|
| OS | Ubuntu 24.04 LTS |
|
||||||
|
|
||||||
|
### 開発上のポイント
|
||||||
|
|
||||||
|
1. **統合メモリアーキテクチャ (UMA)**: CPUとGPUがメモリを共有。大規模モデルが載りやすい
|
||||||
|
2. **ARM64**: x86のwheelは使えない。ARM64ビルドを使用
|
||||||
|
3. **Ollama対応**: すぐ動く。公式サポート済み
|
||||||
|
|
||||||
|
## システム構成
|
||||||
|
|
||||||
|
```
|
||||||
|
GUI操作動画(MP4)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
① フレーム抽出 (OpenCV + SSIM)
|
||||||
|
│ 画面変化を検出し重要フレームのみ抽出
|
||||||
|
▼
|
||||||
|
② Qwen3-VL 8B (Ollama)
|
||||||
|
│ 各フレームの画面内容を解析
|
||||||
|
│ 設定項目・値・操作内容を抽出
|
||||||
|
▼
|
||||||
|
③ LanceDB
|
||||||
|
│ 解析結果をベクトルインデックス化
|
||||||
|
▼
|
||||||
|
④ Gradio WebUI
|
||||||
|
└─ 検索・マニュアル生成
|
||||||
|
```
|
||||||
|
|
||||||
|
## 環境構築
|
||||||
|
|
||||||
|
### 前提条件
|
||||||
|
|
||||||
|
- DGX Sparkにssh接続可能
|
||||||
|
- Ollamaインストール済み
|
||||||
|
|
||||||
|
### セットアップ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# プロジェクトディレクトリ作成
|
||||||
|
mkdir -p ~/projects/video-config-analyzer
|
||||||
|
cd ~/projects/video-config-analyzer
|
||||||
|
|
||||||
|
# 仮想環境作成
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# 依存パッケージインストール
|
||||||
|
pip install opencv-python-headless gradio lancedb sentence-transformers \
|
||||||
|
pillow pyyaml requests numpy tqdm scikit-image pyarrow
|
||||||
|
|
||||||
|
# Qwen3-VLモデル取得(未取得の場合)
|
||||||
|
ollama pull qwen3-vl:8b-instruct
|
||||||
|
```
|
||||||
|
|
||||||
|
## 実装解説
|
||||||
|
|
||||||
|
### 1. フレーム抽出 (frame_extractor.py)
|
||||||
|
|
||||||
|
動画から「画面が変化した」フレームのみを抽出します。
|
||||||
|
|
||||||
|
```python
|
||||||
|
from skimage.metrics import structural_similarity as ssim
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
def extract_keyframes(video_path, threshold=0.95):
|
||||||
|
"""SSIMで画面変化を検出し、変化があったフレームのみ抽出"""
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
prev_frame = None
|
||||||
|
keyframes = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
|
||||||
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
if prev_frame is None:
|
||||||
|
keyframes.append(frame)
|
||||||
|
prev_frame = gray
|
||||||
|
continue
|
||||||
|
|
||||||
|
# SSIM計算
|
||||||
|
score = ssim(prev_frame, gray)
|
||||||
|
if score < threshold: # 変化検出
|
||||||
|
keyframes.append(frame)
|
||||||
|
prev_frame = gray
|
||||||
|
|
||||||
|
return keyframes
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip ポイント
|
||||||
|
SSIM (Structural Similarity Index) を使うことで、わずかなノイズに反応せず、実際の画面遷移のみを検出できます。
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 2. VLM解析 (vlm_analyzer.py)
|
||||||
|
|
||||||
|
Ollama経由でQwen3-VLを呼び出し、画面内容を解析します。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def analyze_frame(image_path, ollama_url="http://localhost:11434"):
|
||||||
|
"""フレームをVLMで解析し、設定情報を抽出"""
|
||||||
|
with open(image_path, "rb") as f:
|
||||||
|
image_b64 = base64.b64encode(f.read()).decode()
|
||||||
|
|
||||||
|
prompt = """この画像はサーバー設定画面です。以下をJSON形式で抽出:
|
||||||
|
{
|
||||||
|
"screen_title": "画面タイトル",
|
||||||
|
"visible_settings": [{"name": "設定名", "value": "値", "type": "タイプ"}],
|
||||||
|
"buttons_visible": ["ボタン名リスト"],
|
||||||
|
"current_action": "操作の説明"
|
||||||
|
}"""
|
||||||
|
|
||||||
|
response = requests.post(f"{ollama_url}/api/generate", json={
|
||||||
|
"model": "qwen3-vl:8b-instruct",
|
||||||
|
"prompt": prompt,
|
||||||
|
"images": [image_b64],
|
||||||
|
"stream": False
|
||||||
|
})
|
||||||
|
|
||||||
|
return response.json()["response"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. インデックス化 (indexer.py)
|
||||||
|
|
||||||
|
LanceDBで解析結果をベクトル化して保存。後から自然言語で検索可能に。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import lancedb
|
||||||
|
from sentence_transformers import SentenceTransformer
|
||||||
|
|
||||||
|
class VideoIndexer:
|
||||||
|
def __init__(self, db_path="./data/lancedb"):
|
||||||
|
self.db = lancedb.connect(db_path)
|
||||||
|
self.embedder = SentenceTransformer("all-MiniLM-L6-v2")
|
||||||
|
|
||||||
|
def index(self, analysis_results, video_id):
|
||||||
|
"""解析結果をベクトルインデックスに追加"""
|
||||||
|
entries = []
|
||||||
|
for result in analysis_results:
|
||||||
|
text = f"{result['screen_title']} {result['current_action']}"
|
||||||
|
vector = self.embedder.encode(text).tolist()
|
||||||
|
entries.append({
|
||||||
|
"video_id": video_id,
|
||||||
|
"text": text,
|
||||||
|
"vector": vector,
|
||||||
|
**result
|
||||||
|
})
|
||||||
|
|
||||||
|
table = self.db.create_table("video_analysis", entries, mode="overwrite")
|
||||||
|
return len(entries)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. WebUI (web_ui.py)
|
||||||
|
|
||||||
|
Gradioで直感的なインターフェースを提供。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import gradio as gr
|
||||||
|
|
||||||
|
def create_ui(pipeline):
|
||||||
|
with gr.Blocks(title="Video Config Analyzer") as app:
|
||||||
|
gr.Markdown("# GUI操作動画解析システム")
|
||||||
|
|
||||||
|
with gr.Tab("動画解析"):
|
||||||
|
video_input = gr.File(label="動画ファイル (MP4)")
|
||||||
|
analyze_btn = gr.Button("解析開始")
|
||||||
|
status = gr.Textbox(label="ステータス")
|
||||||
|
|
||||||
|
with gr.Tab("検索"):
|
||||||
|
query = gr.Textbox(label="検索クエリ")
|
||||||
|
search_btn = gr.Button("検索")
|
||||||
|
results = gr.Dataframe()
|
||||||
|
|
||||||
|
with gr.Tab("マニュアル生成"):
|
||||||
|
video_select = gr.Dropdown(label="動画選択")
|
||||||
|
generate_btn = gr.Button("生成")
|
||||||
|
manual_output = gr.Markdown()
|
||||||
|
|
||||||
|
return app
|
||||||
|
```
|
||||||
|
|
||||||
|
## WebUIの起動
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/projects/video-config-analyzer
|
||||||
|
source venv/bin/activate
|
||||||
|
python app/web_ui.py
|
||||||
|
```
|
||||||
|
|
||||||
|
WebUIは http://localhost:7860 でアクセスできます。
|
||||||
|
|
||||||
|
## トラブルシューティング
|
||||||
|
|
||||||
|
### Q: Ollamaが応答しない
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ollamaサービス確認
|
||||||
|
systemctl status ollama
|
||||||
|
|
||||||
|
# モデル確認
|
||||||
|
ollama list | grep qwen3-vl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: メモリ不足エラー
|
||||||
|
|
||||||
|
DGX Sparkの統合メモリを活用するため、他のプロセスを停止して試してください。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# GPU使用状況確認
|
||||||
|
nvidia-smi
|
||||||
|
|
||||||
|
# 不要なプロセス停止
|
||||||
|
pkill -f "python.*some_heavy_process"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: ARM64用パッケージが見つからない
|
||||||
|
|
||||||
|
一部のPyPIパッケージはARM64用wheelがない場合があります。その場合はソースからビルド:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install --no-binary :all: パッケージ名
|
||||||
|
```
|
||||||
|
|
||||||
|
## まとめ
|
||||||
|
|
||||||
|
DGX Sparkの統合メモリアーキテクチャは、VLMを使った画像解析タスクに最適です。128GBの大容量メモリにより、8Bパラメータのモデルも余裕で動作します。
|
||||||
|
|
||||||
|
このシステムを使えば、GUI操作の録画を後から検索可能なドキュメントに変換できます。
|
||||||
|
|
||||||
|
### 今後の改善案
|
||||||
|
|
||||||
|
- **OmniParser V2の統合**: GUI要素の検出精度向上
|
||||||
|
- **バッチ処理**: 複数動画の一括処理
|
||||||
|
- **差分検出の高度化**: 動的なコンテンツの除外
|
||||||
|
|
||||||
|
## 参考リンク
|
||||||
|
|
||||||
|
- [NVIDIA DGX Spark](https://www.nvidia.com/en-us/products/workstations/dgx-spark/)
|
||||||
|
- [Qwen3-VL](https://github.com/QwenLM/Qwen-VL)
|
||||||
|
- [LanceDB](https://lancedb.github.io/lancedb/)
|
||||||
|
- [Gradio](https://gradio.app/)
|
||||||
|
- [Python on NVIDIA DGX Spark: First Impressions (Anaconda)](https://www.anaconda.com/blog/python-nvidia-dgx-spark-first-impressions)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*この記事は2026年2月時点の情報です。*
|
||||||
Loading…
x
Reference in New Issue
Block a user