1. はじめに
2020年11月時点の TFLite Converter
あるいは edgetpu compiler
のどちらかにバグがあり、 TensorFlow v2.x
の tf.image.resize
オペレーションを含むモデルを量子化すると構造が壊れます。 下記に問題提起されています。
- issue : Resize Nearest Neighbor does not convert #187 - google-coral/edgetpu
- issue : Yolov4-Tiny EdgeTPU Missing Leaky Relu #51 - PINTO0309/PINTO_model_zoo
- issue : RESIZE_NEAREST_NEIGHBOR Operation version not supported #42024 - tensorflow/tensorflow
具体的には、下図の一例のようにEdgeTPUモデルへ変換した際の仕様不備により、 ResizeNearestNeighbor
あるいは ResizeBilinear
以降の変換が正しく行われないばかりか、推論実行時に edgetpu_runtime が動作不安定になりエラーを出力します。 これは TensorFlow v1.x の頃には発生していなかった事象です。 half_pixel_centers
が true
の状態のモデルを量子化して生成すると発生します。 また、 EdgeTPUモデルへ変換せず INT8量子化
を行っただけのモデルの挙動も不安定になるなど、問題が多いです。
エラーの発生例は下記のとおりですが、 ResizeNearestNeighbor
や ResizeBilinear
の部分でエラーになるわけではなく、その後ろのどこかのレイヤーで仕様アンマッチによるエラーを引き起こしますので、問題の所在がとてもわかりくいバグです。
main.ERROR - Only float32 and uint8 is supported currently, got INT8.Node number 404 (LEAKY_RELU) failed to invoke.
main.ERROR - Only float32 and uint8 are supported currently, got -1695564548.Node number 5 (PRELU) failed to invoke.
2. 回避方法
下記は Cloud TPU を使用した場合に発生する類似の問題を回避する方法をご説明いただいている記事です。 今回は下記2種類の対処を同時に実施します。
- TPUでアップサンプリングする際にエラーを出さない方法 - Shikoan's ML Blog - @koshian2さん
- Colab TPUでもtensorflow.kerasでBilinear法のアップサンプリングを行う方法 - Qiita - @fwattyさん
TensorFlow v1.x
世代の resize
オペレーションへ置き換えることにより問題を回避します。 Lamda
を経由してコールしないと Numpy 変換は対応していない、という旨のエラーが発生してしまいます。 Lamda
でラップして定義した v1.x ベースの resize オペレーションは、正常に v2.x ベースの ResizeNearestNeighbor
や ResizeBilinear
へ変換されることを確認済みです。
### 呼び出し先の関数定義 ############################################################
def upsampling2d_bilinear(x, upsampling_factor_height, upsampling_factor_width):
w = x.shape[2] * upsampling_factor_width
h = x.shape[1] * upsampling_factor_height
return tf.compat.v1.image.resize_bilinear(x, (h, w))
def upsampling2d_nearest(x, upsampling_factor_height, upsampling_factor_width):
w = x.shape[2] * upsampling_factor_width
h = x.shape[1] * upsampling_factor_height
return tf.compat.v1.image.resize_nearest_neighbor(x, (h, w))
### 呼び出し元のメインロジック #######################################################
# height方向に2倍、width方向に2倍のupsamplingを行います。整数のみ指定可能です。
x = Lambda(upsampling2d_bilinear,
arguments={'upsampling_factor_height': 2,
'upsampling_factor_width': 2})(x)
# height方向に4倍、width方向に4倍のupsamplingを行います。整数のみ指定可能です。
x = Lambda(upsampling2d_nearest,
arguments={'upsampling_factor_height': 4,
'upsampling_factor_width': 4})(x)
下図のように v1.x ベースの resize オペレーションを使用していても v2.x ベースの resize オペレーションへ正常に変換されていることが分かります。 更に half_pixel_centers
が false
に設定されていることが分かります。
edgetpu_compiler
を通して.tfliteをコンバートすると、下図のように全てのオペレーションが EdgeTPU 対応のカスタムオペレータに変換されたことが分かります。 これで EdgeTPU 上で推論を実行してもエラーになることはありません。
今回の問題を発生させる標準オペレーションは下記です。 そもそも half_pixel_centers
を設定するパラメータがありませんので外から制御することができません。
- tf.image.resize https://www.tensorflow.org/api_docs/python/tf/image/resize
tf.image.resize(
images, size, method=ResizeMethod.BILINEAR, preserve_aspect_ratio=False,
antialias=False, name=None
)
Args | Overview |
---|---|
images | 4-D Tensor of shape [batch, height, width, channels] or 3-D Tensor of shape [height, width, channels]. |
size | A 1-D int32 Tensor of 2 elements: new_height, new_width. The new size for the images. |
method | An image.ResizeMethod, or string equivalent. Defaults to bilinear. |
preserve_aspect_ratio | Whether to preserve the aspect ratio. If this is set, then images will be resized to a size that fits in size while preserving the aspect ratio of the original image. Scales up the image if size is bigger than the current size of the image. Defaults to False. |
antialias | Whether to use an anti-aliasing filter when downsampling an image. |
name | A name for this operation (optional). |
3. おわりに
以上です。 それでは皆さん、 良いTensorFlowライフを満喫してください! ちなにみに私お手製の PyTorch(NCHW) to TensoFlow(NHWC) 変換ツール
openvino2tensorflow はツールレベルで対処済みです。