Contenu connexe
Similaire à TFLite_and_PyTorch_Mobile (20)
Plus de yusuke shibui (20)
TFLite_and_PyTorch_Mobile
- 2. 自己紹介
cat : 0.55
dog: 0.45
human : 0.70
gorilla : 0.30
画像分類Shibui Yusuke
● メルカリ AI Team
基盤エンジニア
MLエンジニア
その他いろいろ
● Github: @shibuiwilliam
● Qiita: @cvusk
● Facebook: @shibui yusuke
● 最近やってること:Android、AR
MLシステムデザインパターン作成中。
これにEdge AIパターンを追加したい!
https://github.com/mercari/ml-system
-design-pattern 2
- 4. ● Why Edge AI?
● Tensorflow Lite & PyTorch Mobile
● Let’s Edge AI
Agenda
4
- 5. Why Edge AI?
● サーバサイドでAI
● クライアントサイドで AI
ボトル
ネック
ボトル
ネック
高性能
低性能
リアル
タイム
・Kotlin
・Java
・Swift
・C++
・C
情報保護
・Python
・Python
・Python
5
- 7. AIをスマホで動かす前処理
● カメラで画像を取得し、画像を AIで扱えるように
サイズとRGBを調整してテンソル(行列)に変換する。
0.2 0.3 0.9 0.0
0.0 0.1 0.5 0.7
0.1 0.3 0.5 0.7
0.7 0.6 0.4 0.6
0.2 0.3 0.9 0.0
0.0 0.1 0.5 0.7
0.1 0.3 0.5 0.7
0.7 0.6 0.4 0.6
0.2 0.3 0.9 0.0
0.0 0.1 0.5 0.7
0.1 0.3 0.5 0.7
0.7 0.6 0.4 0.6
画像を正方形
(224*224)にリサイズ
RGBのテンソル
(行列)に分ける
テンソルを0~1に正規化
60 90 240 0
0 10 127 195
10 92 128 195
195 161 111 161
7
- 12. CameraXにImageAnalysisをbind
abstract class AbstractCameraXActivity : AppCompatActivity(){
@WorkerThread
protected abstract fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float>
~~~~省略~~~~
private fun setupCameraX() {
~~~~省略(preview)~~~~
val imageAnalysisConfig = ImageAnalysisConfig
.Builder()
.apply {
setCallbackHandler(mBackgroundHandler)
setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}
.build()
~~~~次ページへ~~~~
}
}
TFLiteとPyTorchMobileが
analyzeImage()をoverride
12
- 13. CameraXにImageAnalysisをbind
abstract class AbstractCameraXActivity : AppCompatActivity(){
@WorkerThread
protected abstract fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float>
~~~~省略~~~~
private fun setupCameraX() {
~~~~前ページから~~~~
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
imageAnalysis.analyzer = ImageAnalysis.Analyzer {
image: ImageProxy?, rotationDegrees: Int ->
if (image == null) return@Analyzer
val result = analyzeImage(image, rotationDegrees)
if (result != null) runOnUiThread(Runnable { showResult(result) })
}
CameraX.bindToLifecycle(this, preview, imageAnalysis)
}
}
結果を画面に表示
推論して結果を取得
13
- 14. AIの開発ステップ
前処理 学習
前処理 推論 後処理
モデル
学習
サーバサイド
Python
推論
クライアントサイド
Kotlin/Swift
モデル
変
換
14
グレー部分を
TensorFlowや
PyTorchがカバー
- 15. ● tf.lite.TFLiteConverter
○ TFLite向けの専用のコンバータでモデルを FlatBuffersに変換する。
○ 各種クライアントのTFLite InterpreterがFlatBuffersを読み込んでモデルを動かす。
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/python
TensorFlow Lite
スマホで推論するためのモデル変換
スマホで推論モデルを動かすためのランタイム
● org.tensorflow.lite.*
○ チップセットへのdelegateを含めたInterpreter(推論器)を動かすためのライブラリ。
○ データの入出力はjava.nio.Bufferに変換、Interpreterを呼び出す。
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/experimenta
l/support/java/src/java/org/tensorflow/lite/support
15
- 17. Neural Network API (NNAPI)
Androidデバイスで演算負荷の
高いAI処理を実行するための
ネイティブAPI。
演算をGPUや専用チップへ移譲。
アプリ
TFLite
NNAPI
CPUProc
GPU
17
- 18. class TFLiteActivity : AbstractCameraXActivity() {
~~~~省略~~~~
private fun initializeTFLite(device: Constants.Device = Constants.Device.NNAPI, numThreads: Int = 4) {
val delegate = when (device) {
Constants.Device.NNAPI -> NnApiDelegate()
Constants.Device.GPU -> GpuDelegate()
Constants.Device.CPU -> "" }
if (delegate != "") tfliteOptions.addDelegate(delegate)
tfliteOptions.setNumThreads(numThreads)
tfliteModel = FileUtil.loadMappedFile(this, Constants.TFLITE_MOBILENET_V2_PATH)
tfliteInterpreter = Interpreter(tfliteModel, tfliteOptions)
~~~~次ページへ~~~~
}
}
TFLiteの演算を
NNAPIやGPU
に移譲
既存のモデルファイルを
ロード
モデルを計算
グラフに変換
TFLiteの推論モデルを用意する
18
- 19. TFLiteの推論モデルを用意する
class TFLiteActivity : AbstractCameraXActivity() {
~~~~省略~~~~
private fun initializeTFLite(device: Constants.Device, numThreads: Int) {
~~~~前ページから~~~~
inputImageBuffer = TensorImage(tfliteInterpreter.getInputTensor(0).dataType())
outputProbabilityBuffer = TensorBuffer.createFixedSize(
tfliteInterpreter.getOutputTensor(0).shape(),
tfliteInterpreter.getInputTensor(0).dataType())
probabilityProcessor = TensorProcessor
.Builder()
.add(NormalizeOp(0.0f, 1.0f))
.build()
}
}
入出力テンソルのバッファ
実態はjava.nio.Buffer
出力(確率)の
プロセッサ
19
- 20. TFLiteで推論
@WorkerThread
override fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float> {
val bitmap = Utils.imageToBitmap(image)
val cropSize = Math.min(bitmap.width, bitmap.height)
inputImageBuffer.load(bitmap)
val inputImage = ImageProcessor
.Builder()
.add(ResizeWithCropOrPadOp(cropSize, cropSize))
.add(ResizeOp(224, 224, ResizeMethod.NEAREST_NEIGHBOR))
.add(NormalizeOp(127.5f, 127.5f))
.build()
.process(inputImageBuffer)
~~~~次ページへ~~~~
}
前処理
ImageProxyをbitmap
→テンソルに変換
(同時にリサイズと正規化 )
20
- 21. TFLiteで推論
@WorkerThread
override fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float> {
~~~~前ページから~~~~
tfliteInterpreter.run(inputImage!!.buffer,
outputProbabilityBuffer.buffer.rewind())
val labeledProbability: Map<String, Float> = TensorLabel(
labelsList, probabilityProcessor.process(outputProbabilityBuffer)
).mapWithFloatValue
return labeledProbability
}
@UiThread
override fun showResult(result: String) { textView.text = result }
outputProbBufferに
推論結果を格納
ラベルと推論結果を紐
付ける
結果を表示 21
- 22. ● torch.jit.trace()
○ 汎用的なJITコンパイラでモバイル用のモデルを生成。
モバイル用に最適化するものではない。
○ Pythonで作ったPyTorchのモデルをC++から直接呼べるように変換している。
https://github.com/pytorch/pytorch/tree/master/torch/jit
PyTorch Mobile
● org.pytorch.*
torch.jit.trace()で生成したモデルを Nativeライブラリで動かすための Java実装を提供。
https://github.com/pytorch/pytorch/tree/master/android
● com.facebook.soloader.*
org.pytorch.*の実態はSoLoaderというFacebook製のネイティブコードローダー。
https://github.com/facebook/SoLoader
スマホで推論するためのモデル変換
スマホで推論モデルを動かすためのランタイム
22
- 24. PyTorch Mobileの推論モデルを用意する
class PyTorchActivity : AbstractCameraXActivity() {
~~~~省略~~~~
private fun initializePyTorch() {
val pytorchModule = Module.load(Utils.assetFilePath(
this,
Constants.PYTORCH_RESNET18_PATH))
val mInputTensorBuffer = Tensor.allocateFloatBuffer(3 * 224 * 224)
val mInputTensor = Tensor.fromBlob(
mInputTensorBuffer,
longArrayOf(1, 3, 224L, 224L)
)
}
}
推論モデルファイルをロード
この先はSoLoader
入力のテンソルを用意
実態はjava.nio.Buffer
24
- 25. PyTorch Mobileで推論
@WorkerThread
override fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float> {
TensorImageUtils.imageYUV420CenterCropToFloatBuffer(
image.image,
rotationDegrees,
224,
224,
TensorImageUtils.TORCHVISION_NORM_MEAN_RGB,
TensorImageUtils.TORCHVISION_NORM_STD_RGB,
mInputTensorBuffer,
0
)
~~~~次ページへ~~~~
}
前処理
ImageProxyを
テンソルに変換
(同時にリサイズと正規化 )
25
- 26. PyTorch Mobileで推論
@WorkerThread
override fun analyzeImage(image: ImageProxy, rotationDegrees: Int): Map<String, Float> {
~~~~前ページから~~~~
val outputModule = pytorchModule.forward(IValue.from(mInputTensor)).toTensor()
val scores = outputModule.dataAsFloatArray
val labeledProbability: MutableMap<String, Float> = mutableMapOf()
for (i in 0 until labelsList.size - 1) {
labeledProbability[labelsList[i + 1]] = score[i]
}
return labeledProbability
}
@UiThread
override fun showResult(result: String) { textView.text = result }
推論し、結果を
テンソルに変換
ラベルと
推論結果を
紐付ける
結果を表示
26