機械学習周りのプログラミング中心。 イベント情報
ポケモンバトルAI本電子書籍通販中

iPadのNeural Engineで将棋AI part03 dlshogiの評価関数をCore ML形式に変換

iPad上でdlshogiの評価関数であるDNNモデルを動作させるには、Appleが提供しているCore ML APIを使用します。 本記事では、モデルをAppleの開発環境へ取り込むための変換作業を解説します。

モデルの変換

dlshogiのモデルはPyTorch形式のため、これをCore ML専用の形式に変換する必要があります。 そのためには、Pythoncoremltoolsパッケージを使用します。

https://coremltools.readme.io/docs/pytorch-conversion

coremltoolsはPyTorchまたはTensorFlowのモデルをCore ML形式に変換する機構が含まれています。ONNX形式からの変換機構は一度実装されたもののdeprecatedになっているようです。ONNXさえあればPyTorchとTensorflow両方のサポートをしなくてよいと思うのですが、どうしてこういうポリシーなのかはわかりません。

モデルの変換は以下のステップで行います。

  1. PyTorch上でモデルをロードする。
  2. モデルをTorchScriptに変換する。
  3. TorchScriptをCore ML形式に変換する。
  4. 出力変数の名前を書き替える。
  5. モデルを保存する。

モデルの変換を行うcolab notebookはこちらです。ポイントを説明します。

PyTorch上でモデルをロードする

import torch
from dlshogi.common import *
from dlshogi.network.policy_value_network import policy_value_network
from dlshogi import serializers
from dlshogi import cppshogi

model = policy_value_network("resnet10_swish", add_sigmoid=True)
model.set_swish(False)#swishをx*sigmoid(x)で計算するモード
serializers.load_npz("./model/model_resnet10_swish-072", model, False)
model.eval()#評価用モード(Batch Normalization等の挙動設定)

モデルをロードします。ポイントはmodel.set_swish(False)です。これはdlshogiのモデル固有の設定となりますが、PyTorchにはSwishという活性化関数のオペレータが実装されていますが、これを使うと対応するオペレータがCore MLになく変換できないため同等の機能をx * sigmoid(x)というより単純な計算の組み合わせで実行するモードです。

モデルをTorchScriptに変換する

モデルの計算手順を、TorchScriptという形式に変換します。これは、Pythonインタプリタがないような組み込み環境などでも実行できるようなPython依存性の低いフォーマットです。

x1 = torch.zeros(1, 62, 9, 9)
x2 = torch.zeros(1, 57, 9, 9)
traced_model = torch.jit.trace(model, (x1, x2))

変換にはモデルを一度実行して、実行されたオペレータを記録するという形でTorchScriptを構築します。実行のために入力テンソルx1, x2を与えています。形状だけが必要で、テンソルの内容は影響ありません。

TorchScriptをCore ML形式に変換する

ここからcoremltoolsを使います。以下のコードでCore ML形式への変換ができます。入力テンソルの形状とTorchScriptを与えます。

import coremltools as ct

ct_input_x1 = ct.TensorType(name='x1', shape=(1, 62, 9, 9))
ct_input_x2 = ct.TensorType(name='x2', shape=(1, 57, 9, 9))
mlmodel = ct.convert(traced_model, inputs=[ct_input_x1, ct_input_x2])

注意ですが、このやり方ではバッチサイズ1での実行しかできませんので、多数の局面評価をバッチ処理するには効率が悪いです。今後改良します。

出力変数の名前を書き替える

前のステップで出力されたモデルそのままでも使用できるのですが、出力変数名がvar_577のような実装依存の値になり、Swiftコード内でこの名前を指定することになるので不便です。以下のコードで、出力変数名を好きな名前(ここではmoveresult)に書き換えます。

spec = mlmodel.get_spec()
move_name, result_name = mlmodel.output_description
ct.utils.rename_feature(spec, move_name, "move")
ct.utils.rename_feature(spec, result_name, "result")
mlmodel = ct.models.MLModel(spec)

モデルを保存する

モデルをファイルに保存します。

mlmodel.save("./model/DlShogiResnet10Swish.mlmodel")

ファイル名がそのままSwiftコードからモデルを呼び出す際のクラス名になるため、名前をパスカルケースでつけています。

Core ML以外にNeural Engineを使用する方法はないか

Core MLが機械学習専用チップであるNeural Engineを使用する唯一の方法となります。iPhone/iPad向けのTensorflow LiteもCore MLのラッパーとなっています。GPGPUのように自前でシェーダを記述することはできないようです。

次回は、今回出力したモデルをiPad上で動かすサンプルアプリを作ります。