gsplat-optimizer について
gsplat-optimizerは、Appleプラットフォームで3D Gaussian Splattingシーンをリアルタイム描画するための最適化スキルです。デバイスやフレームレートの目標に応じて、プルーニング、LOD、圧縮、Metalのプロファイリングを支援します。
主な機能
- 01スプラット数とメモリの分析
- 02プルーニング方式の提案
- 03LOD方式の設計
- 04データ圧縮の提案
- 05Metalプロファイリングのガイド
活用シーン
- 01iPhone向けに.plyや.splatシーンを準備
- 02GPU予算に合わせてシーンを縮小
- 03大規模シーンにLODを追加
- 04Metalの描画性能を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ckorhonen/ claude-skills --skill gsplat-optimizerインストール後、Claude Code で/gsplat-optimizerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/compression.mdlod-schemes.mdmetal-profiling.mdpruning-strategies.mdscripts/analyze_splat.py詳細
Gaussian Splat Optimizer
Metal を使用して、Apple プラットフォーム(iOS、macOS、visionOS)でリアルタイムレンダリングを行うために、3D Gaussian Splatting シーンを最適化します。
使用する場面
- モバイル/Apple GPU を対象に
.plyまたは.splatファイルを最適化する場合 - パフォーマンス向上のためにガウシアン数を減らす場合(プルーニング戦略)
- 大規模なシーンに Level-of-Detail(LOD)を実装する場合
- 帯域幅/ストレージの制約に合わせてスプラットデータを圧縮する場合
- Metal のレンダリングパフォーマンスをプロファイリング、最適化する場合
- Apple ハードウェアで特定の FPS 目標を達成する場合
クイックスタート
入力:.ply/.splat ファイルのパス、対象デバイスのクラス、FPS の目標を指定します。
# Analyze a splat file
python ~/.claude/skills/gsplat-optimizer/scripts/analyze_splat.py scene.ply --device iphone --fps 60
出力:このスキルでは、以下を提供します。
- 点/ガウシアンのプルーニング計画(不透明度、サイズ、誤差のしきい値)
- LOD 方式の提案(距離区分、ガウシアンのサブセット)
- 圧縮の推奨(帯域幅/ストレージが制約となる場合)
- シェーダー/コンピュートのヒントを含む Metal プロファイリングのチェックリスト
最適化ワークフロー
ステップ 1:シーンを分析する
まず、シーンの特性を把握します。
- ガウシアン数:スプラットの総数
- 不透明度の分布:不透明度値のヒストグラム
- サイズの分布:ガウシアンのスケール統計
- メモリ使用量:推定 GPU メモリ使用量
ステップ 2:対象デバイスを決める
| デバイスクラス | GPU 予算 | 最大ガウシアン数(60fps) | ストレージモード |
|---|---|---|---|
| iPhone(A15 以降) | 4-6GB ユニファイドメモリ | 約 2-4M | Shared |
| iPad Pro(M1 以降) | 8-16GB ユニファイドメモリ | 約 6-8M | Shared |
| Mac(M1-M3) | 8-24GB ユニファイドメモリ | 約 8-12M | Shared/Managed |
| Vision Pro | 16GB ユニファイドメモリ | 約 4-6M(ステレオ) | Shared |
| Mac(ディスクリート GPU) | 8-24MGB VRAM | 約 10-15M | Private |
ステップ 3:プルーニングを適用する
ガウシアン数がデバイスの予算を超える場合:
- 不透明度のしきい値:不透明度が 0.01-0.05 未満のガウシアンを削除します
- サイズによるカリング:サブピクセルのガウシアン(対象解像度で 1px 未満)を削除します
- 重要度に基づくプルーニング:誤差プロキシによる選択に LODGE アルゴリズムを使用します
- フォービエイテッドレンダリング:Vision Pro では、周辺視野の密度を下げます
詳細は references/pruning-strategies.md を参照してください。
ステップ 4:LOD を実装する(大規模なシーン)
シーンが単一フレームの予算を超える場合:
- 距離区分:近距離(0-10m)、中距離(10-50m)、遠距離(50m 以上)
- 階層構造:空間クエリにオクトツリーまたは LoD ツリーを使用します
- チャンクストリーミング:カメラ位置に応じて読み込み/読み込み解除を行います
- 滑らかな遷移:チャンクの境界で不透明度をブレンドします
詳細は references/lod-schemes.md を参照してください。
ステップ 5:圧縮を適用する(必要な場合)
帯域幅/ストレージの制約がある場合:
| 方法 | 圧縮率 | 用途 |
|---|---|---|
| SOGS | 20x | Web 配信、中程度の品質 |
| SOG | 24x | Web 配信、より高い品質 |
| CodecGS | 30x 以上 | 最大限の圧縮 |
| C3DGS | 31x | 高速レンダリングを優先 |
詳細は references/compression.md を参照してください。
ステップ 6:Metal をプロファイリングして最適化する
- ストレージモードを選択する:静的データには Private、動的データには Shared を使用します
- シェーダーを最適化する:関数定数、スレッド占有率
- Xcode でプロファイリングする:GPU Frame Capture、Metal System Trace
- 繰り返す:測定し、最適化し、再度測定します
詳細は references/metal-profiling.md を参照してください。
よくある落とし穴
1. 点群の密度が適切でない
問題: ガウシアン数がシーンの複雑さに合っておらず、視覚的なアーティファクトが発生したり、GPU リソースが無駄になったりします。
- 少なすぎる(アンダーサンプリング): 目に見える隙間、ブロック状の表示、細部の消失
- 多すぎる(オーバーサンプリング): デバイスの予算を超過し、フレーム落ちや GPU の過負荷を引き起こします
デバッグ:
# Analyze gaussian distribution
python ~/.claude/skills/gsplat-optimizer/scripts/analyze_splat.py scene.ply --histogram
# Check against device budget
# Compare total_gaussians vs. device_max in the output table
方針:
- ステップ 2 のデバイス予算を基準に始めます(例:iPhone では 4M)
- シーンが予算を 20% 超えている場合は、トレーニング前にプルーニングを適用します
- プルーニング後に視覚品質が大きく低下する場合は、LOD またはチャンク分割を検討します
- 不透明なガウシアンだけでなく、寄与の小さいガウシアンを削除するために、重要度で重み付けしたサンプリング(LODGE)を使用します
2. トレーニングの不安定性(勾配爆発、発散)
問題: 最適化中(デバイス上でファインチューニングする場合)に、ガウスパラメーターが発散し、次の問題が発生します。
- 損失が突然 NaN になる
- ガウスが消失する、またはスケールが極端に大きくなる
- セッションの途中でモデルを復旧できなくなる
デバッグ:
# Monitor loss during training
tail -f training.log | grep -E "loss|nan|inf"
# Check gradient magnitudes
python -c "
import numpy as np
from plyfile import PlyData
ply_data = PlyData.read('scene.ply')
scales = ply_data['vertex']['scale_0'].data
print(f'Scale range: {scales.min():.6f} to {scales.max():.6f}')
print(f'Any NaN: {np.isnan(scales).any()}')
"
対策:
- 勾配クリッピング: 1ステップあたりの勾配更新をスケール±0.1に制限します
- 学習率の減衰: 1e-4から開始し、エポックごとに0.95を乗じて減衰させます
- 損失の正則化: スケールの大きさにL2ペナルティを加え、爆発を防ぎます
- 早めにチェックポイントを保存: 10回のイテレーションごとに状態を保存し、損失が急上昇したらロールバックします
- 共分散を固定: 収束した場合、トレーニングの80%を過ぎたらスケールと回転の更新を停止します
- デバイスでのトレーニングの場合: 不安定さが続く場合は、バッチサイズまたは解像度を下げます
3. メモリの制限(大規模シーンでのOOMエラー)
問題: シーンが利用可能なユニファイドメモリの容量を超え、割り当ての失敗やGPUの停止が発生します。
- iPhone:アプリとGPUで共有する4~6GB
- iPad Pro:共有する8~16GB
- Vision Pro:16GB(ただし、ステレオではガウス数が2倍になります)
デバッグ:
# Estimate memory footprint
python << 'EOF'
num_gaussians = 5_000_000 # Your count
bytes_per_gaussian = 56 # pos (12) + scale (12) + rot quaternion (16) + opacity (4) + SH DC (12)
total_mb = (num_gaussians * bytes_per_gaussian) / (1024 ** 2)
print(f"Est. memory: {total_mb:.1f} MB")
print(f"Safe for iPhone A15: {total_mb < 2000}") # Leave headroom for app
EOF
# Monitor live memory in Xcode
# Memory graph + Allocations instrument during scene load
対策:
- 大規模シーンのチャンク化: 1~4M個のガウスに分割し、カメラからの距離に応じてストリーミングします
- 量子化: ガウスをFP32ではなくFP16で格納し、メモリ使用量を2分の1にします
- 先にプルーニング: デバイスに転送する前に、不透明度が0.01未満またはサブピクセルのガウスを削除します
- 遅延読み込み: アクティブなLODレベルのみをメモリに保持し、遠方のチャンクをアンロードします
- Vision Proでの考慮事項: 両眼レンダリングではガウス数が2倍になるため、片目あたり4M個を上限にします
4. 品質と速度のトレードオフ(単一指標への過剰最適化)
問題: ある指標に偏って最適化すると、別の指標に悪影響が出ます。
- FPSの最大化 → 視覚的なアーティファクト: 過剰なプルーニングによって重要なジオメトリが削除されます
- 品質の最大化 → フレーム落ち: 対象デバイスに対してガウスが多すぎます
- メモリの最小化 → バンディング/ポスタリゼーション: 過剰な量子化やLODカリングが発生します
デバッグ:
# Profile before/after each change
python << 'EOF'
metrics = {
"original": {"fps": 60, "gaussians": 5_000_000, "artifacts": "none"},
"after_pruning": {"fps": 58, "gaussians": 3_500_000, "artifacts": "block edges visible"},
}
for label, m in metrics.items():
print(f"{label}: {m['fps']}fps, {m['gaussians']/1e6:.1f}M, {m['artifacts']}")
EOF
対策:
- 優先事項を定義する: このデバイスでは速度が重要(AR、リアルタイム)ですか、それとも品質重視(プレビュー)ですか?
- ベースラインを測定する: まず、最適化していない元のシーンをプロファイリングします
- 段階的に反復する: 最適化を1つ(プルーニング、圧縮、LODのいずれか)適用し、測定して判断します
- 品質指標を維持する: PSNR/SSIMのスコアを記録し、品質が1dBを超えて低下したらプルーニングを停止します
- 目標範囲: 50~60fpsの余裕を目指します(ちょうど60fpsまで上げきらないでください。デバイスがスロットリングします)
5. リアルタイムレンダリングの失敗(フレーム落ち、シェーダーのコンパイル)
問題: ガウス数が少ないにもかかわらず、レンダリングパイプラインが停止します。
- 最初のフレーム(コールドスタート):シェーダーのコンパイル中に2~5秒の遅延が発生します
- シーンの途中:新しいLODレベルの読み込み時にフレーム落ちが急増します
- スムーズな再生が、30~60秒後にカクつくようになります
デバッグ:
# Capture Metal frame statistics
# In Xcode: Product > Scheme > Edit > Run > Diagnostics
# Enable: Metal API Validation, GPU Frame Capture
# Check shader compilation time
python ~/.claude/skills/gsplat-optimizer/scripts/metal_profile.py \
--capture-shader-compile \
--target iphone14
# Monitor frame time distribution
tail -f xcode.log | grep -E "frame_time|stutter"
対策:
- シェーダーキャッシュを事前にウォームアップする: 初回読み込み時にすべての関数バリアントをコンパイルし、実行時のカクつきを防ぎます
- LODの遷移を制限する: 複数のLODレベルを使う場合、1フレームあたりの遷移を2回までに制限します
- 非同期ストリーミング: 新しいジオメトリチャンクをバックグラウンドスレッドで読み込み、フレーム間でアップロードします
- デバイスごとの調整:
- iPhone:ドローコールを50未満、コールあたりのジオメトリを500K個未満のガウスに保ちます
- Mac:より余裕があります。ドローコールあたり2M個未満のガウスを目指します
- Vision Pro:ステレオを考慮します。有効容量は予算の半分です
- プロファイリングの手順: 最適化の前後にMetal System Traceを実行し、次の項目を追跡します。
- GPU使用率(目標:70~85%)
- シェーダー時間(目標:10ms未満)
- メモリ帯域幅(目標:50GB/s未満)
主な指標
| 指標 | 目標 | 測定方法 |
|---|---|---|
| フレーム時間 | 16.6ms(60fps) | Metal System Trace |
| GPUメモリ | デバイスの予算未満 | Xcode Memory Graph |
| 帯域幅 | 50GB/s未満 | GPU Counters |
| シェーダー時間 | 10ms未満 | GPU Frame Capture |
リファレンス実装
MetalSplatterは、Swift/Metal のガウススプラッティングにおける主要なリファレンスです。
- リポジトリ:https://github.com/scier/MetalSplatter
- iOS、macOS、visionOS に対応
- v1.1 の最適化により、約 8M のスプラットを処理可能
- Vision Pro 向けのステレオレンダリング
MetalSplatter を使い始める
git clone https://github.com/scier/MetalSplatter.git
cd MetalSplatter
open SampleApp/MetalSplatter_SampleApp.xcodeproj
# Set to Release scheme for best performance
リソース
リファレンスドキュメント
- プルーニング戦略 - ガウス要素の削減手法
- LOD 方式 - 詳細度のアプローチ
- 圧縮 - 帯域幅/ストレージの最適化
- Metal のプロファイリング - Apple GPU の最適化
研究論文
- LODGE - 大規模シーン向け LOD
- FLoD - ハードウェアの違いに対応する柔軟な LOD
- Voyager - 都市規模のモバイルレンダリング
- 3DGS 圧縮サーベイ