---
title: 推論ライブラリを実装する
tags:  #unity #unity3d #cedec2023  
author: [Unity Technologies Japan](https://convert.docswell.com/user/UnityJapan)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/4JZV32WX73.jpg?width=480
description: 2023/8/23〜25に開催された CEDEC 2023 の講演スライドです。 講師：大前 広樹（ユニティ・テクノロジーズ・ジャパン株式会社）
published: December 13, 23
canonical: https://convert.docswell.com/s/UnityJapan/Z8GD69-cedec2023-hirokiomae
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/4JZV32WX73.jpg)

推論ライブラリを実装する
ユニティ・テクノロジーズ・ジャパン株式会社
大前 広樹


# Page. 2

![Page Image](https://bcdn.docswell.com/page/YE65XVGPJV.jpg)

2
*ただし、周囲の受講者にご配慮下さい


# Page. 3

![Page Image](https://bcdn.docswell.com/page/GE5YXDVPE4.jpg)

3
AI


# Page. 4

![Page Image](https://bcdn.docswell.com/page/972GX83Z7R.jpg)

4
AI
SUGOI
“‘X{)$(O’&amp;Q
3重耐性
49連勝
3点振り
$@%#”
Babu
Babu
２０２２年までは・・・


# Page. 5

![Page Image](https://bcdn.docswell.com/page/DJYV861NJM.jpg)

5
AI
AI
AI
AI
AI
２０２３年


# Page. 6

![Page Image](https://bcdn.docswell.com/page/V7NMQZ2VE8.jpg)

AIは世界的なトレンドになり
世界を急激に変え始めている
技術者としても
そろそろ避けて通れない雰囲気…


# Page. 7

![Page Image](https://bcdn.docswell.com/page/YJ9NDZ1VJ3.jpg)

でもなんか気付いたらメッチャ
色々技術が積み上がってて何を
どうすれば良いのか・・・


# Page. 8

![Page Image](https://bcdn.docswell.com/page/GJ8K3144ED.jpg)

あ、▼▼さん！
今度の企画なんですけど、
○○にAI使ってやれませんかね
…って言われても
どうすりゃいいんだよ〜


# Page. 9

![Page Image](https://bcdn.docswell.com/page/LJLZVQ6V7R.jpg)

AIコワイ
あれ・・こわくない・・・？
本セッションの目標


# Page. 10

![Page Image](https://bcdn.docswell.com/page/47MVG15N7W.jpg)

• AIとは
構成
• AI(機械学習の基本)
• モデルを実機で使うためには(ONNX)
• 実機で推論モデルを動かすためには
Unity Sentisを実例に


# Page. 11

![Page Image](https://bcdn.docswell.com/page/P7R2ZL34J9.jpg)

11
AIって何？


# Page. 12

![Page Image](https://bcdn.docswell.com/page/PJXD9W4ZEX.jpg)

12
input
なんかこういう図だけ見たことあるけど・・・
こういう「ニューラルネット」をつくって「学習」させると
なんかの役に立つらしい？
でも効率的ではないとも聞くなぁ
ていうか、そもそも・・・
output


# Page. 13

![Page Image](https://bcdn.docswell.com/page/3JKXPVZVED.jpg)

13
人の顔を認識したり・・・
質問にイイ感じに回答したり・・・
なんでこれが出来るようになるん？


# Page. 14

![Page Image](https://bcdn.docswell.com/page/LE35XMXQJ5.jpg)

AI（機械学習）の基本


# Page. 15

![Page Image](https://bcdn.docswell.com/page/8EDD262WEG.jpg)

台東区で2LDKの部屋
借りようとおもったら
だいたいイクラくらい？
それだったら
月○○万円
くらいっすね
そもそも機械学習（AI）で
解決したい問題は、
これはコンちゃん？
なすちゃん？
プログラミング
それは
『なすちゃん』
(アルゴリズム)だけでは
っすね
解決しづらい問題
これ数字の何って
描いてあんの？
それは
『５』
っすね


# Page. 16

![Page Image](https://bcdn.docswell.com/page/V7PX1Y1XE8.jpg)

識別的モデル
入力内容から答えを予想したり、
・・・
分類したりする
線形回帰
２値分類
多値分類
数字認識
生成的モデル
画像や文章や音声など、
・・・
入力されたデータ以上の
（あるいは異なる形式の）
出力を生成する
画像生成
文章生成
音声生成
解決したい問題に合わせて「モデル」を設計していく
画像認識


# Page. 17

![Page Image](https://bcdn.docswell.com/page/2JVLYGY37Q.jpg)

予測計算
学習データ
学習データをもらって正解の値
を目指して計算する
正解データ
最適化
損失計算
「勾配」を使って、予測計算の
ためのパラメーターを調整する
正解データとどのくらい離れて
いるかを計算する
勾配計算
損失から「勾配」をつくる
勾配降下法を使った識別モデルのプログラムは、４つの要素で出来ている


# Page. 18

![Page Image](https://bcdn.docswell.com/page/5EGX989YJL.jpg)

入力データをみて
か
２値分類
か？
を分類したい


# Page. 19

![Page Image](https://bcdn.docswell.com/page/4JQ8W9W67P.jpg)

この辺で線を引いて・・・
こっち側にいるのは
で・・・
こっち側にいるのは
かな・・・
AとBで分類したいデータが
ある
予め用意したデータじゃなくて
も、入力したら
か
分かるようになりたい。
か
今取ったデータは
かな？
かな？


# Page. 20

![Page Image](https://bcdn.docswell.com/page/K742KXKMJ1.jpg)

この直線を引く一次関数
Yp = W * X + B
＝
適切なWとBの値が
２値分類の
予測計算
見つけられたら、
正確に分類出来る
これを見つける作業が『学習』


# Page. 21

![Page Image](https://bcdn.docswell.com/page/LJ1MXNXYEG.jpg)

損失計算
Yp
予測結果と正解データの２つの値がどれだけズレてるか
（損失）を計算する。
損失はできるだけ０に近づけたいので、単純な差分を使う
今のパラメータで
予想してみたで〜
よりも差が際立ちやすい手法を使った方が学習に役立つ
Y
正解データ
正解はこれでした
i.e.
loss = (Y-Yp)²


# Page. 22

![Page Image](https://bcdn.docswell.com/page/GJW3N4N1J2.jpg)

勾配計算
損失から「パラメータを次に調整すると
今回の損失の値は
こんな感じでした
きはどうしたらいい？」という足がかりに
勾配値に反映しとくな！
なる「勾配値」を作る


# Page. 23

![Page Image](https://bcdn.docswell.com/page/4EZV323XJ3.jpg)

最適化（パラメータ調整）
更新された勾配値でパラメータをそれぞれ更新する。
パラメータ
W
W
この時にどのくらい反映するか＝「学習率」
とっても簡単な最適化例：
B
B
W -= 学習率 x Wの勾配値
B -= 学習率 x Bの勾配値
そしてまた予測計算へ！


# Page. 24

![Page Image](https://bcdn.docswell.com/page/Y765XVXPEV.jpg)

この４つのプロセスを繰り返すことでだんだん
最適なパラメーターが見つかる
最適と思われるパラメータを獲得したモデルを
「学習済みモデル」と呼ぶ
モデルを保存してスマホやPC、サーバーなどで使う！


# Page. 25

![Page Image](https://bcdn.docswell.com/page/G75YXDXP74.jpg)

input
output
入力テンソル
この謎のグラフは…
予測関数
出力テンソル
実は「予測関数」のこと！


# Page. 26

![Page Image](https://bcdn.docswell.com/page/9J2GX8XZJR.jpg)

より複雑なモデルでは
『特徴表現学習』という部分が増えて、
元データの特徴をより多角的に学習で
きるようにモデルを作ったりする
（でも、基本の構成は同じ！）
入力画像
畳み込み処理を何回か行うことで
畳み込みを行った結果
元画像から学べる特徴量を増やす
小さくなった画像を1階
のテンソルに変換して、
多値分類を行う
複雑な複合材構造の衝撃検出と特性評価のための畳み込みニューラルネットワーク
A Convolutional Neural Network for Impact Detection and Characterization of Complex Composite Structures, Iuliana Tabian, Hailing Fu and Zahra Sharif Khodaei, 2019


# Page. 27

![Page Image](https://bcdn.docswell.com/page/DEYV868NEM.jpg)

０階のテンソル
スカラー値
1.0
1階のテンソル
ベクトル
[1.0, 0.0, 0.0]
機械学習のモデルで
扱う入出力はすべて
「テンソル」
2階のテンソル
行列
・
・
・
[
1.0, 0.0, 0.0, 0.0
0.0, 1.0, 0.0, 0.0
0.0, 0.0, 1.0, 0.0
0.0, 0.0, 0.0, 1.0
]


# Page. 28

![Page Image](https://bcdn.docswell.com/page/VJNMQZQV78.jpg)

手書き数字の画像(28 x 28)
[784] の
入力テンソル
テンソルに変換
[784]
数値予測
出力テンソル
[10] の
[10]
どの数字かの確率を
保持したテンソル
関数は基本同じ階のテンソルを扱うので、
事情に合わせて変形して使う


# Page. 29

![Page Image](https://bcdn.docswell.com/page/YE9NDZDVE3.jpg)

https://projector.tensorflow.org/
文章や単語なども
ベクトルに変換してしまう
ことで扱えるようになる
Word2Vec 10K


# Page. 30

![Page Image](https://bcdn.docswell.com/page/GE8K31347D.jpg)

テンソルに対する計算処理は、大抵のライブラリで
部品化されている
線形関数
活性化
線形関数
活性化
関数
線形関数
関数
入力テンソル
予測モデル
これらのコンポーネントを
「レイヤー」
と呼ぶ
活性化
関数
出力テンソル


# Page. 31

![Page Image](https://bcdn.docswell.com/page/LELZVQVVJR.jpg)

学習したものを
実機に持っていく


# Page. 32

![Page Image](https://bcdn.docswell.com/page/4JMVG1GNJW.jpg)

● さまざまな推論用のシステムが
サポートする共通フォーマット
● モデル構造や、モデルに紐付くデータや
メタデータなどを効率的に持っていける
● 一般的に必要な要件を定義しながらも、
拡張性にも考慮されている
● ONNXは実行環境とは独立した
仕様となっている


# Page. 33

![Page Image](https://bcdn.docswell.com/page/PJR2ZLZ4E9.jpg)

モデルデータは好みの環境で作って
ONNX形式で出力する


# Page. 34

![Page Image](https://bcdn.docswell.com/page/PEXD9W9Z7X.jpg)

34
数多くのオペレーター
が定義されている


# Page. 35

![Page Image](https://bcdn.docswell.com/page/3EKXPVPV7D.jpg)

35
Operator
線形関数
活性化
線形関数
関数
入力テンソル
活性化
関数
出力テンソル
PyTorchで描いた
予測関数
ONNXモデルを
グラフ化したもの


# Page. 36

![Page Image](https://bcdn.docswell.com/page/L735XM4QE5.jpg)

Unity Sentis
● ONNXベースのモデルを
Unityが対応している
さまざまなプラットフォームで
実行するライブラリ


# Page. 37

![Page Image](https://bcdn.docswell.com/page/87DD26QW7G.jpg)

Safe
Harbor
State
●Unity Sentisは現在まだ実験的機能
(Experimental) です。
ここで解説された実装方式や方針は
今後予告なく変わることがあります。
●本セッション内容は
「推論ライブラリっていうのはこういうことを
してるのね」ということを理解するための
補助として参照してください。


# Page. 38

![Page Image](https://bcdn.docswell.com/page/VJPX1YLX78.jpg)

数多くのONNX
オペレーターを
実装
推論ライブラリを実装する＝(ONNXの)オペレーターを実装する
という作業


# Page. 39

![Page Image](https://bcdn.docswell.com/page/2EVLYGQ3JQ.jpg)

推論ライブラリ実行時の流れ
準備（Editor）
実行(Runtime)
Layer
model.onnx
Layer
Layer
Layer
Model Asset
モデルデータの
実行環境向けに
インポート
最適化
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
モデルの実行をスケジュール
推論結果の受取（非同期）
推論ライブラリの役割は
● モデルに保存されたグラフから、実行するオペレーション（レイヤー）群を構築する
● 構築されたレイヤー群を使って、定型のオペレーションを効率良く実行する


# Page. 40

![Page Image](https://bcdn.docswell.com/page/57GX98WYEL.jpg)

Sentisでの
モデルの
最適化
ModelOptimizer
model.onnx
Model Asset
•意味のないレイヤーや重複しているレイヤーなどを見つけて整理
•レイヤーやサブグラフの中に同様に機能するもっと簡素な
別のレイヤーに置き換えられるものがあれば置き換え
•推論時にデータの読み取りが必要なレイヤーは
CPUで動作するよう設定
•etc


# Page. 41

![Page Image](https://bcdn.docswell.com/page/4EQ8W936JP.jpg)

ONNX Model
Model Asset


# Page. 42

![Page Image](https://bcdn.docswell.com/page/KJ42KX1ME1.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
Layer
Layer
Layer
モデルの実行をスケジュール
ModelAsset modelAsset = Resources.Load(“model.onnx”) as ModelAsset;
Model runtimeModel = ModelLoader.Load(modelAsset);
推論結果の受取（非同期）


# Page. 43

![Page Image](https://bcdn.docswell.com/page/LE1MXNGY7G.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
Layer
Layer
Layer
モデルの実行をスケジュール
推論結果の受取（非同期）
IWorker worker = WorkerFactory.CreateWorker (BackendType.GPUCompute, runtimeModel);
CPUで動かすか
GPUで動かすかなどを指定する


# Page. 44

![Page Image](https://bcdn.docswell.com/page/GEW3N4K1E2.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
Layer
Layer
Layer
モデルの実行をスケジュール
TensorFloat inputTensor = TextureConverter.ToTensor(inputTexture);
テクスチャデータなど、ゲームでよく使うデータ構造を
テンソルに変換してくれるコンバータも用意されている
推論結果の受取（非同期）


# Page. 45

![Page Image](https://bcdn.docswell.com/page/47ZV32ZXE3.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
worker.Execute(inputTensor);
非同期で実行
Layer
Layer
Layer
モデルの実行をスケジュール
推論結果の受取（非同期）


# Page. 46

![Page Image](https://bcdn.docswell.com/page/YJ65XVZP7V.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
Layer
Layer
Layer
モデルの実行をスケジュール
TensorFloat outputTensor = worker.PeekOutput() as TensorFloat;
outputTensor.AsyncReadbackRequest(callback); // callback =&gt; Action&lt;bool&gt;
推論結果の受取（非同期）


# Page. 47

![Page Image](https://bcdn.docswell.com/page/GJ5YXDWPJ4.jpg)

Sentisでモデルを実行
する
Layer
モデルの
モデルを実行する
入力データの準備
ロード
Workerを作成
（テンソル化）
Layer
Layer
Layer
モデルの実行をスケジュール
推論結果の受取（同期）
TensorFloat outputTensor = worker.PeekOutput() as TensorFloat;
推論結果を同期待ちしたい場合は
outputTensor.MakeReadable();
float[] results = outputTensor.ToReadOnlyArray();
MakeReadable()を呼ぶと
終わるまでブロックする


# Page. 48

![Page Image](https://bcdn.docswell.com/page/LE35XM46J5.jpg)

CPU
BurstとJob Systemで
CPU実行
Sentisの
バックエンド
タイプ
さまざまなプラットフォームで利用可能
にするため、レイヤー/Opの実装は1つ
GPU
Compute
GPU
Command Bu er
Compute Shaderで
コマンドバッファに書き込み
GPU実行
任意のタイミングでGPU実行
GPU
Pixel
Pixel Shaderで
ではない
ff
GPU実行


# Page. 49

![Page Image](https://bcdn.docswell.com/page/8EDD26QMEG.jpg)

フィルタ
GPU Pixel
実装の工夫
テンソルはRender Textureを
フィルタ
使用して実装するが、
テクスチャデータの次元に沿っては格
納しない
畳み込み結果
テクスチャフェッチ回数が多いConv（畳み込み）
レイヤー等に有利な形でテンソルをテクスチャに格納


# Page. 50

![Page Image](https://bcdn.docswell.com/page/V7PX1YLQE8.jpg)

GPU
Backend
Sentisの
Workerは生成時に実際の処理を行う”Backend”
オブジェクトが接続される。
処理構造
Worker
参照
*講演後編集
Model


# Page. 51

![Page Image](https://bcdn.docswell.com/page/2JVLYGQP7Q.jpg)

TensorData
(GPU)
転送
Tensor
TensorData
(CPU)
*講演後編集
Backend
テンソルは使用時にはBackendと
同じメモリ空間にいる必要があるので、
テンソルのデータは内部的には
TensorDataという別の形で持っており、
かつデバイス間を移動（アップロード）
する機能を持つ
GPU


# Page. 52

![Page Image](https://bcdn.docswell.com/page/5EGX98WQJL.jpg)

TensorData
(GPU)
生成
Job
Tensor
GPU
Operation実装
Backend
Job
Job
Job
Job
…
Job Thread
Worker
Job発行
Workerを動かすと、
ジョブを使えるバックエンドでは
Modelの構成に沿ってJobを発行
Execute
Model
*講演後編集


# Page. 53

![Page Image](https://bcdn.docswell.com/page/4JQ8W93W7P.jpg)

TensorData
(GPU)
生成
Job
Tensor
Job
Job
Job
Job
…
Job Thread
Worker
各Jobが
BackendのOperationを呼び出して
処理を実行
Execute
Model
*講演後編集
GPU
Operation実装
Backend


# Page. 54

![Page Image](https://bcdn.docswell.com/page/K742KX11J1.jpg)

Y
ReLU関数の
実装例
X
活性化関数のひとつ
public interface IOps : IDisposable
{
…
TensorFloat Relu(TensorFloat x);
…
}
*講演後編集
(0, 0)
インターフェイス


# Page. 55

![Page Image](https://bcdn.docswell.com/page/LJ1MXNG5EG.jpg)

CPU(Burst) の場合
public virtual TensorFloat Relu(TensorFloat X)
{
var O = NewOutputTensorFloat(X.shape);
if (O.shape.HasZeroDims())
return O;
C# (Job発行側)
var job = new ReluJob();
job.ScheduleXO(Pin(X), Pin(O, uploadCache: false), O.shape.length, 1024);
return O;
}
float Apply(float v) { return 0.5f * (v + abs(v)); }
public void Execute(int threadIdx)
{
float v = Xptr[threadIdx];
Optr[threadIdx] = Apply(v);
}
*講演後編集
C# (Burst Job)


# Page. 56

![Page Image](https://bcdn.docswell.com/page/GJW3N4KWJ2.jpg)

GPU Compute の場合
public override TensorFloat Relu(TensorFloat X)
{
var O = NewOutputTensorFloat(X.shape);
if (O.shape.HasZeroDims())
return O;
C# (CPU)
var fn = new ComputeFunc(&quot;Relu&quot;);
fn.ScheduleXO(Pin(X), Pin(O, uploadCache: false), O.shape.length);
return O;
}
#ifdef RELU
[numthreads(64, 1, 1)]
void Relu(uint3 dispatchThreadID : SV_DispatchThreadID)
{
uint threadIdx = unrolledDispatchArgs.x * dispatchThreadID.y + dispatchThreadID.x;
if(threadIdx &gt;= unrolledDispatchArgs.y)
return;
{
float v = Xptr[threadIdx];
Optr[threadIdx] = Apply(v);
}
}
#endif
*講演後編集
Compute Shader


# Page. 57

![Page Image](https://bcdn.docswell.com/page/4EZV32Z2J3.jpg)

GPU Pixel の場合
public override TensorFloat Relu(TensorFloat X)
{
return Activation(X, &quot;Relu&quot;);
}
C# (CPU)
TensorFloat Activation(TensorFloat X, string kernelName,
float alpha = 0f, float beta = 0f)
{
var O = NewOutputTensorFloat(X.shape);
if (O.shape.HasZeroDims())
return O;
var func = new PixelFunc(&quot;Hidden/Sentis/Activation&quot;);
var pinX = PinBlockAny(X);
var pinO = PinAsSame(O, pinX, uploadCache: false);
func.SetFloat(k_ID_Alpha, alpha);
func.SetFloat(k_ID_Beta, beta);
func.SetTensor(k_TensorPropertiesX, pinX);
func.SetTensorBlockStride(k_TensorPropertiesO, pinO);
func.EnableKeyword(kernelName);
func.Dispatch(pinO);
return O;
}
*講演後編集
Pixel Shader
float4 frag(v2f i, UNITY_VPOS_TYPE screenPos :
VPOS) : SV_Target
{
…
#ifdef Relu
v = 0.5f * (v + abs(v));
#endif
…
return v
}


# Page. 58

![Page Image](https://bcdn.docswell.com/page/Y765XV86EV.jpg)

Special Thanks
Lein.@キノピオPro 氏 ( twitter.com/lears_VR )
みどりの森（ https://mido0021.booth.pm/ ）


# Page. 59

![Page Image](https://bcdn.docswell.com/page/G75YXD9574.jpg)

Q&amp;A


