Armadilloフォーラム

量子化したtfliteモデルの出力が一定値になってしまう

toshiki814

2022年1月21日 16時26分

お世話になっております。 金田です。

現在、armadillo IoT G4用にuint8量子化したtfliteモデルを作成しました。
しかしながら、このモデルに対して、異なる画像を入力しても、出力が一定値になってしまう問題が発生しています。

"float32量子化"の場合には、出力は一定値にならず、"問題なく取得"することができます。

問題を再現するプログラムを添付いたします。
main.pyの上部に書かれているrequirementを実行していただき、main.pyを実行していただければ、問題が再現できると思います。
プログラムの流れとしては、pytorchモデルをonnx経由でtensorflowモデルに変換し、そこから量子化を行ってtfliteモデルを作成しています。
uint8量子化を行っている部分は、pt2tflite.pyファイルの143行目から165行目になります。pt2tflite.pyファイルのfloat32量子化は167行目から171行目になります。
出力が変化したかどうかは、異なる画像をモデルに二枚いれて、各出力の差の最大最小を見ています。

機械学習寄りの質問にはなってしまいますが、原因が分かる方がいましたら、助言を頂けると幸いです。

ファイル ファイルの説明
toshiki814.zip 再現プログラム
コメント

at_akihito.irie

2022年1月26日 18時44分

入江です。

当方でも同じ現象が再現できました。

原因の調査に当たっておりますので、今しばらくお待ちください。

以上、よろしくお願いいたします。

at_akihito.irie

2022年1月28日 13時23分

入江です。

現状、正確な原因を特定できておらず申し訳ございませんが、モデルの変換に
おいてKerasを経由することで異なる入力毎に出力が変化することが確認でき
ましたので、取り急ぎ手順のみご案内します。

モデル変換のルートとしましては、Pytorch->onnx->Keras->TFLiteです。

model.onnxを生成するまでは頂いたソースコードのままです。

以下のようにonnx->Kerasの変換を行います。model.onnxへのパスは適宜読み
替えてください

import onnx
from onnx2keras import onnx_to_keras
 
onnx_model = onnx.load('/path/to/model.onnx')
k_model = onnx_to_keras(onnx_model=onnx_model, input_names=['input'],
                        change_ordering=True, verbose=False)

ここで、onnx_to_kerasの引数としてchange_ordering=Trueを指定することで、
モデルの入力がchannel-first(NCHW)からchannel-last(NHWC)に変換されます。

生成したk_modelをTFLiteへ変換します。下の実行例は量子化しない例です。

converter = tf.lite.TFLiteConverter.from_keras_model(k_model)
tflite_model = converter.convert()
 
with open('./float32_via_keras.tflite', 'wb') as f:
    f.write(tflite_model)

量子化を行う場合は以下のように変換を行います。
データセットへのパスは適宜読み替えてください。

def representative_data_gen():
    dataset_list = tf.data.Dataset.list_files('/path/to/dataset/' +  "*.png")
    for i in range(len(os.listdir('/path/to/dataset'))):
        image = next(iter(dataset_list))
        image = tf.io.read_file(image)
        image = tf.io.decode_jpeg(image, channels=3)
        image = tf.image.resize(image, [224, 224])
        image = tf.cast(image / 255, tf.float32)
        image = tf.expand_dims(image, 0) ★変更点
        yield [image]
 
converter = tf.lite.TFLiteConverter.from_keras_model(k_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
tflite_model = converter.convert()
 
with open('./uint8_via_keras.tflite', 'wb') as f:
    f.write(tflite_model)

representative_data_genは頂いたソースから一部変更しています。
★変更点: Kerasを経由した時にNHWCに変換したので、transposeは必要なくなりました。

checker.pyのtflite_outputも同様にinputのtransposeを削除してください。

最後に生成したモデルでcheck_outputを実行すると、当方の環境では異なる入
力毎に出力も変わるようになりましたので、お試しください。

toshiki814

2022年1月28日 15時50分

入江 様

返信ありがとうございます。

入江様の助言の通りに、Keras経由でモデルを変換したところ、こちらの環境でも、
異なる入力毎に出力が変化することが確認できました。

非常に助かりました。
ありがとうございますした。

金田