람쥐썬더

[PYTHON] tensorflow2 keras 모델로 openvino 활용 inference 본문

파이썬

[PYTHON] tensorflow2 keras 모델로 openvino 활용 inference

람쥐썬더123 2022. 7. 4. 15:48

평소처럼 model.predict를 해서 결과값을 뽑아내는데 이걸 뭔가에 적용하기에는 너무 느렸다..

 

영상에서 이미지를 predict 해야하는데 속도가 느리다 보니 프레임이 확 확 떨어져서 predict 속도를 어떻게 끌어올릴까 하다가 Openvino 를 찾았다..

 

인텔에서 제공하는 모듈로 cpu로 연산 어쩌구 하는데 잘 모르겠고~ 그냥 활용하는 법만 올려본다..

 

 

 

1. 본인이 만든 custom model 을 onnx 형식으로 변환해준다

=> keras, torch 등 다양한 모델을 통일 시켜주는게 onnx 라고 한다 (Open Neural Network Exchange)

 

from tensorflow import keras
import tf2onnx
import onnx
import tensorflow as tf

model = keras.models.load_model('custom_model.h5')
model.input.set_shape((1,256,256, 3))
onnx_model, _ = tf2onnx.convert.from_keras(model, opset=16)
onnx.save(onnx_model, '/test_model.onnx')

여기서 주의할점이 model.input.set_shape으로 input_shape을 None에서 1로 바꿔주지 않으면 나중에 아래와 같은 에러가 뜬다

=================================================================

InferenceEngine::Core::LoadNetwork doesn't support inputs having dynamic shapes. Use ov::Core::compile_model API instead. Dynamic inputs are :{ input:'input_1,input_1', shape={?,256,256,3}}

=================================================================

 

찾아 보니 openvino에서는 동적인(dynamic)한 input shape을 지원하지 않아서 생기는 에러라고 한다

( Batch size로 학습하는데 그런게 어딨냐..)

물론 동적으로 바꿀 수 있다는데 난 안돼서 그냥 onnx 형식으로 저장할때 shape을 지정해줬다..

 

 

2. onnx model load 후 Openvino 에 적용될 network를 생성한다

 

import os
import numpy as np
from openvino.inference_engine import IECore

ie = IECore()

net = ie.read_network("/test_model.onnx")

input_name = list(net.input_info.keys())[0]
output_name = list(net.outputs.keys())[0]

net.input_info[input_name].precision = 'FP32'
net.outputs[output_name].precision = 'FP32'

exec_net = ie.load_network(network=net, device_name='CPU')

 

openvino를 설치 한 후에 IECore를 import 해주고 read_network를 통해서 onnx 모델을 읽어온다

input name과 output name을 받아주고
설정된 network에서 동일한 이름을 가진 layer의 형식을 'FP32'로 정의하는 단계다

FP32 , BF16 , I32 등 여러 형식이 있는것 같은데 (FLOAT, INT)  자료구조를 잘 모르니 가장 DEFAULT 한 FP32로 설정해줬다

CPU만 사용 가능하다고 하며 GPU 사용시 다른 형식으로 바꿔줘야 한다고 하긴 함..(난 바꿔도 에러나든디)

 

그리고 최종적으로 device_name을 cpu로 지정해주고 네트워크를 완성해주면 inference를 위한 OV 모델은 완성이 됐따

 

 

 

3. Inference

 

from PIL import Image
import cv2

img = cv2.imread('/image.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (256,256))
pred_img = cv2.resize(img, (256,256))/255.

############# Inf ###############
prob = exec_net.infer({input_name : pred_img})
result = prob['output_layer']

print(result)

Image.fromarray(img)

 

최종적으로 Inference 해주는 코드

이미지 전처리를 해준 뒤 위에 정의된 exec_net.infer를 통해 input_name에 전처리된 이미지 변수를 지정해준다(딕셔너리형)

그럼 딕셔너리 형으로 원래 모델에 기록돼있던 { output_layer : predict value } 형식으로 나오게된다

 

결과적으로 model.predict와 다르지 않았으나 약간의 속도 향상은 있었다.

 

model.predict : 60ms ~ 260ms

OpenVino inference : 20ms ~ 60ms

 

GPU로 해보려고 위에서 형식과 device_name을 gpu로 지정해보긴 했는데 결과값이 너무 높게나온다(decoding이 필요한듯)

 

 

암턴 그래도 된긴했으니까 아 몰랑~(공부 더해야함)