NatML + Unity + Local DL Modelでクロスプラットフォームアプリ実装 ~DLモデル準備編~（2/n）

# 最終目標
android/iOS/OSX/windowsでDL推論アプリを単一プラットフォーム・単一言語でつくる。
# 今回の内容
- NatMLで利用するためのDLモデル（onnx, coreml, tflite）を用意する。
# 背景
- NatMLHubではモデルを１つアップロードすれば自動的に他のモデル形式に変換してくれるものの、ローカルモデルを読み込む場合には自前で用意する必要がある。また、NatMLも開発が継続して進んでおり、ちょっと前に用意（変換した）モデルが読み込めないといったことに遭遇する。そのために変換のための道筋を記事として残しておく。
- ここで作成したモデルファイルは一連のNatML記事で利用する予定。

# 必要となるモデル
- onnx, coreml, tflite (float16)
**2023/09/04：MobileNetV3はfloat32でなければモデルを読み込めなかった。**
- NatMLはandroidでNNAPIをサポートしているので、最も適応が広いと予想されるfloat16を利用する。（int8も使う可能性を残しておく）

**注意!!**
pythonでonnxruntimeがあってOSXでも動くからと言ってNatMLもそうとは限らない。OSXで開発をする場合はCoreMLが必要。めんどくさい人は素直にNatMLのHubを使ってね。

>https://github.com/natmlx/natml-unity | Note that specific model formats can only be used on specific platforms. CoreML models can only be used on iOS and macOS; ONNX can only be used on Windows; and TensorFlow Lite can only be used on Android. Use NatML Hub to convert your model to different ML formats.

# MobileNetV3(Large)の変換

## 選定理由
- 軽い。
- 出力はImageNet[1,1000]のlogitでデバッグがしやすい。
- 前処理がなくても（e.g.アスペクト比がぐちゃってなっても）、ある程度それっぽい結果がとれる。
- 現在でいうところの"複雑なオペレーション"を使っていないのでNatMLで動作することが期待される。今のtransformerとか対応しているかとかはわからない。
    - どのオペレーションが対応してそうかは、公式のnatmlhubで掲載されているモデルをみつつ、推し量るのがよいでしょう。

## 流れ
pytorch -> coreml
pytorch -> onnx -> tflite

- coremlは[公式レポ](https://coremltools.readme.io/docs/installation)を参考にした。
- onnx,tfliteは[pinto氏のzenn note](https://zenn.dev/pinto0309/articles/216488def0c00b)をもとにonnx2tfの[公式レポ](https://github.com/PINTO0309/onnx2tf)でアップデートしたものをベースとしている。

## コード

colabの環境はころころ変わるので、https://github.com/PINTO0309/onnx2tf 含め最新の情報をどこかで確認すること。
```convert.ipynb
!sudo apt-get -y update
!sudo apt-get -y install python3-pip
!sudo apt-get -y install python-is-python3
!wget https://github.com/PINTO0309/onnx2tf/releases/download/1.7.3/flatc.tar.gz \
  && tar -zxvf flatc.tar.gz \
  && sudo chmod +x flatc \
  && sudo mv flatc /usr/bin/
!pip install -U pip \
  && pip install tensorflow==2.13.0 \
  && pip install -U onnx==1.14.0 \
  && python -m pip install onnx_graphsurgeon \
        --index-url https://pypi.ngc.nvidia.com \
  && pip install -U onnxruntime==1.15.1 \
  && pip install -U onnxsim==0.4.33 \
  && pip install -U simple_onnx_processing_tools \
  && pip install -U onnx2tf \
  && pip install -U protobuf==3.20.3 \
  && pip install -U h5py==3.7.0 \
  && pip install -U psutil==5.9.5
```

### pytorch　-> coreml

```python:convert.ipynb
# 最新のバージョンor NatMLと適合するバージョンは随時確認する
!pip install coremltools==7.0b2

import torch
import torchvision
import coremltools as ct

weights = torchvision.models.MobileNet_V3_Large_Weights.DEFAULT
torch_model = torchvision.models.mobilenet_v3_large(weights=weights)
torch_model.eval()

# Trace the model with random data.
SIZE = 128
x = torch.randn((1, 3, SIZE, SIZE))

traced_model = torch.jit.trace(torch_model, x)
out = traced_model(x)

model = ct.convert(
    traced_model,
    # convert_to="mlprogram",
    inputs=[ct.TensorType(shape=x.shape)]
 )

model.save("MobileNetV3Large.mlmodel")

```

### pytorch -> onnx -> tflite

```python:convert.ipynb
import torch
import torchvision

weights = torchvision.models.MobileNet_V3_Large_Weights.DEFAULT
model = torchvision.models.mobilenet_v3_large(weights=weights)
model.eval()
onnx_file = f'MobileNetV3Large.onnx'
SIZE = 128
x = torch.randn((1, 3, SIZE, SIZE))
torch.onnx.export(
    model,
    args=(x),
    f=onnx_file,
    opset_version=11,
    input_names=[
        'input',
    ],
    output_names=[
        'output',
    ],
)

!onnx2tf -i MobileNetV3Large.onnx
```

## 生成物の入出力情報
もとのpytorchはNCHWのRGB画像で出力は[1,1000]
imagenet系の画像分類は前処理transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])がたいてい入っているので今回も多分それ。覚えておく。

https://pytorch.org/tutorials/intermediate/realtime_rpi.html?highlight=mobilenet
https://pytorch.org/vision/main/models/generated/torchvision.models.mobilenet_v3_large.html

netronを使って各グラフのin out形式を確認する。
なおtfliteはonnx2tfのデフォルト設定を利用したときに限った話で、他のツールや次元変更オプションをいれた場合はその限りじゃないことに注意。
**2023/09/04：MobileNetV3はfloat32でなければモデルを読み込めなかった。**
|フォーマット|入力|出力|
|----|----|----|
|onnx|float32 NCHW|float32[1,1000]|
|tflite (float16)|float32 NHWC|float32[1,1000]|
|coreml|NCHW|多分float32[1,1000]|

CoreMLはんぜかnetronを使っても出口の形がよくわからない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156483/b4d4b764-67c7-6832-6c34-920fd968eab1.png)

# 展望
- もう少しNatMLの内部を見て、onnxのどのopsetならよいのかなどモデルごとに適合するバージョンを把握したい。
- onnxはopset、coremlはcoreml versionなど。