Deploy de modelos Deep Learning para soluções em tempo real

Hits: 2053

 

 Certamente a maioria dos desenvolvedores de soluções ainda estão na fase de "aprender onde colocar a inteligência artificial". Esta fase é de fato difícil e complicada, porém existem outras situações igualmente difíceis como por exemplo, implantar um modelo treinado de aprendizado profundo (Deep Learning) em produção. Se houver um requisito de baixa latência e alto rendimento, implantar esse sistema pode se tornar um grande problema. Existem várias alternativas. Neste documento trateremos de uma delas por meio do uso do TensorRT, uma biblioteca de baixo nível C++ capaz de absorver modelos já compilados do tensorflow e tratar situações onde é necessário processar muitas imagens em pouco tempo. Vejam o ganho de desempenho no demonstrativo abaixo:

 

 

Veja como a mágica aconteçe. 

Passo 1. Ambiente

Ubuntu 16.04, Python 2.7, CUDA 9.0 (cudnn 7.0), Tensorflow 1.4+ com GPU. Instale o TensorRT 3.0 (Incluindo Python lib)

Vale citar que o tensorRT integra o tensorflow 1.7 https://developers.googleblog.com/2018/03/tensorrt-integration-with-tensorflow.html

 

Passo 2. Exportando o modelo do tensorflow parao formato UFF 

Vamos usar o modelo compilado da VGG-16 do módulo tf.keras.applications module

 

# Importa libs
import uff
import tensorflow as tf
# Cria uma sessão TF e grafo VGG-16
model = tf.keras.applications.VGG16(include_top=True)
# Inicializa as variáveis e carrega os pessos da rede de um modelo treinado
model.load_weights('~/.keras/models/vgg16_weights_tf_dim_ordering_tf_kernels.h5')
model_input = model.input.name.strip(':0')
model_output = model.output.name.strip(':0')

 

print(model_input, model_output)
# expect(u'input_1', u'predictions/Softmax')
# Obtém a definição do grafo
graph = tf.get_default_graph().as_graph_def()
# Algo semelhante a isso:
# node {
# name: "input_1"
# op: "Placeholder"
# attr {
# key: "dtype"
# value {
# type: DT_FLOAT
# }
# }
# attr {
# etc...
# Obtém a sessão
sess = tf.keras.backend.get_session()
# Congela o grafo e remove os nós que são usados somente para treinamento
frozen_graph = tf.graph_util.convert_variables_to_constants(sess, graph, [model_output])
frozen_graph = tf.graph_util.remove_training_nodes(frozen_graph)
# Cria um modelo UFF a partir do grafo 
uff_model = uff.from_tensorflow(frozen_graph, [model_output])
dump = open('VGG16.uff', 'wb')
dump.write(uff_model)
dump.close()

 

Passo 3. Realizando inferência com tensorRT 

import pycuda.driver as cuda
import pycuda.autoinit
import argparse
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input, decode_predictions
import tensorrt as trt
from tensorrt.parsers import uffparser
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Função auxiliar para realizar a inferência
def infer(context, input_img, batch_size):
# carrega a engine
engine = context.get_engine()
assert(engine.get_nb_bindings() == 2)
# Cria um vetor de saída
dims = engine.get_binding_dimensions(1).to_DimsCHW()
elt_count = dims.C() * dims.H() * dims.W() * batch_size
# Converte a entrada para o formato Float32
input_img = input_img.astype(np.float32)
# Alocação de memória
output = cuda.pagelocked_empty(elt_count, dtype=np.float32)
    # Alocação de memória na gpu
d_input = cuda.mem_alloc(batch_size * input_img.size * input_img.dtype.itemsize)
d_output = cuda.mem_alloc(batch_size * output.size * output.dtype.itemsize)
    bindings = [int(d_input), int(d_output)]
    stream = cuda.Stream()
    # transfere os dados para a gpu
cuda.memcpy_htod_async(d_input, input_img, stream)
# executa o modelo
context.enqueue(batch_size, bindings, stream.handle, None)
# devolve o resultado da predição
cuda.memcpy_dtoh_async(output, d_output, stream)
    # 
return output
# carrega o modelo no formato UFF
uff_model = open('VGG16.uff', 'rb').read()
# Cria o parse do modelo
parser = uffparser.create_uff_parser()
parser.register_input("input_1", (3, 224, 224), 0)
parser.register_output("predictions/Softmax")
# Cria a engine e sessão 
trt_logger = trt.infer.ConsoleLogger(trt.infer.LogSeverity.INFO)
engine = trt.utils.uff_to_trt_engine(logger=trt_logger,
stream=uff_model,
parser=parser,
max_batch_size=1, # 1 imagem por vez
max_workspace_size= 1 << 30, # 1 GB GPU memória
datatype=trt.infer.DataType.FLOAT)
context = engine.create_execution_context()

 

Passo 4. Testando...

 

# Carrega e preprocessa a imagem
test_image = image.load_img('imagem.jpg', target_size=(224, 224, 3))
test_image = image.img_to_array(test_image)
processed_im = preprocess_input(np.expand_dims(test_image, 0))[0, :, :, :]
# prepara a imagem para RT engine
processed_im = np.transpose(processed_im, axes=(2, 0, 1))
processed_im = processed_im.copy(order='C')
# realiza a inferência
prediction_proba = infer(context, processed_im, 1)
decode_predictions(np.expand_dims(prediction_proba, 0)) 

 

Links relevantes:

https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/topics/topics/index.html

https://devblogs.nvidia.com/tensorrt-3-faster-tensorflow-inference/

https://medium.com/@fortyq/tensorrt-becomes-a-valuable-tool-for-data-scientist-64cf1b764df2