ブラウザ上でYOLO v8を動かす~PyScriptとONNXRuntime-webを使ったディープラーニング物体検出
ブラウザ上でYOLOv8を動かす「YOLOv8-browser」を作ったので、本記事で紹介します。
PC・スマホのブラウザで動くので、ぜひデモを試してみてください。
このプロジェクトでは、PyScriptとONNXRuntime-webを利用しています。
背景
DNN推論するPythonプロジェクトからブラウザへの移植を想定しています。
これまでの課題
DNN推論するPythonプロジェクトをブラウザへ移植する場合、PythonからJSへの翻訳工数が大きい課題があります。
以前 YOLO v2をJSとブラウザだけで動かしたときは、YOLO推論処理のために大量のJS/TSファイルが必要でした。
本手法が解決すること
元のPythonプロジェクトの.pyファイルをそのままブラウザ上で動かすことで、追加コードを最低限にしつつ、ブラウザ上でのDNN推論を実現します。
本プロジェクトの追加コードは、index.htmlに記述したJavaScriptと、ブラウザ用に記述したPython(assets/front.pyとassets/YOLOv8_browser.py)だけです。
PyScriptとは
PyScriptは、HTMLとPyodide、WASM、そして最新のウェブ技術の力を使って、ブラウザで豊かなPythonアプリケーションを作成できるフレームワークです。
以下のようにHTMLファイルに直接、Pythonの設定と処理を記述・実行できます。
https://github.com/lilacs2039/YOLOv8-browser/blob/main/index.html#L116
<py-config type="toml">
[[interpreters]]
src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js"
...
[[fetch]]
files=[
"assets/front.py",
...
</py-config>
<py-script output="image">
from assets.front import main
import asyncio
asyncio.ensure_future(main())
</py-script>
なお、JavaScriptと一緒にPythonを実行する弊害として、Python側の関数をasyncにする必要があります。Python処理中に画面が固まるのを防ぐためです。
Pyodideとは
Pyodideは2019年4月に発表されたMozillaのプロジェクトです。
WebAssembly/EmscriptenにCPythonを移植したもので、ブラウザ内でPythonパッケージをインストールして実行できるようにするものです。PyPIにホイールがある純粋なPythonパッケージはどれでも対応しています。また、多くのC拡張を持つパッケージもPyodide用に移植されています。
余談ですが、Pyodideを利用してブラウザだけでJupyterLabが動く、JupyterLiteというWEBアプリもあります。
コアJupyter 開発者によって開発されている、非公式プロジェクトです。
https://jupyterlite.readthedocs.io/en/latest/
ONNXRuntime-webとは
ONNXRuntime-webは、MicrosoftのONNX Runtimeのウェブブラウザ向けの実装であり、WebAssemblyやWebGLなどの技術を使ってディープラーニングモデルの推論を行います。
ONNX Runtimeと同様にonnx形式のDNNモデルを実行できますが、一部対応していないオペレーションがあり、適宜ワークアラウンドが必要です。(たとえば、本プロジェクトでは、YOLOv8モデルのResizeレイヤはwebglバックエンドで実行エラーだったため、wasmバックエンドを利用するようにしています)
YOLO v8とは
物体検出の新しいモデルで、2023年1月に公開されました。YOLOv8 は、入力された画像から物体の位置と種類を高速かつ高精度に検出することができます。YOLOv8 は、既存のオブジェクト検出器を上回り、速度と精度のトレードオフが向上しています。
仕組み
PythonではDNN推論にonnxruntimeが利用できますが、PyScriptでは利用できません。代わりに、JSライブラリのonnxruntime-webを使ってDNN推論を行います。
また、DNN推論以外の処理(検出矩形の描画など)は、PyScript上で元プロジェクトのPythonファイルをそのまま利用します。
呼び出し関係のイメージ
ページ読み込みしたとき
onnxruntime-webセッションの初期化とサンプル画像の物体検出を実行します。
DNN推論はJSライブラリのonnxruntime-webを使うので、セッション関連の処理はindex.htmlに記述したJS関数を呼び出します。
ローカルから画像選択したとき
選択画像の物体検出を実行します。
実装~コツ
PyScriptでの実装のコツは、pythonの時点でonnxruntimeモジュールを使う処理を別ファイルに分けて書いておくことです。
例
yolov8/YOLOv8_base.py に共通処理を書いて…
class YOLOv8Base(ABC):
"abstract class for YOLOv8."
# ----------------------- public methods -----------------------
def __init__(self, path, conf_thres=0.7, iou_thres=0.5):
self.conf_threshold = conf_thres
...
# ----------------------- abstract methods -----------------------
@abstractmethod
async def init_session(self, path):
raise NotImplementedError()
yolov8/YOLOv8.py にonnxruntimeを使う処理を記述する。
import onnxruntime
...
class YOLOv8(YOLOv8Base):
async def init_session(self, path):
self.session = onnxruntime.InferenceSession(path,
providers=['CUDAExecutionProvider',
'CPUExecutionProvider'])
...
assets/YOLOv8_browser.py に、ブラウザから呼び出すPythonの処理を記述する。
from js import js_init_session, js_run_session
from pyodide.ffi import create_proxy, to_js
import asyncio
...
class YOLOv8(YOLOv8Base):
async def init_session(self, path):
self.session = await js_init_session(path)
...
Pyodideではonnxruntimeは使えず、代わりに処理をJS側に投げてonnxruntime-webを使うので、Pythonで開発する時点であらかじめ分けておくとJSへの移行がスムーズです。
実装~つらみ
PyodideのPython-Javascriptのデータ型変換には、苦労が伴いますが、opencvのMatを経由してTensorに変換することができました。
https://github.com/lilacs2039/YOLOv8-browser/blob/main/index.html#L85
↓ つらい変換:list(Float32Array)→cv.Mat→ort.Tensor
const tensor = new ort.Tensor("float32",
cv.matFromArray(640, 480, cv.CV_32FC3,
new Float32Array(_input_tensor.flat(Infinity).map(a => Array.from(a)).flat())
).data32F, modelInputShape)
本手法のメリット
低工数:既存のPythonコードをそのまま利用できるため、追加コードが最小限で済みます。本プロジェクトでブラウザ用に記述したpythonファイルはassets/front.pyとassets/YOLOv8_browser.pyだけです。
以前 YOLO v2をJSとブラウザだけで動かしたときは、YOLO推論処理のために大量のJS/TSファイルが必要でした。Pyodideを使わない場合、DNNプロジェクトのブラウザ移植は、たくさんのファイルをpythonからjavascriptへ翻訳する必要がありました。
コスト・スケーラビリティ:推論はエッジ端末で行われるため、推論サーバーのコスト不要で無限のスケーラビリティが手に入ります。
本手法のデメリット
パフォーマンス:ブラウザ上での実行によるパフォーマンス低下や、特定のブラウザや環境での互換性問題があります。
互換性・安定性:pyscriptやonnxruntime-webのように若い技術を使うため、互換性や安定性が保証されていません。
今後の課題
高速化
GPU処理なら40ms程度の処理が、400ms以上かかっています。
高速化のために以下の方法が考えられます。
webglやwebGPUバックエンドに対応できるようにモデルを変更
fp16やint8への低精度化による高速化
まとめ
ブラウザ上でYOLOv8を動かす「YOLOv8-browser」を紹介しました。
本手法により、低工数・低コストで物体検出システムを配布することができます。これにより、ディープラーニングによる物体検出を手軽に利用できるようになります。
ただし、pyscriptとその関連技術の成熟度やブラウザの互換性に注意しながら開発を進めることが重要です。今後の課題を克服し、パフォーマンスの向上や互換性の改善を実現すれば、さらなる応用例が広がることでしょう。