Skip to content

yujiteshima/mruby-gpu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mruby-gpu

mruby から Raspberry Pi 5 の GPU(VideoCore VII / Vulkan 1.2)を利用するための mrbgem です。
カメラキャプチャ・GPU顔認識・リアルタイムプレビューをたった数十行の mruby スクリプトで実現します。

ドキュメント

ファイル 内容
docs/PERFORMANCE.md ボトルネック分析と高速化アイデア
docs/GPU_VS_CPU_ANALYSIS.md GPU vs CPU 推論の比較調査・なぜ V3D で遅いのか
docs/MINIBATCH_PLAN.md MNIST ミニバッチ化計画・GPU 高速化ロードマップ
docs/BATCH_INFERENCE_PLAN.md 録画→バッチ推論パイプライン計画
docs/LT_SCRIPT.md LT 発表スクリプト(台本・デモ手順)

機能

クラス 概要
GPU Vulkan Compute Shader によるベクトル演算・行列演算
Camera V4L2 経由のカメラキャプチャ(USB / CSI カメラ対応)
FaceDetector NCNN + Vulkan による GPU 顔検出(UltraFace-slim モデル)
Display SDL2 ウィンドウへのリアルタイム表示・枠描画

動作環境

  • ボード: Raspberry Pi 5
  • OS: Ubuntu 24.04 (arm64)
  • GPU: VideoCore VII(V3D 7.1)— Vulkan 1.2 対応
  • カメラ: USB Webカメラ(UVC準拠、例: Logitech C920)

依存関係のインストール

# Vulkan / SDL2 / ビルドツール
sudo apt install -y libvulkan-dev vulkan-tools libsdl2-dev cmake build-essential git

# NCNN (GPU 推論フレームワーク) — ソースからビルド
git clone --depth=1 https://github.com/Tencent/ncnn.git ~/ncnn
cd ~/ncnn
git submodule update --init --depth=1
mkdir build && cd build
cmake \
  -DNCNN_VULKAN=ON \
  -DNCNN_BUILD_EXAMPLES=OFF \
  -DNCNN_BUILD_TOOLS=OFF \
  -DNCNN_BUILD_BENCHMARK=OFF \
  -DNCNN_BUILD_TESTS=OFF \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr/local \
  ..
make -j1          # メモリ不足防止のため -j1 推奨(RAM 2GB 環境)
sudo make install

注意: Raspberry Pi 5 (RAM 2GB) では -j4 でビルドするとフリーズします。
事前にスワップを追加してください:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

セットアップ

1. モデルのダウンロード

cd /home/ubuntu/work/mruby-gpu
mkdir -p models
wget "https://raw.githubusercontent.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/master/ncnn/data/version-slim/slim_320.param" \
     -O models/ultraface-slim.param
wget "https://raw.githubusercontent.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/master/ncnn/data/version-slim/slim_320.bin" \
     -O models/ultraface-slim.bin

2. シェーダーのコンパイル

cd shader
make
cd ..

3. mruby のビルド

cd /home/ubuntu/work/mruby
rake MRUBY_CONFIG=gpu

ビルドが成功すると build/host/bin/mruby が生成されます。


LT デモ用コマンド

以下を順番に実行すると LT のストーリーに沿ったデモになります。

cd /home/ubuntu/work/mruby-gpu
MRUBY=/home/ubuntu/work/mruby/build/host/bin/mruby

Step 1: GPU で一発計算(mruby から GPU を叩けることを見せる)

$MRUBY -e 'GPU.init("shader"); a = GPU.array([1.0, 2.0, 3.0]); b = GPU.array([10.0, 20.0, 30.0]); puts GPU.add(a, b).head(3).inspect'
[11.0, 22.0, 33.0]

Step 2: 100 万要素の GPU ベクトル加算(GPU の並列計算力を見せる)

$MRUBY examples/demo.rb
1,000,000 elements x 5 runs  Avg: 5.06 ms

Step 3: カメラ + 顔認識 — GPU モード(GPU 推論を見せる)

DISPLAY=:0 $MRUBY examples/face_demo.rb fast gpu

/dev/dri の権限エラーが出る場合(video / render グループ未反映時):

sg video -c "sg render -c 'DISPLAY=:0 /home/ubuntu/work/mruby/build/host/bin/mruby examples/face_demo.rb fast gpu'"

→ ~6 FPS で動く。「GPU で顔認識が動いた!」

Step 4: カメラ + 顔認識 — CPU モード(適材適所を見せる)

DISPLAY=:0 $MRUBY examples/face_demo.rb fast cpu

権限エラーが出る場合:

sg video -c "sg render -c 'DISPLAY=:0 /home/ubuntu/work/mruby/build/host/bin/mruby examples/face_demo.rb fast cpu'"

~30 FPS で動く。 「小さなモデルは CPU NEON が得意。使い分けられるのが mruby-gpu の強み。」

ESC キーまたはウィンドウの × ボタンで停止します。

モード一覧

引数1 引数2 速度 検出距離 用途
fast cpu 30 FPS ~3m デモ・プレゼン
fast gpu 6 FPS ~3m GPU 推論デモ
count cpu 20 FPS ~7m 会場の人数カウント
count gpu 1 FPS ~7m GPU + タイル処理

タイル処理の仕組み(count モード):
640×480 の画像を 320×240 の5タイルに分割して各タイルを個別に推論することで、
実効解像度を2倍にして遠距離の小さな顔(17px → 34px)を検出可能にしています。

[全体] + [左上] + [右上] + [左下] + [右下] + [中央] = 6回推論 / フレーム
       ↑ 各タイルは元画像の1/4領域 = モデル入力と同サイズで2倍ズーム相当

操作方法

操作 動作
ESC キー デモを終了してサマリーを表示
ウィンドウの × ボタン デモを終了してサマリーを表示
Ctrl+C(ターミナル) 強制終了(サマリーは表示されません)

終了時のサマリー表示例

====================================================
  終了サマリー
  総フレーム数 : 300
  最大同時検出 : 5 人
  平均処理時間 : 165.0 ms/frame  (6.1 FPS)
====================================================
  • 最大同時検出: セッション中にカメラ映像内に映っていた最大人数

ターミナル出力(30フレームごと)

Frame #30  |  2 人検出  |  163.6ms (6.1 FPS)  |  最大検出: 2 人
  [0] (120, 80) 140x200  score=0.99
  [1] (380, 60) 130x190  score=0.97

パフォーマンス(Raspberry Pi 5 実測値)

処理 fast モード count モード
V4L2 キャプチャ ~2ms ~2ms
YUYV → RGB 変換 (C) ~2ms ~2ms
UltraFace 推論 (NCNN + Vulkan) ~160ms × 1 ~160ms × 6
NMS・枠描画・表示 <2ms <5ms
合計 ~165ms (6.1 FPS) ~970ms (1.0 FPS)
検出距離 ~3m ~7m

初回フレームのみ Vulkan シェーダーコンパイルで約 200ms かかります。


mruby API リファレンス

GPU モジュール

GPU.init("shader")        # シェーダーディレクトリを指定して初期化
GPU.backend               # => "Vulkan"
GPU.device_name           # => "V3D 7.1.10.2"

# ベクトル演算
a = GPU.array([1.0, 2.0, 3.0])
b = GPU.fill(3, 1.0)
c = GPU.add(a, b)         # => GPU::Buffer
c.head(3)                 # => [2.0, 3.0, 4.0]

# 行列演算
c = GPU.matmul(a, b, M, K, N)

Camera クラス

cam = Camera.open("/dev/video0", 640, 480)  # デバイス, 幅, 高さ
cam.width                                   # => 640
cam.height                                  # => 480

yuyv = cam.capture                          # YUYV raw bytes (String)
rgb  = cam.capture_rgb                      # RGB888 bytes (String)

rgb  = Camera.yuyv_to_rgb(yuyv, 640, 480)  # YUYV→RGB 変換のみ

cam.close

FaceDetector クラス

detector = FaceDetector.new("models/ultraface-slim", use_gpu: true)

faces = detector.detect_rgb(rgb, width, height, threshold: 0.6)
# faces => Array of Hash
# 各要素: { x: Float, y: Float, w: Float, h: Float, score: Float }

faces.each do |f|
  puts "x=#{f[:x].round} y=#{f[:y].round} w=#{f[:w].round} h=#{f[:h].round}"
  puts "score=#{f[:score].round(2)}"
end
パラメータ 説明 デフォルト
use_gpu: Vulkan GPU 推論を使用 true
threshold: 検出スコアの閾値(0.0〜1.0) 0.7
  • 座標 (x, y) は検出枠の左上角(ピクセル単位、元画像サイズ基準)
  • score が 1.0 に近いほど確信度が高い

Display クラス

disp = Display.open(640, 480, "ウィンドウタイトル")

# RGB888 文字列をウィンドウに表示
disp.show(rgb, width, height)

# 検出枠を描画した新しい RGB 文字列を返す(元のデータは変更しない)
rgb = disp.draw_rect(rgb, width, height,
                     x, y, w, h,      # 枠の位置とサイズ(Integer)
                     r, g, b)         # 枠の色 (0〜255)

# ウィンドウ閉じる / ESC イベントを確認
break if Display.poll_quit

disp.close

ファイル構成

mruby-gpu/
├── src/                        # C/C++ ソース
│   ├── gpu_internal.h          # GPU 内部共有ヘッダ
│   ├── gpu_vulkan.c            # Vulkan 初期化・コンピュートディスパッチ
│   ├── gpu_buffer.c            # GpuBuffer 作成・アクセス・I/O
│   ├── gpu_ops.c               # mruby メソッド定義・gem init/final
│   ├── mrb_camera.c            # Camera クラス (V4L2)
│   ├── mrb_face.cpp            # FaceDetector クラス (NCNN + Vulkan)
│   ├── mrb_display.c           # Display クラス (SDL2)
│   ├── v4l2_capture.c          # V4L2 カメラ低レベル実装
│   └── v4l2_capture.h
├── shader/                     # Compute Shader
│   ├── add.comp / .spv         # ベクトル加算
│   ├── matmul.comp / .spv      # 行列積
│   ├── rgb_convert.comp        # YUYV→RGBA GPU 変換
│   ├── draw_rect.comp          # 枠描画 GPU シェーダー
│   └── Makefile
├── models/                     # NCNN モデル
│   ├── ultraface-slim.param
│   └── ultraface-slim.bin
├── examples/                   # デモ・サンプルスクリプト
│   ├── demo.rb                 # GPU 基本演算デモ
│   ├── face_demo.rb            # 顔認識デモ (LT 本番用)
│   ├── mnist.rb                # MNIST 推論
│   └── train.rb                # MNIST 学習
├── bench/                      # ベンチマーク
│   ├── basic.rb                # 基本ベンチマーク
│   └── scaling.rb              # スケーリングベンチマーク
├── test/                       # テスト
│   └── test_gpu.rb             # GPU 基本テスト
├── tools/                      # データ準備・スタンドアロンテスト
├── docs/                       # ドキュメント
│   └── PERFORMANCE.md
├── mrbgem.rake                 # gem ビルド設定
└── README.md                   # このファイル

トラブルシューティング

SDL_Init failed エラー
環境変数 DISPLAY が設定されていません。

DISPLAY=:0 mruby examples/face_demo.rb

カメラが開けない (Camera.open failed)
デバイスを確認してください。

v4l2-ctl --list-devices   # 接続中のカメラ一覧
# /dev/video0 以外の場合は examples/face_demo.rb の Camera.open 行を修正

顔が検出されない

  • カメラに顔を向けてください
  • threshold: を下げてみてください(例: threshold: 0.4
  • 照明が暗すぎる場合は明るい場所で試してください

ビルド時に undefined reference to ncnn エラー
NCNN がインストールされていません。「依存関係のインストール」を参照してください。

Raspberry Pi がフリーズする(NCNN ビルド時)
メモリ不足です。スワップを追加して -j1 でビルドしてください(前述の手順を参照)。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors