Tensorflow で crop_and_resize を使うと onnx 変換で中間レイヤーの入力 shape 未確定エラーする

Page content

今回のネタはかなり細かい話なので、前提の説明が必要になる。 調べた結果を最初に書いておくので、それ以降は興味のある人向け。

TL;DR

  • tensorflow の crop_and_resize を使ったモデルを onnx 変換する時は opset 14 以上 を使え

crop_and_resize とは

AI を使って画像からオブジェクトを検出し、 そのオブジェクトを識別する際の実現方法は次の2つに分かれる。

  • 解析対象の画像を入力してオブジェクトの検出と、識別をそれぞれ別々に行なう2つのモデルを用意する
  • 解析対象の画像を入力し、1つのモデル内でオブジェクトの検出と識別を連続して行なうモデルを用意する

前者の「別々に行なうモデル」は、 オブジェクトの検出モデルと、その検出された領域情報を使って画像を切り抜き、 切り抜いた画像を識別モデルに入力して識別結果を得る。 つまり 「別々に行なうモデル」は、2 つのモデルの間に AI 処理ではない機械的な処理が動く。

一方で後者の「1つのモデル内で連続で行なうモデル」は、 AIモデルに画像を入力すると、オブジェクトの領域と識別結果が得られる。

そもそも、なんで検出と識別のモデルを分ける必要があるかというと、 検出はある程度大雑把な特徴量で処理できることが多いのに対し、 識別は細かい特徴量で処理する必要があり、 それぞれで適したモデル構造が異なる為だ。

また、検出された領域情報を使って切り抜かれた画像を識別モデルに入力することで、 識別に関係のない情報(切り抜き外の領域画像)に影響されずに特徴量を抽出し 識別精度向上が期待できる。

そして、検出モデルと識別モデルのそれぞれを繋げて 一つの AI モデルとするために必要なのが、 今回のネタの crop_and_resize である訳だ。

onnx とは

AI 処理は、膨大な計算が必要で様々な定石が判っている。 それらを 1 から作るのは大変なので、 pytorch や tensorflow などの様々なフレームワークが利用されている。

そして、フレームワークには様々な種類があり、フレームワーク間に互換性はない。 つまり、 pytorch で開発された AI モデルは tensorflow では動かない。

そこで登場するのが onnx となる。

onnx は、 AI モデルの推論に特化した規格で、 pytorch や tensorflow などのフレームワークで開発した AI モデルを onnx 形式に変換することで、 onnx ランタイムが動く環境であればどこでも動かせるようになる。

もちろん、onnx ランタイムを動かせることが条件になるが、 推論に特化していることで構成がシンプルになり、 それぞれのフレームワークを動かすよりはハードルが下がる。

ただ、いま世間で話題になっているローカルで動かせる AI ツールの大部分は、 onnx は使用せずに各種フレームワーク向けのモデルのまま動かしている状況だと思う。

では onnx モデルは誰が使っているのか?というと、 主に有償ソフトの AI 機能として利用しているケースがメインだと思う。

何故かといえば、 onnx ではなく各種フレームワークをそのまま使おうとなると、 各種フレームワークのセットアップが必要になる。 有償ソフトで各種フレームワークのインストールを行なわせる、 というのはかなりのハードルの高さになるので、 そのようなインストールが不要な onnx が選択肢になる。

なお、Mac の場合はオープン技術ではなく独自路線が大好きなので、 onnx ではなく Core ML という Apple 独自の技術が利用されている。

そして、今回のネタは tensorflow の AI モデルを onnx に変換する話だ。

onnx 変換で中間レイヤーの入力 shape 未確定エラーする

前置きがだいぶ長くなったがようやく本題になる。

Tensorflow で crop_and_resize を使うと、 onnx 変換時に中間レイヤーの入力 shape が未確定というエラーが発生する。

どういうことだか意味不明だと思うが、自分自身も全て理解している訳ではない。

確実なのは、

  • onnx は、AI の推論処理に必要な処理を集めた規格である
  • 「onnx 変換」は、各種フレームワークで定義している AI モデルのレイヤー構造を、 onnx で定義されているレイヤー構造に置き換えている
  • その置き換え処理で何らかのエラーが発生している

なお、 AI 処理が日々進化しているように、onnx もバージョン更新を続けている。

<https://onnx.ai/onnx/repo-docs/Versioning.html#released-versions>

これは何故かというと、AI の推論に必要な処理が増えていっているからだ。

AI の推論処理の大部分は行列演算である。これは間違いない。

しかし、行列演算と言ってもそのパターンは様々である。

それこそ、 AI 研究ではその行列演算をどう行なうかが日々研究されている。 各種フレームワークを利用して、その行列演算の有効性を実証し、報告されている。

一方で onnx は推論に特化している。 その実現方法は、特定の行列演算の組み合わせに特化する形ではなく、 汎用的に作られている。 具体的には、onnx は「MatMul」や「Conv」といった基本的な演算子のセットを定義し、 それらを自由に組み合わせることで、様々なAIモデルを表現する仕組みである。

しかし、現実問題として既存の演算子では表現できない全く新しい「基本演算」が 発明された場合や、 int8 などの量子化への対応などで常にバージョンの更新が 必要になっている。

対応方法

今回の tensorflow の crop_and_resize も、 onnx バージョンの更新によって追加対応された機能が必要になる処理になる。

よって onnx 変換する際に指定する opset は、所定のバージョン以上を指定する必要がある。

そして、onnx 変換時に指定する opset バージョンが所定のバージョンよりも低いと、 「onnx 変換時に中間レイヤーの入力 shape が未確定というエラーが発生する」ということだ。

では、具体的にどの opset バージョンを指定すればいいかと言うと、 次のバージョンを指定するとエラーなく変換できた。

opset 14

これを解決するために、もろもろ合せると何だかんだで 3 日ほど掛った。。。