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

iPadのNeural Engineで将棋AI part07 iPadの冷却は必要か

前回までで、Core MLによる評価関数モデルの実行ができました。ただしボタンをタップした時に1回だけ実行するというものでした。対局では約1時間にわたり連続稼働する必要がありますので、連続稼働で問題がないかを確認しました。具体的には、発熱によって性能が低下したりクラッシュしたりしないかを確認します。

10分間にわたりモデルの実行を連続して行い、実行速度の時間変化を測定しました。計算に用いるエンジンとしてNeural Engine (ANE)とCPUを試しました(GPUはエラーで動きません)。冷却条件として、ポリエステル製のケースに入った状態(normal)と、ケースを外してサーキュレータの風を直接あてた状態(cooling)を試しました。気温は20度でした。バッチサイズは64で、モデルの実行が完了すると結果は捨ててすぐに次の実行を行います。10秒ごとに、直近10秒間で処理できたサンプル数から計算速度を算出してプロットします。

f:id:select766:20220213094423j:plain
サーキュレータでの冷却。サーキュレータの真上にiPadを置いた。

f:id:select766:20220213094225p:plain
冷却条件による実行速度の時間変化

結果を上図に示します。ANEの場合は1000samples/sec、CPUの場合は300samples/sec程度に収束しました。最初の100秒程度は10%程度高速です。ANEの冷却なしの場合に速度低下が少し遅かったですが、測定を1回しか行っていないため原因はよくわかりません。冷却の有無では速度に差がみられず、いずれの場合も最初の速度より低い速度で収束するということがわかりました。速度の低下は、外部からの冷却では防げない箇所の温度上昇か、温度に関係なくタスクスケジューラが消費電力を抑制しようとしている可能性があります。また、本体の温度を手で触って確認しましたが、わずかしか温度上昇は感じられませんでした。

結論として、iPadを強制空冷しても速度に違いはないことがわかりました。冷却は不要というのが現状の結論です。ただし、評価にNeural Engineを用いつつ、探索でCPUに負荷をかけた場合までは未検証のため、将棋エンジン全体ができた際に再検討する余地があります。

ログ出力の実装

iPad上で動作したログを出力し、PC側で閲覧するための実装の概要を示します。

ログの出力には、Swift標準のログ機能を用いました。ロガーの初期化は以下のように行います。

import os

let logger = Logger(subsystem: "jp.outlook.select766.DlshogiOnCoreML", category: "main")

ログの出力は、

logger.log("hello")

として行うことができます。今回はJSONが出力したかったので、次のような補助関数を実装しました。

func log(_ obj: Any) {
    do {
        // シリアライズできないデータが来ると、 NSInvalidArgumentException が来て
        // これはNSExceptionのサブクラスでありswiftのcatchで処理できず落ちる
        let data = try JSONSerialization.data(withJSONObject: obj, options: [])
        guard let str = String(data: data, encoding: .utf8) else {
            logger.error("Failed to write log")
            return
        }
        logger.log("\(str, privacy: .public)") // 直接Stringは渡せない
    } catch {
        logger.error("Failed to write log")
    }
}

この関数を log(["type": "start", "cu": loadedModelComputeUnits, "bs": batchSize])のようにして呼び出すと、JSON文字列が保存されます。logger.logの引数はただのStringではなく、文字列補間 \()の中身がデフォルトではログに残らないような仕組みになっています。動的な文字列には個人情報などが含まれる想定で保護する目的のようですが、今回は不要なのでprivacy: publicというオプションをつけています。JSONSerialization.dataメソッドの例外はdo-catchでは処理できないObjective-Cベースの例外のようですがObjective-Cの知識がないため放置しています。シリアライズに失敗するようなデータを与えない限り問題ありません。

ログをUSB接続したMacから取り出すには以下のコマンドを実行します。

sudo log collect --device --last 5m

lastオプションはどれぐらいの期間のログを取り出すかを指定します。ログには自作のアプリ以外にもシステム上のすべてのログが含まれています。アプリが終了してもログは残ります(ログレベルに依存)。

実行結果はsystem_logs.logarchiveというディレクトリに書き出されます。ダブルクリックするとMac標準のコンソールアプリで中身を確認できます。

また、以下のコマンドでログをフィルタリングして文字列として出力できます。これをファイルにリダイレクトすることで、Pythonを使った分析ができます。

% log show --archive system_logs.logarchive --predicate '(subsystem IN {"jp.outlook.select766.DlshogiOnCoreML"})' --last 5m
Filtering the log data using "subsystem IN {"jp.outlook.select766.DlshogiOnCoreML"}"
Skipping info and debug messages, pass --info and/or --debug to include.
Timestamp                       Thread     Type        Activity             PID    TTL
2022-02-09 07:49:56.952750+0900 0xc4e3a    Default     0x0                  5462   0    DlshogiOnCoreML: [jp.outlook.select766.DlshogiOnCoreML:main] {"type":"start","cu":"NE","bs":64}
2022-02-09 07:49:57.488087+0900 0xc4e3a    Default     0x0                  5462   0    DlshogiOnCoreML: [jp.outlook.select766.DlshogiOnCoreML:main] {"type":"end","samplePerSec":147.98817574086306,"elapsed":0.43246698379516602,"resultDiff":"Max difference: 0.0040952563","moveDiff":"Max difference: 0.08522034"}
--------------------------------------------------------------------------------------------------------------------
Log      - Default:          2, Info:                0, Debug:             0, Error:          0, Fault:          0
Activity - Create:           0, Transition:          0, Actions:           0

ちなみに、Core ML自体から出力されるログも存在します。

neural-engine/os-log.md at master · hollance/neural-engine · GitHub

log show --archive system_logs.logarchive --predicate '(subsystem IN {"com.apple.espresso","com.apple.coreml"}) && (category IN {"espresso","coreml"})' --info --debug --last 5m

以下のような警告が出ていました。実行結果はあっているので問題ありません。

2022-02-08 21:00:02.369336+0900 0xbb6f5    Debug       0x0                  4853   0    DlshogiOnCoreML: (Espresso) [com.apple.espresso:espresso] Kernel validation warning u1_1_1 (convolution) @ 2: HW utilization loss: HW may round up computation of output sizes to multiple of 8 or 16, but the output size is 9x9
2022-02-08 21:00:02.371119+0900 0xbb6f5    Debug       0x0                  4853   0    DlshogiOnCoreML: (Espresso) [com.apple.espresso:espresso] Kernel validation warning 126 (activation) @ 8: ACTIVATION_SIGMOID and ACTIVATION_TANH can be well approximated. Do precision check to make sure
2022-02-08 21:00:02.371183+0900 0xbb6f5    Debug       0x0                  4853   0    DlshogiOnCoreML: (Espresso) [com.apple.espresso:espresso] Kernel validation warning x.5 (convolution) @ 10: HW utilization loss: HW may round up computation of output sizes to multiple of 8 or 16, but the output size is 9x9
2022-02-08 21:00:02.371264+0900 0xbb6f5    Debug       0x0                  4853   0    DlshogiOnCoreML: (Espresso) [com.apple.espresso:espresso] Kernel validation warning 139 (activation) @ 11: ACTIVATION_SIGMOID and ACTIVATION_TANH can be well approximated. Do precision check to make sure
2022-02-08 21:00:02.373080+0900 0xbb6f5    Debug       0x0                  4853   0    DlshogiOnCoreML: (Espresso) [com.apple.espresso:espresso] Kernel validation warning input.93 (reshape) @ 87: Invalid input blob shape for resize/unflatten

ここまでで、Core MLで将棋の評価関数を動作させる技術検証ができました。ここからは将棋アプリを開発していきます。まずは合法手生成からです。