0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TensorFlow Hub:Kaggle Modelで配布されているmultiple inputsを備えたTensorFlow1形式の生成AI「BigGAN」をTensorFlow Lite形式とONNX形式へと変換して保存・推論する

Last updated at Posted at 2025-04-12

Kaggle Modelで配布されているモデルをONNX形式へと変換して組み込み開発に活用しよう

TensorFlow Hub:Kaggle Model では数多くのAIモデルが配布されています。これらの多くは学習済みのAIモデルとなっていますので、学習用のデータセットを準備することなく、すぐにAIアプリケーションの実装に活用することが可能です。今回は、こうしたAIモデルを、組み込み開発でよく利用されるONNX形式へと変換し、onnxruntimeにより推論を実行する方法についてご説明いたします。

2025/04/13追記:入力テンソルを固定長にする方法は以下の通りです

本記事の範囲外 (調査中)

本記事では、ソースコードを利用してTensorFlow.Keras形式のAIモデルをONNX形式へと変換します。tf2onnxコマンドを利用した変換方法については現在調査中です(2025年4月11日現在:outputsのリストを正しく参照できていないようです)。

BigGANをONNX形式へと変換して推論する

AIモデルには様々なバリエーションがありますが、中でも生成AIである BigGAN はKaggle Modelで配布されているAIモデルをONNX形式として活用する方法を理解するためのベストプラクティスです。 BigGAN は、Imagenetで定義されるクラス(ジャンル)のうち、指定されたクラスに対応した画像を生成できるAIモデルであり、3個の入力テンソルを入力として、1個の画像を含んだ出力テンソルを生成します。

BigGANがTensorFlow Hub:Kaggle Modelを理解するためのベストプラクティスと感じる理由は、BigGANを利用するために、以下の疑問を解決しなければならないためです。 これらのポイントを抑えておけば、Kaggle Modelで配布されている大抵のAIモデルをONNX形式へと変換することができるでしょう。

  • 複数の入力を必要とするモデルを扱う方法を理解しているか
  • scalar値の入力を扱うモデルについて理解しているか
  • 出力が妥当であることを簡単に評価できるか

BigGANの出力を確認する

BigGANが生成する出力は、以下のような RGB画像を含むテンソル です。float32型で定義されているため、matplotlibを利用した以下のメソッドを定義することで簡単に可視化することができます。可視化した結果、自身が指定したクラスらしい画像を生成できていれば、BigGANの制御に成功していると言えます。 結果を評価関数に通すことなく、目視で結果を評価できるため、わかりやすいです。

export_1.png

### (128, 128, 3)のテンソルを画像として保存するメソッド
def save_tensor_as_image(image_tensor, title):
  # 一度に1個の画像のみを扱う
  n = 1
  # BigGANの生成する画像サイズを基に計算する
  image_size = 128
  # ピクセル数から幅を決定する
  w = (image_size * 6) // 320
  # グラフの縦と横の長さを設定する
  plt.figure(figsize=(w * n, w * 1.1))
  # グラフに0.0~1.0の値を取る画像をプロットする
  plt.imshow(image_tensor, aspect='equal')
  plt.axis('off')
  plt.title(title)
  # PNG形式で保存する
  plt.savefig("export.png")
  
### -1.0~+1.0の出力テンソルの値を0.0~1.0に丸める
output = (output * 0.5) + 0.5

### 出力テンソルを画像として保存する
save_tensor_as_image(output[0], 'Output Image')

学習済みのBigGANを含むONNX形式のモデルで推論する

それでは実装をはじめましょう。

必要なパッケージをimportする

まず、以下のパッケージをimportします。各パッケージのバージョンは本記事末尾に掲載する requirements.txt の内容をご参照ください。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow_hub as hub
import tf2onnx
import onnx
import onnxruntime
from onnxruntime.datasets import get_example

複数入力をとるKerasLayerの扱い方

次に、TensorFlow Hub:Kaggle Modelから学習済みのモデルを取得し、これをレイヤーとしたモデルを生成します。TensorFlow Hub:Kaggle Modelのモデルを基にレイヤーを作成するためには hub.KerasLayer を利用します。レイヤーを定義した後に keras.Input で定義した入力テンソルを接続します。複数の入力を結合するためには dict を使用します。これらの要素に基づいて、Kerasの提供するFuncational API機能を利用し、モデルを定義します。 特にinput_truncation を定義する方法について注意してください。このInputはscalar値であるため batch_shape() 引数を利用して、batch_sizeを含まないInputとなるように定義する必要があります。

モデルを定義した後に build メソッドを呼び出してモデルを確定させ、 summary メソッドを実行して期待するモデルを定義でいていることを確認します。問題なくAIモデルが構成できていれば save メソッドで保存しましょう。

######
### 指定したURLからモデルを取得してKeras形式のAIモデルを定義する
######
model_url = "https://www.kaggle.com/models/deepmind/biggan/TensorFlow1/128/2"

### AIモデルの入力を定義する
# truncation (scalar)
input_truncation = keras.Input(batch_shape=(), name='truncation')
# class (1, 1000)
input_y = keras.Input(shape=(1000, ), name='y')
# noize (1, 120)
input_z = keras.Input(shape=(120, ), name='z')

# Kaggleから取得したAIモデルをKerasLayerに変換する
hub_layer = hub.KerasLayer(
            model_url,
            trainable=False,
            signature="default", 
            signature_outputs_as_dict=True,
        )
        
# 複数の入力(multiple inputs)をKerasLayerに接続する(dictを利用する)
inputs = dict(y=input_y, z=input_z, truncation=input_truncation)
output = hub_layer(inputs)

### KerasのFunctional API機能を利用し
### 入力テンソルと出力テンソルを指定してモデルを定義する
model = tf.keras.models.Model(inputs=[input_truncation, input_y, input_z], outputs=[output])

### モデルをビルドする
model.build(([1], [1, 1000], [1, 120]))

### モデルのサマリーを表示する
model.summary()

### Kerasモデルを保存する
model.save("biggan-128")
Model: "model"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 truncation (InputLayer)        [None]               0           []                               
                                                                                                  
 y (InputLayer)                 [(None, 1000)]       0           []                               
                                                                                                  
 z (InputLayer)                 [(None, 120)]        0           []                               
                                                                                                  
 keras_layer (KerasLayer)       {'default': (None,   141028845   ['truncation[0][0]',             
                                128, 128, 3)}                     'y[0][0]',                      
                                                                  'z[0][0]']                      
                                                                                                  
==================================================================================================
Total params: 141,028,845
Trainable params: 0
Non-trainable params: 141,028,845

Kaggleから読み込んだTensorFlow1形式のAIモデルをTensorFlow Lite形式として保存する

続いて、ネットワークをNetronで可視化するために、AIモデルをTensorFlow Lite形式へと変換して保存します。 tf.lite.TFLiteConverter.from_keras_model を利用することにより、簡単にKeras形式のモデルをTensorFlow Lite形式へと変換、保存することが可能です。ここで保存されたtflite形式のファイルを可視化すると以下のようになります。可視化した際に serving_default_truncation:0, serving_default_y:0, serving_default_z:0 の入力テンソルと StatefulPartitionedCall:0 の出力テンソルが定義されていることを確認しておきましょう。

### Keras形式のAIモデルをTensorFlow Lite形式へと変換して保存する
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
open("biggan-128.tflite", "wb").write(tflite_model)

image.png

Kaggleから読み込んだTensorFlow1形式のAIモデルをKeras形式のAIモデルを介してONNX形式へと変換する

TensorFlow Lite形式のモデルを利用し、AIモデルの内容を可視化できるかを確認した後に tf2onnx.convert.from_keras メソッドを利用して、Keras形式のAIモデルをONNX形式へと変換し、保存します。ここで保存したONNX形式のAIモデルも、Netronを利用することにより、内容を確認することができます。Netronでモデルを可視化した際に truncation(float32), y(float32), z(float32) の入力テンソルと keras_layer(float32) の出力テンソルが定義されていることを確認しておきましょう。 またこのとき各入力テンソルと出力テンソルのshapeも確認しておいてください。

### Keras形式のAIモデルをONNX形式へと変換して保存する
onnx_model, _ = tf2onnx.convert.from_keras(model, outputs_as_nchw=[model.outputs[0].name])
onnx.save(onnx_model, './biggan-128.onnx')

image.png

ONNX形式のAIモデルで推論を実行する

ONNX形式で保存したAIモデルを実行するために onnxruntime から InferenceSession クラスのコンストラクタを利用して開きます。

### 推論用にモデルをロードする
sess = onnxruntime.InferenceSession('./biggan-128.onnx', providers=['CPUExecutionProvider'])

ONNX形式のAIモデルを開いた後に sess.get_inputs()sess.get_outputs() の内容を確認することにより、AIモデルを実行する際に、どのような入力テンソルが必要であり、どのように出力テンソルをデコードすれば良いかについて知ることができます。ソースコードを実行すると、以下のように、AIモデルの実行には入力テンソルに truncation[](scalar), y[batch_size, 1000], z[batch_size, 120] が必要であり、AIモデルが出力テンソルとして keras_layer[batch_size, 128, 128, 3] を生成することがわかります。 これらの構成は前の手順でNetronにより可視化したAIモデルの情報と一致します。

### 入力テンソルと出力テンソルの名前とshapeを出力する
inputs_onnx_model = sess.get_inputs()
for i in range(len(inputs_onnx_model)):
    input_name = inputs_onnx_model[i].name
    print("Input name  :", input_name)
    input_shape = inputs_onnx_model[i].shape
    print("Input shape :", input_shape)
    input_type = inputs_onnx_model[i].type
    print("Input type  :", input_type)
    print()

outputs_onnx_model = sess.get_outputs()
for i in range(len(outputs_onnx_model)):
    output_name = outputs_onnx_model[i].name
    print("Output name  :", output_name)  
    output_shape = outputs_onnx_model[i].shape
    print("Output shape :", output_shape)
    output_type = outputs_onnx_model[i].type
    print("Output type  :", output_type)
    print()
Input name  : truncation
Input shape : []
Input type  : tensor(float)

Input name  : y
Input shape : ['unk__234', 1000]
Input type  : tensor(float)

Input name  : z
Input shape : ['unk__235', 120]
Input type  : tensor(float)

Output name  : keras_layer
Output shape : ['unk__236', 128, 128, 3]
Output type  : tensor(float)

以下はNetronにより可視化したInputsとOutputsです。

スクリーンショット 2025-04-12 202947.png

入力テンソルを作成する

入力テンソルの型に基づいて、以下のように入力テンソルを定義します。

######
### 入力テンソルを作成する
######
# trunction
# -->> スカラー値
truncation = np.full((), 0.2, dtype=np.float32)
# クラスを選択するOne-Hot-Enodingテンソル(1000クラス)
# -->> [batch_size, 1000]
y = np.zeros((1, 1000), dtype=np.float32)
y[0][207] = 1.0 # golden retriever
# バリエーションを与えるテンソル(120個の乱数)
# -->> [batch_size, 120]
z = np.random.randn(1, 120).astype(np.float32)

ここで tuncation の値は、Pythonの通常のスカラー値 float でなく、Numpyの定義する np.float32 型を持つスカラー値であることに注意してください。 なお、 y の値はOne-Hot-Encodingでクラスを示すフラグを含んだベクトルであり、z の値は生成する画像にバリエーションを与えるための乱数を格納したベクトルです。ベクトルの詳しい意味については、BigGANの解説 ページをご参照ください。

推論を実行する

作成した入力テンソルを辞書形式に加工して、これを引数として sess.run() メソッドを実行することにより、推論が実行され、生成AIにより生成された画像をテンソル outpuut として取得することができます。なお、outputのshapeは [batch_size, 128, 128, 3] のため、他のプログラムが出力テンソルを参照する前に np.reshape(output, [-1, 128, 128, 3]) メソッドを利用して、整形しておきましょう。

### 推論を実行する
output = sess.run(["keras_layer"],
                  {"truncation":truncation, "y": y, "z": z,},)

### 出力テンソルのshapeを[batch_size, 128, 128, 3]にする
output = np.reshape(output, [-1, 128, 128, 3])

### 推論完了
print("sess.run finished.")

matplotlib.pyplotを利用して出力テンソルを画像として保存する

最後に、出力テンソルを画像として保存すれば、完了です。

######
### (128, 128, 3)のテンソルを画像として保存するメソッド
######
def save_tensor_as_image(image_tensor, title):
  n = 1
  image_size = 128
  w = (image_size * 6) // 320
  plt.figure(figsize=(w * n, w * 1.1))
  plt.imshow(image_tensor, aspect='equal')
  plt.axis('off')
  plt.title(title)
  plt.savefig("export.png")

### -1.0~+1.0の出力テンソルの値を0.0~1.0に丸める
output = (output * 0.5) + 0.5

### 出力テンソルを画像として保存する
save_tensor_as_image(output[0], 'Output Image')

export.png

期待する画像を取得できましたね!


補足:入力テンソルと出力テンソルのshapeを固定する

作成したONNX形式のモデルに対して、以下のコマンドを実行することにより、Input shapeとOutput shapeを固定することができます(ここでは1に固定しています)。指定している unk__234unk__235 はNetronで確認できる変数です。組み込み開発では、 AIモデルをGPU以外のハードウェアアクセラレータへで実行する際に、固定長でAIモデルを扱うこともあるため、そうした場面で本コマンドは有用です。

### yを固定する(Outputsも固定される)
$ python -m onnxruntime.tools.make_dynamic_shape_fixed --dim_param unk__234 --dim_value 1 biggan-128.onnx biggan-128_fixed.onnx
### zを固定する
$ python -m onnxruntime.tools.make_dynamic_shape_fixed --dim_param unk__235 --dim_value 1 biggan-128_fixed.onnx biggan-128_fixed.onnx

固定する前のshape

スクリーンショット 2025-04-12 202947.png

固定した後のshape

スクリーンショット 2025-04-12 204454.png


本記事の内容により、複数入力とスカラー値の入力を持つ
Kaggle Model(TF1.x)をONNX形式へと変換できました!

なかなかKaggle ModelをONNXとして利用する方法や、
複数の入力を扱うKerasLayerの扱い方についての
情報が見当たらないため、まとめてみました。

内容としては簡単ですので、是非お試しください!!


本記事が解決するQ&A


ソースコード全文

以下に今回実装したソースコード全文を掲載します。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow_hub as hub
import tf2onnx
import onnx
import onnxruntime
from onnxruntime.datasets import get_example

######
### 指定したURLからモデルを取得してKeras形式のAIモデルを定義する
######
model_url = "https://www.kaggle.com/models/deepmind/biggan/TensorFlow1/128/2"

### AIモデルの入力を定義する
# truncation (scalar)
input_truncation = keras.Input(batch_shape=(), name='truncation')
# class (1, 1000)
input_y = keras.Input(shape=(1000, ), name='y')
# noize (1, 120)
input_z = keras.Input(shape=(120, ), name='z')

# Kaggleから取得したAIモデルをKerasLayerに変換する
hub_layer = hub.KerasLayer(
            model_url,
            trainable=False,
            signature="default", 
            signature_outputs_as_dict=True,
        )
        
# 複数の入力(multiple inputs)をKerasLayerに接続する(dictを利用する)
inputs = dict(y=input_y, z=input_z, truncation=input_truncation)
output = hub_layer(inputs)

### KerasのFunctional API機能を利用し
### 入力テンソルと出力テンソルを指定してモデルを定義する
model = tf.keras.models.Model(inputs=[input_truncation, input_y, input_z], outputs=[output])

### モデルをビルドする
model.build(([1], [1, 1000], [1, 120]))

### モデルのサマリーを表示する
model.summary()

### Kerasモデルを保存する
model.save("biggan-128")

### Keras形式のAIモデルをTensorFlow Lite形式へと変換して保存する
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
open("biggan-128.tflite", "wb").write(tflite_model)

### Keras形式のAIモデルをONNX形式へと変換して保存する
onnx_model, _ = tf2onnx.convert.from_keras(model, outputs_as_nchw=[model.outputs[0].name])
onnx.save(onnx_model, './biggan-128.onnx')

### 推論用にモデルをロードする
sess = onnxruntime.InferenceSession('./biggan-128.onnx', providers=['CPUExecutionProvider'])

### 入力テンソルと出力テンソルの名前とshapeを出力する
inputs_onnx_model = sess.get_inputs()
for i in range(len(inputs_onnx_model)):
    input_name = inputs_onnx_model[i].name
    print("Input name  :", input_name)
    input_shape = inputs_onnx_model[i].shape
    print("Input shape :", input_shape)
    input_type = inputs_onnx_model[i].type
    print("Input type  :", input_type)
    print()

outputs_onnx_model = sess.get_outputs()
for i in range(len(outputs_onnx_model)):
    output_name = outputs_onnx_model[i].name
    print("Output name  :", output_name)  
    output_shape = outputs_onnx_model[i].shape
    print("Output shape :", output_shape)
    output_type = outputs_onnx_model[i].type
    print("Output type  :", output_type)
    print()

######
### 入力テンソルを作成する
######
# trunction
# -->> スカラー値
truncation = np.full((), 0.2, dtype=np.float32)
# クラスを選択するOne-Hot-Enodingテンソル(1000クラス)
# -->> [batch_size, 1000]
y = np.zeros((1, 1000), dtype=np.float32)
y[0][207] = 1.0 # golden retriever
# バリエーションを与えるテンソル(120個の乱数)
# -->> [batch_size, 120]
z = np.random.randn(1, 120).astype(np.float32)

### 推論を実行する
output = sess.run(["keras_layer"],
                  {"truncation":truncation, "y": y, "z": z,},)

### 出力テンソルのshapeを[batch_size, 128, 128, 3]にする
output = np.reshape(output, [-1, 128, 128, 3])

### 推論完了
print("sess.run finished.")

######
### (128, 128, 3)のテンソルを画像として保存するメソッド
######
def save_tensor_as_image(image_tensor, title):
  n = 1
  image_size = 128
  w = (image_size * 6) // 320
  plt.figure(figsize=(w * n, w * 1.1))
  plt.imshow(image_tensor, aspect='equal')
  plt.axis('off')
  plt.title(title)
  plt.savefig("export.png")

### -1.0~+1.0の出力テンソルの値を0.0~1.0に丸める
output = (output * 0.5) + 0.5

### 出力テンソルを画像として保存する
save_tensor_as_image(output[0], 'Output Image')

requirements.txt

absl-py==2.2.1
astunparse==1.6.3
cachetools==5.5.2
certifi==2025.1.31
charset-normalizer==3.4.1
coloredlogs==15.0.1
contourpy==1.3.1
cycler==0.12.1
flatbuffers==1.12
fonttools==4.57.0
gast==0.4.0
google-auth==2.38.0
google-auth-oauthlib==0.4.6
google-pasta==0.2.0
grpcio==1.71.0
h5py==3.13.0
humanfriendly==10.0
idna==3.10
keras==2.9.0
Keras-Preprocessing==1.1.2
kiwisolver==1.4.8
libclang==18.1.1
Markdown==3.7
MarkupSafe==3.0.2
matplotlib==3.10.1
mpmath==1.3.0
numpy==1.23.5
oauthlib==3.2.2
onnx==1.14.1
onnx-graphsurgeon==0.5.7
onnx2tf==1.26.9
onnxruntime==1.21.0
opt_einsum==3.4.0
packaging==24.2
pillow==11.1.0
protobuf==3.20.3
psutil==7.0.0
pyasn1==0.6.1
pyasn1_modules==0.4.2
pyparsing==3.2.3
python-dateutil==2.9.0.post0
requests==2.32.3
requests-oauthlib==2.0.0
rsa==4.9
six==1.17.0
sng4onnx==1.0.4
sympy==1.13.3
tensorboard==2.9.0
tensorboard-data-server==0.6.1
tensorboard-plugin-wit==1.8.1
tensorflow==2.9.0
tensorflow-estimator==2.9.0
tensorflow-hub==0.16.1
tensorflow-io-gcs-filesystem==0.37.1
tensorflow-neuron==1.0
termcolor==3.0.0
tf-keras==2.14.1
tf2onnx==1.13.0
typing_extensions==4.13.0
urllib3==2.3.0
Werkzeug==3.1.3
wrapt==1.17.2

記事は以上となります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?