EfficientNet B0의 Keeras 모델을 ONX 모델로 변환하여 추론
개시하다
"불합리한 이미지 분류기를 만들어 보다"시리즈에서 Keeras와 EfficientNetB0을 사용하여 이미지 분류기를 실현했다.
나는 그 이미지 분류 모델을 ONX 모델로 바꾸어 추론하고 싶다.
ONX가 뭐예요?
온NX(Open Neural Network Exchange)는 페이스북, 마이크로소프트가 주도해 머신러닝 프레임워크를 상호 운용하는 프로그램이다.자세한 내용은 먼저 구글에서 확인하세요.
왜 ONX 모형으로 바꿨어요?
개인적으로 가장 큰 이유는'ONXRuntime의 추론이 빠르다'는 것이지만, 추론할 때Kers, PyTorch 등 서로 다른 기계 학습 프레임워크를 사용해 학습하는 모델을 통일적으로 처리할 수 있다는 기쁨도 있다.
모형을 바꾸는 두 가지 방법
대략적인 조사만 하면 Kers 모델을 ONX 모델로 변환하는 방법은 다음과 같은 두 가지가 있다.
tf2onnx로 변환 ← 추천!keras2onnx로 변환 ← 실패또 이 글은 학습을 하지 않고 전환, 추론만 하고 학습 후 전환하는 순서도 같다.
컨디션
어떤 변환, 추론이든 다음과 같은 환경에서 집행된다.Docker 내에서 실행되며 GPU는 사용되지 않습니다.
tf2 onx로 변환→성공
tf2onnx는 TensorFolow 모델을 ONX 모델로 변환하는 도구입니다.
Kers에서 모델을 만든 후 TensorFolow Saved Model 형식으로 모델을 저장하면 이 도구로 변환할 수 있습니다.
Kers H5 형식은 사용할 수 없습니다.
Docker 이미지 만들기
사용한 경우
Dockerfile와 requirements.txt는 다음과 같다.Dockerfile
FROM nvidia/cuda:11.0.3-cudnn8-devel-ubuntu20.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \
build-essential \
ca-certificates \
python3-dev \
python3-pip \
python3-setuptools \
tzdata \
&& rm --recursive --force /var/lib/apt/lists/*
RUN python3 -m pip install --upgrade pip setuptools
WORKDIR /opt/app
COPY requirements.txt ./
RUN python3 -m pip install --requirement requirements.txt
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
requirements.txtonnxruntime==1.7.0
tensorflow-hub==0.11.0
tensorflow==2.4.1
tf2onnx==1.8.4
모델 생성
TensorFlow Hub에서 학습한 EfficientNet B0를 그대로 저장하여 모델 파일을 생성합니다.
원래 공부를 했는데 이번에는 전환 전후를 통해 학습 전의 추론 결과를 비교하여 전환의 성공 여부를 판단한다.
save_model.py
#!/usr/bin/env python3
import tensorflow as tf
import tensorflow_hub as hub
model = tf.keras.Sequential(
[
hub.KerasLayer(
"https://tfhub.dev/tensorflow/efficientnet/b0/feature-vector/1",
trainable=False,
),
tf.keras.layers.Dense(1, activation="sigmoid"),
]
)
model.build([None, 224, 224, 3])
model.summary()
model.save("efficientnet-b0")
실행 예는 다음과 같다.성공하면 efficientnet-b0 디렉터리를 생성합니다.$ ./save_model.py
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
keras_layer (KerasLayer) (None, 1280) 4049564
_________________________________________________________________
dense (Dense) (None, 1) 1281
=================================================================
Total params: 4,050,845
Trainable params: 1,281
Non-trainable params: 4,049,564
_________________________________________________________________
2021-04-23 00:07:12.365759: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
$ ls efficientnet-b0
assets saved_model.pb variables
Keeras로 추론하다
원스 모델로 전환하기 전에 케어스의 추론 결과를 확인해 보자.
여기에 흑백 두 장의 그림에 대해 추론을 진행한다.
predict_keras.py
#!/usr/bin/env python3
import numpy as np
import tensorflow as tf
model = tf.keras.models.load_model("efficientnet-b0")
images = np.array(
[
np.zeros((224, 224, 3), dtype=np.float32),
np.ones((224, 224, 3), dtype=np.float32),
]
)
results = model.predict(images)
print(results)
실행 예는 다음과 같다.모든 조합 층은 무작위 수로 초기화되어 있기 때문에 모델을 저장할 때마다 값이 달라질 수 있음을 주의하십시오.$ ./predict_keras.py
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
[[0.5295639]
[0.5148043]]
변환 모델
tf2onnx를 사용하여 모델을 변환합니다.convert.sh
#!/bin/bash
python3 -m tf2onnx.convert --saved-model efficientnet-b0 --output efficientnet-b0.onnx
실행 예는 다음과 같다.몇 개의 경고를 내보냈지만 이번에는 무시했다.$ ./convert.sh
/usr/lib/python3.8/runpy.py:127: RuntimeWarning: 'tf2onnx.convert' found in sys.modules after import of package 'tf2onnx', but prior to execution of 'tf2onnx.convert'; this may result in unpredictable behaviour
warn(RuntimeWarning(msg))
2021-04-23 00:14:01,125 - WARNING - '--tag' not specified for saved_model. Using --tag serve
2021-04-23 00:14:06,873 - INFO - Signatures found in model: [serving_default].
2021-04-23 00:14:06,873 - WARNING - '--signature_def' not specified, using first signature: serving_default
2021-04-23 00:14:06,873 - INFO - Output names: ['dense']
WARNING:tensorflow:From /usr/local/lib/python3.8/dist-packages/tf2onnx/tf_loader.py:557: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.compat.v1.graph_util.extract_sub_graph`
2021-04-23 00:14:09,553 - WARNING - From /usr/local/lib/python3.8/dist-packages/tf2onnx/tf_loader.py:557: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.compat.v1.graph_util.extract_sub_graph`
2021-04-23 00:14:10,275 - INFO - Using tensorflow=2.4.1, onnx=1.9.0, tf2onnx=1.8.4/cd55bf
2021-04-23 00:14:10,275 - INFO - Using opset <onnx, 9>
2021-04-23 00:14:11,053 - INFO - Computed 0 values for constant folding
2021-04-23 00:14:13,763 - INFO - Optimizing ONNX model
2021-04-23 00:14:17,027 - INFO - After optimization: BatchNormalization -42 (49->7), Const -240 (442->202), Identity -926 (926->0), Squeeze -16 (16->0), Transpose -275 (276->1), Unsqueeze -64 (64->0)
2021-04-23 00:14:17,056 - INFO -
2021-04-23 00:14:17,057 - INFO - Successfully converted TensorFlow model efficientnet-b0 to ONNX
2021-04-23 00:14:17,057 - INFO - Model inputs: ['keras_layer_input:0']
2021-04-23 00:14:17,057 - INFO - Model outputs: ['dense']
2021-04-23 00:14:17,057 - INFO - ONNX model is saved at efficientnet-b0.onnx
원스로 추론하다
변환된 ONX 모델을 사용하여 추론합니다.
predict_onnx.py
#!/usr/bin/env python3
import numpy as np
import onnxruntime
session = onnxruntime.InferenceSession("efficientnet-b0.onnx")
images = np.array(
[
np.zeros((224, 224, 3), dtype=np.float32),
np.ones((224, 224, 3), dtype=np.float32),
]
)
results = session.run(["dense"], {"keras_layer_input:0": images})
print(results)
실행 예는 다음과 같다.$ ./predict_onnx.py
[array([[0.52956396],
[0.5148051 ]], dtype=float32)]
케어스 모델의 추론 결과와 엄격하게 일치하지 않지만 소수점 5위까지 일치하기 때문에 문제가 없는 것 같습니다.keras2 onx로 변환 → 실패
다음은 keras2onnx로 변환해 보세요.
tf2onnx의 전환은 단번에 성공했지만 keras2onnx의 전환은 상당히 어렵다.참고는 다음과 같습니다.
keras2onnx는 TensorFlowv2입니다.4 대응 없음, TensorFlowv2.대응(2021년 4월 23일 기준, v1.7.0)Docker 이미지 만들기
사용한 경우
Dockerfile와 requirements.txt는 다음과 같다.CUDA, TensorFolow의 버전 등과
tf2onnx의 상황은 다르다.Dockerfile
FROM nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \
build-essential \
ca-certificates \
python3-dev \
python3-pip \
python3-setuptools \
tzdata \
&& rm --recursive --force /var/lib/apt/lists/*
RUN python3 -m pip install --upgrade pip setuptools
WORKDIR /opt/app
COPY requirements.txt ./
RUN python3 -m pip install --requirement requirements.txt
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
requirements.txtkeras2onnx==1.7.0
onnxruntime==1.7.0
tensorflow-hub==0.11.0
tensorflow==2.2.1
모델 생성
기본 단계는
tf2onnx와 같지만 왜fit나 predict를 호출하지 않으면 모델을 저장할 때 오류가 발생합니다.save_model.py
#!/usr/bin/env python3
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
model = tf.keras.Sequential(
[
hub.KerasLayer(
"https://tfhub.dev/tensorflow/efficientnet/b0/feature-vector/1",
trainable=False,
),
tf.keras.layers.Dense(1, activation="sigmoid"),
]
)
model.build([None, 224, 224, 3])
model.summary()
model.predict(np.zeros((1, 224, 224, 3), dtype=np.float32))
model.save("efficientnet-b0")
실행 예는 다음과 같습니다.$ ./save_model.py
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
keras_layer (KerasLayer) multiple 4049564
_________________________________________________________________
dense (Dense) multiple 1281
=================================================================
Total params: 4,050,845
Trainable params: 1,281
Non-trainable params: 4,049,564
_________________________________________________________________
2021-04-23 00:35:08.379870: W tensorflow/python/util/util.cc:329] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
Keeras로 추론하다
소스 코드가
tf2onnx와 같기 때문에 생략합니다.실행 예는 다음과 같다.
$ ./predict_keras.py
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
[[0.41439614]
[0.43379608]]
변환 모델
keras2onnx를 사용하여 모델을 변환합니다.convert.py
#!/usr/bin/env python3
import keras2onnx
import onnx
import tensorflow as tf
model = tf.keras.models.load_model("efficientnet-b0")
onnx_model = keras2onnx.convert_keras(model, "efficientnet-b0")
onnx.save_model(onnx_model, "efficientnet-b0.onnx")
실행 예는 다음과 같다.$ ./convert.py
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
tf executing eager_mode: True
tf.keras model eager_mode: False
2021-04-23 00:41:39.446674: W tensorflow/python/util/util.cc:329] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARN: No corresponding ONNX op matches the tf.op node sequential/keras_layer/StatefulPartitionedCall/StatefulPartitionedCall/StatefulPartitionedCall/StatefulPartitionedCall/StatefulPartitionedCall/tf_op_layer_BroadcastTo_1/PartitionedCall/BroadcastTo_1 of type BroadcastTo
The generated ONNX model needs run with the custom op supports.
The ONNX operator number change on the optimization: 4007 -> 492
원스로 추론하다
소스 코드가
tf2onnx와 같기 때문에 생략합니다.실행 예는 다음과 같다.
$ ./predict_onnx.py
Traceback (most recent call last):
File "./predict_onnx.py", line 6, in <module>
session = onnxruntime.InferenceSession("efficientnet-b0.onnx")
File "/usr/local/lib/python3.6/dist-packages/onnxruntime/capi/onnxruntime_inference_collection.py", line 280, in __init__
self._create_inference_session(providers, provider_options)
File "/usr/local/lib/python3.6/dist-packages/onnxruntime/capi/onnxruntime_inference_collection.py", line 307, in _create_inference_session
sess = C.InferenceSession(session_options, self._model_path, True, self._read_config_from_model)
onnxruntime.capi.onnxruntime_pybind11_state.Fail: [ONNXRuntimeError] : 1 : FAIL : Load model from efficientnet-b0.onnx failed:Fatal error: BroadcastTo is not a registered function/op
/오류가 발생했습니다.변환 시 정보와 같이 ONX에서 지원하지 않는 운영자
BroadcastTo 때문일 수 있습니다.맞춤형 조작원을 추가하면 대응이 가능할 수 있지만
tf2onnx 전환이 성공해 조사가 중단됐다.결론
tf2onnx 사용하세요.
Reference
이 문제에 관하여(EfficientNet B0의 Keeras 모델을 ONX 모델로 변환하여 추론), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/kleamp1e/articles/202104-keras-onnx텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)