A IA na borda é um dos cenários de borda mais populares. As implementações desse cenário incluem classificação de imagem, deteção de objetos, análise de corpo, rosto e gestos e manipulação de imagem. Este guia de arquitetura descreve como usar o Azure IoT Edge para dar suporte a esses cenários.
Você pode melhorar a precisão da IA atualizando o modelo de IA, mas em alguns cenários o ambiente de rede do dispositivo de borda não é bom. Por exemplo, nas indústrias de energia eólica e petróleo, os equipamentos podem estar localizados no deserto ou no oceano.
Os gêmeos de módulo IoT Edge são usados para implementar o modelo de IA carregado dinamicamente. Os módulos do IoT Edge são baseados no Docker. Uma imagem para um módulo IoT Edge em um ambiente de IA normalmente tem um tamanho de pelo menos 1 GB, portanto, atualizar incrementalmente o modelo de IA é importante em uma rede de largura de banda estreita. Essa consideração é o foco principal deste artigo. A ideia é criar um módulo IoT Edge AI que possa carregar modelos de deteção de objetos LiteRT (anteriormente TensorFlow Lite) ou Open Neural Network Exchange (ONNX). Você também pode habilitar o módulo como uma API da Web para que possa usá-lo para beneficiar outros aplicativos ou módulos.
A solução descrita neste artigo pode ajudá-lo das seguintes maneiras:
- Habilite a inferência de IA em dispositivos de borda.
- Minimize o custo de rede da implantação e atualização de modelos de IA na borda. A solução pode economizar dinheiro para você ou seus clientes, especialmente em um ambiente de rede de largura de banda estreita.
- Crie e gerencie um repositório de modelos de IA no armazenamento local de um dispositivo de borda IoT.
- Alcance quase zero tempo de inatividade quando o dispositivo de borda muda de modelo de IA.
TensorFlow e LiteRT são marcas comerciais da Google Inc.
Arquitetura
Transfira um ficheiro do Visio desta arquitetura.
Fluxo de dados
- O modelo de IA é carregado no Armazenamento de Blobs do Azure ou em um serviço Web. O modelo pode ser um modelo LiteRT ou ONNX pré-treinado ou um modelo criado no Azure Machine Learning. O módulo IoT Edge pode acessar esse modelo e baixá-lo para o dispositivo de borda mais tarde. Se você precisar de melhor segurança, considere o uso de conexões de ponto de extremidade privado entre o Armazenamento de Blob e o dispositivo de borda.
- O Hub IoT do Azure sincroniza gêmeos de módulo de dispositivo automaticamente com informações de modelo de IA. A sincronização ocorre mesmo que o IoT Edge esteja offline. (Em alguns casos, os dispositivos IoT são conectados a redes em horários horários, diários ou semanais programados para economizar energia ou reduzir o tráfego de rede.)
- O módulo carregador monitora as atualizações dos gêmeos de módulo via API. Quando deteta uma atualização, obtém o token SAS do modelo de aprendizagem automática e, em seguida, transfere o modelo de IA.
- Para obter mais informações, consulte Criar token SAS para um contêiner ou blob.
- Você pode usar a propriedade ExpiresOn para definir a data de expiração dos recursos. Se o seu dispositivo ficar offline por muito tempo, você pode estender o tempo de expiração.
- O módulo carregador salva o modelo de IA no armazenamento local compartilhado do módulo IoT Edge. Você precisa configurar o armazenamento local compartilhado no arquivo JSON de implantação do IoT Edge.
- O módulo carregador carrega o modelo de IA do armazenamento local através da API LiteRT ou ONNX.
- O módulo carregador inicia uma API da Web que recebe a foto binária via solicitação POST e retorna os resultados em um arquivo JSON.
Para atualizar o modelo de IA, você pode carregar a nova versão para o Blob Storage e sincronizar os gêmeos do módulo do dispositivo novamente para uma atualização incremental. Não há necessidade de atualizar toda a imagem do módulo IoT Edge.
Detalhes do cenário
Nesta solução, um módulo IoT Edge é usado para baixar um modelo de IA e, em seguida, habilitar a inferência de aprendizado de máquina. Você pode usar modelos LiteRT ou ONNX pré-treinados nesta solução.
LiteRT
Um
.tflite
arquivo é um modelo de IA pré-treinado. Você pode baixar um de TensorFlow.org. É um modelo genérico de IA que você pode usar em aplicativos multiplataforma, como iOS e Android. O LiteRT suporta modelos de TensorFlow, PyTorch, JAX e Keras. Para obter mais informações sobre metadados e campos associados (por exemplo,labels.txt
) consulte Ler os metadados de modelos.Um modelo de deteção de objetos é treinado para detetar a presença e a localização de várias classes de objetos. Por exemplo, um modelo pode ser treinado com imagens que contêm vários pedaços de fruta, juntamente com um rótulo que especifica a classe de fruta que eles representam (por exemplo, maçã) e dados que especificam onde cada objeto aparece na imagem.
Quando uma imagem é fornecida ao modelo, ela gera uma lista dos objetos que deteta, o local de uma caixa delimitadora para cada objeto e uma pontuação que indica a confiança da deteção.
Se você quiser criar ou ajustar um modelo de IA, consulte LiteRT Model Maker.
Você pode obter mais modelos de deteção pré-treinados gratuitos, com várias características de latência e precisão, no Detection Zoo. Cada modelo usa as assinaturas de entrada e saída mostradas nos exemplos de código a seguir.
ONNX
ONNX é um formato de padrão aberto para representar modelos de aprendizado de máquina. É apoiado por uma comunidade de parceiros que o implementaram em muitas estruturas e ferramentas.
- O ONNX suporta ferramentas para criar e implantar modelos e para realizar outras tarefas. Para obter mais informações, consulte Ferramentas ONNX suportadas.
- Você pode usar o ONNX Runtime para executar modelos pré-treinados ONNX. Para obter informações sobre modelos pré-treinados, consulte ONNX Model Zoo.
- Para esse cenário, você pode usar um modelo de deteção de objeto e segmentação de imagem: Tiny YOLOv3.
A comunidade ONNX fornece ferramentas para ajudá-lo a criar e implantar seu modelo de aprendizado profundo.
Baixar modelos de IA treinados
Para baixar modelos de IA treinados, recomendamos que você use gêmeos de dispositivo para receber notificações quando um novo modelo estiver pronto. Mesmo que o dispositivo esteja offline, a mensagem pode ser armazenada em cache no Hub IoT até que o dispositivo de borda volte a ficar online. A mensagem será sincronizada automaticamente.
A seguir está um exemplo de código Python que registra notificações para os gêmeos do dispositivo e, em seguida, baixa o modelo de IA em um arquivo ZIP. Ele também executa outras operações no arquivo baixado.
O código executa estas tarefas:
- Receba a notificação de gêmeos do dispositivo. A notificação inclui o nome do arquivo, o endereço de download do arquivo e o token de autenticação MD5. (No nome do arquivo, você pode incluir informações de versão, como 1.0.)
- Baixe o modelo de IA como um arquivo ZIP para o armazenamento local.
- Opcionalmente, execute a soma de verificação MD5. A verificação MD5 ajuda a evitar arquivos ZIP que foram adulterados durante a transmissão de rede.
- Descompacte o arquivo ZIP e salve-o localmente.
- Envie uma notificação para o Hub IoT ou uma mensagem de roteamento para informar que o novo modelo de IA está pronto.
# define behavior for receiving a twin patch
async def twin_patch_handler(patch):
try:
print( "######## The data in the desired properties patch was: %s" % patch)
if "FileName" in patch:
FileName = patch["FileName"]
if "DownloadUrl" in patch:
DownloadUrl = patch["DownloadUrl"]
if "ContentMD5" in patch:
ContentMD5 = patch["ContentMD5"]
FilePath = "/iotedge/storage/" + FileName
# download AI model
r = requests.get(DownloadUrl)
print ("######## download AI Model Succeeded.")
ffw = open(FilePath, 'wb')
ffw.write(r.content)
ffw.close()
print ("######## AI Model File: " + FilePath)
# MD5 checksum
md5str = content_encoding(FilePath)
if md5str == ContentMD5:
print ( "######## New AI Model MD5 checksum succeeded")
# decompressing the ZIP file
unZipSrc = FilePath
targeDir = "/iotedge/storage/"
filenamenoext = get_filename_and_ext(unZipSrc)[0]
targeDir = targeDir + filenamenoext
unzip_file(unZipSrc,targeDir)
# ONNX
local_model_path = targeDir + "/tiny-yolov3-11.onnx"
local_labelmap_path = targeDir + "/coco_classes.txt"
# LiteRT
# local_model_path = targeDir + "/ssd_mobilenet_v1_1_metadata_1.tflite"
# local_labelmap_path = targeDir + "/labelmap.txt"
# message to module
if client is not None:
print ( "######## Send AI Model Info AS Routing Message")
data = "{\"local_model_path\": \"%s\",\"local_labelmap_path\": \"%s\"}" % (filenamenoext+"/tiny-yolov3-11.onnx", filenamenoext+"/coco_classes.txt")
await client.send_message_to_output(data, "DLModelOutput")
# update the reported properties
reported_properties = {"LatestAIModelFileName": FileName }
print("######## Setting reported LatestAIModelName to {}".format(reported_properties["LatestAIModelFileName"]))
await client.patch_twin_reported_properties(reported_properties)
else:
print ( "######## New AI Model MD5 checksum failed")
except Exception as ex:
print ( "Unexpected error in twin_patch_handler: %s" % ex )
Inferência
Depois que o modelo de IA é baixado, o próximo passo é usar o modelo no dispositivo de borda. Você pode carregar dinamicamente o modelo e executar a deteção de objetos em dispositivos de borda. O exemplo de código a seguir mostra como usar o modelo LiteRT AI para detetar objetos em dispositivos de borda.
O código executa estas tarefas:
- Carregue dinamicamente o modelo LiteRT AI.
- Execute a padronização de imagens.
- Detetar objetos.
- Calcular pontuações de deteção.
class InferenceProcedure():
def detect_object(self, imgBytes):
results = []
try:
model_full_path = AI_Model_Path.Get_Model_Path()
if(model_full_path == ""):
raise Exception ("PLEASE SET AI MODEL FIRST")
if '.tflite' in model_full_path:
interpreter = tf.lite.Interpreter(model_path=model_full_path)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
input_shape = input_details[0]['shape']
# bytes to numpy.ndarray
im_arr = np.frombuffer(imgBytes, dtype=np.uint8)
img = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)
im_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
im_rgb = cv2.resize(im_rgb, (input_shape[1], input_shape[2]))
input_data = np.expand_dims(im_rgb, axis=0)
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
detection_boxes = interpreter.get_tensor(output_details[0]['index'])
detection_classes = interpreter.get_tensor(output_details[1]['index'])
detection_scores = interpreter.get_tensor(output_details[2]['index'])
num_boxes = interpreter.get_tensor(output_details[3]['index'])
label_names = [line.rstrip('\n') for line in open(AI_Model_Path.Get_Labelmap_Path())]
label_names = np.array(label_names)
new_label_names = list(filter(lambda x : x != '???', label_names))
for i in range(int(num_boxes[0])):
if detection_scores[0, i] > .5:
class_id = int(detection_classes[0, i])
class_name = new_label_names[class_id]
# top, left, bottom, right
results_json = "{'Class': '%s','Score': '%s','Location': '%s'}" % (class_name, detection_scores[0, i],detection_boxes[0, i])
results.append(results_json)
print(results_json)
except Exception as e:
print ( "detect_object unexpected error %s " % e )
raise
# return results
return json.dumps(results)
A seguir está a versão ONNX do código anterior. Os passos são basicamente os mesmos. A única diferença é como a pontuação de deteção é tratada, porque os parâmetros de saída e modelo Labelmap
são diferentes.
class InferenceProcedure():
def letterbox_image(self, image, size):
'''resize image with unchanged aspect ratio using padding'''
iw, ih = image.size
w, h = size
scale = min(w/iw, h/ih)
nw = int(iw*scale)
nh = int(ih*scale)
image = image.resize((nw,nh), Image.BICUBIC)
new_image = Image.new('RGB', size, (128,128,128))
new_image.paste(image, ((w-nw)//2, (h-nh)//2))
return new_image
def preprocess(self, img):
model_image_size = (416, 416)
boxed_image = self.letterbox_image(img, tuple(reversed(model_image_size)))
image_data = np.array(boxed_image, dtype='float32')
image_data /= 255.
image_data = np.transpose(image_data, [2, 0, 1])
image_data = np.expand_dims(image_data, 0)
return image_data
def detect_object(self, imgBytes):
results = []
try:
model_full_path = AI_Model_Path.Get_Model_Path()
if(model_full_path == ""):
raise Exception ("PLEASE SET AI MODEL FIRST")
if '.onnx' in model_full_path:
# input
image_data = self.preprocess(imgBytes)
image_size = np.array([imgBytes.size[1], imgBytes.size[0]], dtype=np.float32).reshape(1, 2)
labels_file = open(AI_Model_Path.Get_Labelmap_Path())
labels = labels_file.read().split("\n")
# Loading ONNX model
print("loading Tiny YOLO...")
start_time = time.time()
sess = rt.InferenceSession(model_full_path)
print("loaded after", time.time() - start_time, "s")
input_name00 = sess.get_inputs()[0].name
input_name01 = sess.get_inputs()[1].name
pred = sess.run(None, {input_name00: image_data,input_name01:image_size})
boxes = pred[0]
scores = pred[1]
indices = pred[2]
results = []
out_boxes, out_scores, out_classes = [], [], []
for idx_ in indices[0]:
out_classes.append(idx_[1])
out_scores.append(scores[tuple(idx_)])
idx_1 = (idx_[0], idx_[2])
out_boxes.append(boxes[idx_1])
results_json = "{'Class': '%s','Score': '%s','Location': '%s'}" % (labels[idx_[1]], scores[tuple(idx_)],boxes[idx_1])
results.append(results_json)
print(results_json)
except Exception as e:
print ( "detect_object unexpected error %s " % e )
raise
# return results
return json.dumps(results)
Se seu dispositivo de borda IoT incorporar o código e os recursos anteriores, seu dispositivo de borda terá deteção de objeto de imagem AI e suporta atualização dinâmica de modelos de IA. Se você quiser que o módulo de borda forneça funcionalidade de IA para outros aplicativos ou módulos por meio de uma API da Web, você pode criar uma API da Web em seu módulo.
Flask framework é um exemplo de uma ferramenta que você pode usar para criar rapidamente uma API. Você pode receber imagens como dados binários, usar um modelo de IA para deteção e, em seguida, retornar os resultados em um formato JSON. Para obter mais informações, consulte Flask: Flask Tutorial no Visual Studio Code.
Contribuidores
Este artigo é mantido pela Microsoft. Foi originalmente escrito pelos seguintes contribuidores.
Autor principal:
- Bo Wang - Brasil | Engenheiro de Software Sênior
Outros contribuidores:
- Freddy Ayala - Brasil | Arquiteto de Soluções Cloud
Para ver perfis não públicos do LinkedIn, inicie sessão no LinkedIn.
Próximos passos
- Compreender e usar gêmeos de módulo no Hub IoT
- Saiba como implementar módulos e estabelecer rotas no IoT Edge
- Dê aos módulos acesso ao armazenamento local de um dispositivo
- Compreender as implantações automáticas do IoT Edge para dispositivos individuais ou em escala
- Troca de Rede Neural Aberta
- Tutoriais ONNX
- Implante um modelo de aprendizado de máquina em dispositivos IoT e de borda