A combinação entre aprendizado de máquina e microcontroladores abre um mundo de possibilidades para a criação de sistemas inteligentes e autônomos. O TensorFlow Lite, uma versão leve do TensorFlow, permite que os desenvolvedores implantem modelos de aprendizado de máquina em dispositivos com recursos limitados, como o ESP32.
Além disso, as redes neurais ganharam imensa popularidade no campo da inteligência artificial e do aprendizado de máquina devido à sua capacidade de aprender padrões complexos e fazer previsões precisas. Neste artigo, vamos explorar o processo de uso do TensorFlow Lite em uma placa ESP32 e demonstrar como integrá-lo aos seus projetos. Para isso, também abordaremos alguns conceitos fundamentais da AIoT através da implementação de um modelo de rede neural simples, capaz de prever o seno de um número que varia de 0 a π.
Para a execução desse projeto, precisaremos dos seguintes materiais:
A Inteligência Artificial das Coisas, ou AIoT, é uma poderosa combinação dos recursos da Inteligência Artificial (IA) com a interconectividade dos dispositivos de Internet das Coisas (IoT). Os dispositivos IoT são dispositivos inteligentes interconectados e incorporados com sensores, atuadores e conectividade de rede que permitem coletar e transmitir dados. Assim, a AIoT aproveita esses dados para tomar decisões inteligentes e automatizar processos. Ao combinar o poder da IA e da IoT, os sistemas AIoT podem aumentar a eficiência, otimizar a utilização de recursos e permitir diversas análises preditivas.
Dessa forma, a AIoT representa uma mudança de paradigma em como as máquinas interagem e tomam decisões. Isso, pois, ao integrar algoritmos e técnicas de IA em dispositivos e redes de IoT, permite que esses dispositivos não apenas coletem e transmitam dados, mas também analisem, aprendam e tomem decisões autônomas com base nas inferências realizadas em tempo real. Assim, traz um novo nível de inteligência cognitiva para a vasta rede de dispositivos conectados, capacitando-os a operar de forma mais eficiente, precisa e adaptável.
Como exemplo de maior eficiência, podemos citar a forma com que os sistemas tradicionais de IA baseados em nuvem enfrentam desafios em termos de latência, restrições de largura de banda e questões de privacidade. Dessa forma, a chamada computação de borda aproxima os recursos de IA dos próprios dispositivos, permitindo processamento e análise de dados em tempo real, em proximidade ao local de geração. Essa arquitetura distribuída minimiza a necessidade de comunicação constante com a nuvem, melhora a capacidade de resposta e reduz o congestionamento da rede.
As redes neurais são uma classe de algoritmos inspirados na estrutura neural do cérebro humano, sendo, portanto um importante componente dos sistemas AIoT. São compostas por nós interconectados, chamados neurônios, que trabalham juntos para processar e transformar dados. Além disso, uma rede neural é constituída por camadas: uma camada de entrada, uma ou mais camadas ocultas e uma camada de saída. Cada neurônio recebe uma entrada, realiza cálculos e produz uma saída.
Dessa forma, um neurônio em uma rede neural imita o comportamento de um neurônio biológico. Ao receber sinais de entrada, aplica pesos (como se fossem notas) a eles, os soma e então aplica uma função de ativação, que irá finalmente produzir uma saída. Assim, a função de ativação introduz a não-linearidade na rede, permitindo modelar relacionamentos complexos entre dados.
Esse processo de alimentação de entradas e saídas através da rede é conhecido como propagação feedforward, ou retropropagação. Treinar uma rede neural também envolve expô-la a um grande conjunto de dados com entradas e saídas conhecidas e, nesse processo, a rede ajusta seus pesos e vieses com base no feedback de erro obtido por meio da retropropagação.
Assim, a retropropagação é um processo crucial que permite que as redes neurais aprendam com seus erros e melhorem seu desempenho, pois envolve comparar a saída prevista da rede com a saída real, calcular o erro e ajustar os pesos e desvios de acordo. Esse processo iterativo é guiado por algoritmos de otimização. Finalmente, depois de treinada, a rede pode ser testada em dados não vistos antes, para que seja possível avaliar seu desempenho.
Existem diferentes algoritmos de redes neurais que podem ser aplicados para diversos tipos de dados. No entanto, nem sempre é necessário escrever um algoritmo do zero, pois existem frameworks poderosos disponíveis para uso, tornando esse processo muito mais simples. Assim, ao invés de precisar desenvolver uma rede neural sozinho, é possível usar modelos prontos e otimizar suas arquiteturas.
Um desses frameworks é o TensorFlow, uma biblioteca de código aberto desenvolvida pelo Google e projetada para permitir computações numéricas e machine learning em grande escala. Com uma ampla gama de modelos e algoritmos de machine learning e deep learning, o TensorFlow simplifica o uso dessas técnicas, abstraindo grande parte da complexidade.
Uma das principais características do TensorFlow é a capacidade de criar grafos de fluxo de dados. Essas estruturas descrevem como os dados se movem através de uma série de nós de processamento. Em um grafo TensorFlow, cada nó representa uma operação matemática, enquanto as conexões ou arestas entre os nós representam arrays de dados multidimensionais.
Arquitetura simplificada do TensorFlow.
Na imagem acima, cada nódulo representa uma computação realizada, que fluem de um nódulo para outro de forma a transformar os dados para gerar os resultados. Enquanto, no TensorFlow, essas computações são chamados de operators, as arestas que ligam uma operação a outra recebem o nome de tensor, unidade fundamental desse framework e que representa arrays multi-dimensionais de dados.
O TensorFlow Lite, por sua vez, é responsável por converter um modelo pré-treinado no TensorFlow para um formato otimizado para menos armazenamento e processamento, pois é projetado para dispositivos com recursos limitados, como microcontroladores, telefones celulares e dispositivos IoT, em geral. Assim, fornece um tempo de execução simplificado que permite o uso eficiente de modelos de IA em dispositivos com memória mínima e requisitos computacionais baixos. Para isso, o TensorFlow Lite emprega várias técnicas de otimização, como a quantização, para otimizar seu desempenho nesses dispositivos.
Diagrama das etapas do modelo e seus respectivos frameworks.
Na imagem acima podemos visualizar um esquema que demonstra qual framework será responsável por cada etapa do projeto. Note que as inferências são realizadas pelo modelo do TensorFlow Lite no ESP 32.
Agora chegou a hora de aplicarmos os conhecimentos adquiridos para desenvolver um algoritmo usando o TensorFlow e realizarmos inferências pelo ESP32. Para demonstrar a aplicação prática de AIoT e redes neurais, criaremos uma rede neural simples que prevê o seno de um número que varia de 0 a π. A escolha dessa aplicação decorre da simplicidade de gerar dados para o treino da rede e dos diversos conceitos abordados na criação do algoritmo que facilitarão o entendimento sobre o funcionamento desse tipo de IA.
Como usaremos o Tensor Flow (e, portanto, o Python), talvez seja necessário possuir ambos instalados em sua máquina. No entanto, os códigos podem ser rodados em serviços de nuvem, como o Google Colab, sem a necessidade de instalar esses softwares na sua máquina. Por isso, esse artigo não abordará a instalação dos pacotes, mas o notebook Python com os códigos compilados estará disponível logo abaixo.
O primeiro passo é importar as bibliotecas:
import math import numpy as np # as bibliotecas math e numpy serão usadas para gerar os dados de treino e teste, isto é, usadas para gerar os valores de seno import tensorflow as tf from tensorflow.keras import layers from everywhereml.code_generators.tensorflow import tf_porter
Agora, precisamos gerar um conjunto de dados, que serão usados como pares de entrada e saída na nossa rede neural, onde a entrada é um número que varia de 0 a π e a saída é o valor do seno correspondente. Você pode usar um script para criar esse conjunto de dados, ou criar manualmente um arquivo CSV com os pares de entrada-saída.
# a variável SAMPLES recebe a quantidade de dados que vamos gerar para x e y, ou seja, um valor entre 0 e pi e o respectivo seno desse valor SAMPLES = 1000 # aqui, usaremos uma função do numpy para gerar uma quantidade números aleatórios entre um intervalo, definido entre 0 e 2*pi x_values = np.random.uniform(low=0, high=2*math.pi, size=SAMPLES) # e então, geramos os dados de seno correspondentes, através da função sin do numpy y_values = np.sin(x_values)
Agora que já possuímos os dados necessários, chegou a hora de criarmos nosso modelo. Usando o TensorFlow, criaremos uma rede neural com duas camadas e 16 neurônios. Para facilitar, gerarei os dados de treino e teste na mesma função que treinarei o modelo.
def get_model(): # a variável SAMPLES recebe a quantidade de dados que vamos gerar para x e y, ou seja, um valor entre 0 e pi e o respectivo seno desse valor SAMPLES = 1000 # a função seed, do numpy, define uma "semente" para gerar números aleatórios, garantindo que a sequência permaneça a mesma em várias execuções, permitindo reprodutibilidade np.random.seed(1337) # aqui, usaremos uma função do numpy para gerar uma quantidade números aleatórios entre um intervalo, definido entre 0 e 2*pi x_values = np.random.uniform(low=0, high=2*math.pi, size=SAMPLES) # agora, usaremos outra função do numpy para embaralhar os dados gerados np.random.shuffle(x_values) # e então, geramos os dados de seno correspondentes, através da função sin do numpy y_values = np.sin(x_values) # o próximo passo é adicionar algum tipo de ruído aos dados. A função randn do numpy gera dados aleatórios pertencentes à distribuição normal, a partir de um formato especificado y_values += 0.1 * np.random.randn(*y_values.shape) # agora, com os dados em mãos, podemos separá-los entre treino e teste. TRAIN_SPLIT = int(0.6 * SAMPLES) TEST_SPLIT = int(0.2 * SAMPLES + TRAIN_SPLIT) x_train, x_test, x_validate = np.split(x_values, [TRAIN_SPLIT, TEST_SPLIT]) y_train, y_test, y_validate = np.split(y_values, [TRAIN_SPLIT, TEST_SPLIT]) # aqui, criaremos uma rede neural com 2 camadas de 16 neurônios model = tf.keras.Sequential() model.add(layers.Dense(16, activation='relu', input_shape=(1,))) model.add(layers.Dense(16, activation='relu')) model.add(layers.Dense(1)) # e então definimos as métricas e o otimizador, que é algoritmo usado para minimizar uma função de perda em relação aos parâmetros treináveis do modelo model.compile(optimizer='rmsprop', loss='mse', metrics=['mae']) # finalmente, treinamos o modelo model.fit(x_train, y_train, epochs=200, batch_size=16, validation_data=(x_validate, y_validate)) # precisamos que, além do próprio modelo, a função retorne os dados de treino para que possam ser usados pela biblioteca everywhereml return model, x_train, y_train
Finalmente, com a arquitetura pronta e os dados em mãos, podemos treinar o nosso algoritmo.
# chamamos a função para treinar o modelo tf_model, x_train, y_train = get_model()
# e então usamos a função do TensorFlow para converter o modelo para o TensorFlow Lite converter = tf.lite.TFLiteConverter.from_keras_model(tf_model) tflite_model = converter.convert() with open('model.tflite', 'wb') as f: f.write(tflite_model)
Com o modelo em mãos, o próximo passo é carregá-lo para o nosso microcontrolador. Como citado, o treinamento do modelo foi realizado usando o Python, linguagem utilizada pelo próprio Tensor Flow. No entanto, dispositivos como os ESP compilam códigos em C/C++. Portanto, para que seja possível carregar o nosso modelo para a placa, iremos converte-lo para C++. Para isso, utilizaremos uma biblioteca chamada everywhereml.
# agora usamos a biblioteca everywhereml para converter o modelo do TF Lite em um código c++ porter = tf_porter(tflite_model, x_train, y_train) cpp_code = porter.to_cpp(instance_name='modelo_seno', arena_size=4096) print(cpp_code) # salve o código gerado em um arquivo c++
Os códigos em Python usados até agora também estão disponíveis para visualização no seguinte notebook Colab. Abaixo, o código resultante.
#ifndef UUID140516234207264 #define UUID140516234207264 #include <EloquentTinyML.h> #include <eloquent_tinyml/tensorflow.h> #ifdef __has_attribute #define HAVE_ATTRIBUTE(x) __has_attribute(x) #else #define HAVE_ATTRIBUTE(x) 0 #endif #if HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__)) #define DATA_ALIGN_ATTRIBUTE __attribute__((aligned(4))) #else #define DATA_ALIGN_ATTRIBUTE #endif #ifndef ARENA_SIZE #define ARENA_SIZE 4096 #endif /** model size = 3164 bytes **/ const unsigned char modelData[] DATA_ALIGN_ATTRIBUTE = { 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x10, 0x07, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x98, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xca, 0xf9, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x14, 0x06, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xbc, 0x05, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x32, 0x2e, 0x30, 0x00, 0x00, 0xd6, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf5, 0xff, 0xff, 0xc4, 0xf5, 0xff, 0xff, 0xc8, 0xf5, 0xff, 0xff, 0xfe, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x74, 0x2d, 0x17, 0x3e, 0x9d, 0xc8, 0xbc, 0x3f, 0x70, 0xf7, 0x0a, 0x3e, 0xc4, 0x1c, 0x07, 0x3e, 0x29, 0x93, 0x63, 0x3f, 0x3c, 0x8e, 0x74, 0x3e, 0x0c, 0x53, 0x02, 0xbe, 0x1d, 0xb5, 0xbf, 0x3e, 0x63, 0x7f, 0xae, 0xbf, 0x50, 0x2a, 0x69, 0x3e, 0x7c, 0x69, 0xba, 0x3e, 0x6b, 0xff, 0xde, 0xbe, 0xbd, 0xa9, 0xb3, 0x3d, 0xf6, 0x5b, 0xb0, 0x3e, 0xf5, 0x29, 0xf7, 0xbe, 0xe0, 0xb9, 0xb6, 0x3f, 0x4a, 0xfb, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x27, 0x7d, 0x50, 0xbc, 0x58, 0xb3, 0x5b, 0xbe, 0x50, 0x7e, 0xad, 0x3c, 0x08, 0xfe, 0x08, 0xbd, 0x89, 0x37, 0x11, 0xbe, 0x73, 0x55, 0xd7, 0x3e, 0x02, 0xcf, 0xdc, 0xbe, 0x63, 0xa9, 0x96, 0x3e, 0xed, 0x6a, 0xd9, 0x3d, 0xb4, 0xe2, 0xa5, 0xbe, 0x4d, 0x11, 0xcf, 0xbe, 0xfb, 0x76, 0xba, 0x3e, 0x5c, 0xe4, 0x13, 0xbe, 0xa2, 0x48, 0x55, 0x3e, 0x75, 0x32, 0x9d, 0x3e, 0x38, 0x30, 0x1d, 0xbe, 0x13, 0x71, 0x57, 0x3e, 0x52, 0xe8, 0xdb, 0xbe, 0x8c, 0xa9, 0x61, 0xbf, 0x41, 0x78, 0x2c, 0xbe, 0x53, 0xbe, 0x00, 0xbe, 0x17, 0xaa, 0x9b, 0xbe, 0xaf, 0xc2, 0x80, 0x3e, 0x53, 0xe1, 0x9b, 0x3e, 0xca, 0x7c, 0xd1, 0xbc, 0x7c, 0x62, 0xcc, 0x3d, 0x7e, 0x18, 0xe2, 0x3d, 0xd8, 0xa9, 0xb9, 0xbe, 0x38, 0xed, 0x3b, 0x3d, 0x9c, 0x65, 0xc5, 0x3d, 0x48, 0xad, 0x42, 0xbf, 0xb9, 0x06, 0xf3, 0x3e, 0xf0, 0x1f, 0x86, 0x3c, 0xa0, 0x60, 0x9b, 0xbe, 0xe0, 0x78, 0x94, 0xbd, 0xdd, 0x9b, 0x80, 0xbe, 0xfb, 0x02, 0x9c, 0x3e, 0xb2, 0x1d, 0xd8, 0xbe, 0x5b, 0x62, 0xb7, 0x3e, 0x56, 0x38, 0x06, 0x3e, 0xfb, 0x44, 0x86, 0xbe, 0x70, 0x5d, 0xee, 0xbc, 0xc0, 0x02, 0x0f, 0x3c, 0x30, 0xd0, 0x04, 0xbe, 0xf7, 0x4f, 0x80, 0xbe, 0xf4, 0xf4, 0xda, 0xbd, 0x42, 0x83, 0x06, 0x3e, 0x54, 0xe7, 0xad, 0xbd, 0x5b, 0xdb, 0xbc, 0x3e, 0x30, 0xbc, 0x2a, 0xbd, 0xde, 0xf0, 0xa9, 0xbe, 0x2e, 0xc5, 0x03, 0x3e, 0xe1, 0xcd, 0xd6, 0xbe, 0x2d, 0xee, 0xc3, 0xbe, 0x67, 0x7a, 0xc9, 0x3e, 0x20, 0xa2, 0x6b, 0x3c, 0x78, 0x89, 0x69, 0xbe, 0xa5, 0xf7, 0x7c, 0xbe, 0x7f, 0x9a, 0xb1, 0x3e, 0x22, 0x0c, 0x5a, 0x3e, 0x6c, 0x49, 0xc9, 0x3d, 0x96, 0x38, 0x7c, 0x3e, 0x3b, 0xd1, 0x8c, 0x3e, 0x2f, 0x4f, 0xad, 0xbe, 0xa6, 0xf6, 0xba, 0x3e, 0xbb, 0x60, 0xc9, 0x3e, 0x68, 0x68, 0x1b, 0xbf, 0xd8, 0xfc, 0x3d, 0xbf, 0x5f, 0x02, 0x9c, 0xbe, 0xc8, 0xd4, 0xe7, 0xbd, 0x00, 0x51, 0xf4, 0x3c, 0x30, 0x77, 0x26, 0xbe, 0x47, 0x99, 0x0b, 0x3f, 0x5d, 0x4f, 0x97, 0x3e, 0x53, 0xa2, 0xb6, 0xbe, 0x16, 0x67, 0x6a, 0x3e, 0x52, 0x4c, 0x37, 0x3e, 0x53, 0x38, 0xd8, 0xbe, 0xb7, 0x4f, 0x8a, 0xbe, 0x56, 0x3c, 0x92, 0x3d, 0xea, 0xca, 0x03, 0xbe, 0xa0, 0x8d, 0xdc, 0x3c, 0x14, 0xa3, 0x99, 0x3d, 0xa7, 0xb6, 0xdc, 0x3e, 0xa7, 0xd3, 0xa4, 0x3e, 0x60, 0x32, 0x81, 0x3d, 0xf5, 0x03, 0xa7, 0x3e, 0x7e, 0x40, 0x34, 0x3e, 0xf0, 0xac, 0xb0, 0xbd, 0x9e, 0xad, 0x71, 0x3e, 0xb3, 0x00, 0xb2, 0xbe, 0x20, 0xce, 0x22, 0xbd, 0x32, 0xca, 0x7b, 0x3e, 0xe9, 0x4d, 0x90, 0x3e, 0x64, 0xf8, 0xa4, 0xbe, 0x98, 0x1d, 0xaf, 0xbd, 0x9f, 0xde, 0xca, 0xbe, 0xb6, 0x55, 0x57, 0xbe, 0x96, 0xb3, 0x44, 0xbe, 0x70, 0x32, 0xbb, 0xbd, 0x34, 0x4e, 0xb6, 0x3d, 0xef, 0xc5, 0x4e, 0xbe, 0xf4, 0x9f, 0xc4, 0xbe, 0x1c, 0x14, 0xa3, 0xbe, 0x1c, 0x5f, 0xea, 0xbd, 0xac, 0x3d, 0x91, 0x3d, 0x6c, 0xb2, 0xb1, 0xbd, 0xe0, 0x8d, 0xb2, 0xbc, 0x00, 0x70, 0xcc, 0xba, 0xa1, 0xcd, 0x64, 0xbe, 0x5d, 0x92, 0x6a, 0xbe, 0xb0, 0x42, 0xf3, 0xbd, 0x3d, 0xe6, 0x87, 0xbe, 0x56, 0x31, 0x1c, 0x3e, 0x44, 0x26, 0xa1, 0x3e, 0x31, 0xbf, 0xf1, 0x3d, 0x51, 0x47, 0x9a, 0xbe, 0x32, 0x60, 0x2c, 0x3e, 0xde, 0xf3, 0x44, 0x3e, 0x2d, 0x3a, 0x82, 0xbe, 0x29, 0x9d, 0xf4, 0x3e, 0x4a, 0x8f, 0x28, 0x3e, 0x27, 0x93, 0xc8, 0xbe, 0xec, 0x7e, 0xe7, 0xbd, 0xa4, 0x5d, 0xe7, 0x3d, 0x1c, 0x7d, 0xfc, 0x3d, 0x2d, 0x25, 0x87, 0xbe, 0x95, 0x63, 0xa2, 0xbe, 0xd1, 0x2b, 0x9b, 0xbe, 0x26, 0x29, 0x1b, 0xbe, 0xf0, 0x55, 0x83, 0xbd, 0x22, 0x7f, 0x5f, 0x3d, 0x09, 0xb0, 0x18, 0x3e, 0x19, 0x4a, 0x9b, 0xbe, 0x89, 0xc8, 0x93, 0xbe, 0x49, 0x22, 0x89, 0x3e, 0x8f, 0x89, 0x01, 0xbd, 0x19, 0xc8, 0xa7, 0xbe, 0x2e, 0x59, 0x7e, 0x3e, 0x22, 0xfe, 0xd1, 0xbe, 0xc2, 0x88, 0x2c, 0xbe, 0x0d, 0x6f, 0xb8, 0x3e, 0x82, 0x12, 0x4a, 0xbf, 0xd3, 0x41, 0x43, 0xbe, 0xaa, 0x95, 0x3a, 0x3e, 0xc2, 0xeb, 0x08, 0x3e, 0x8a, 0x22, 0x39, 0x3e, 0x10, 0x9b, 0xfb, 0x3c, 0xbb, 0x5c, 0xa0, 0x3e, 0xbc, 0x41, 0xcb, 0xbd, 0xf0, 0xa9, 0x83, 0x3c, 0x34, 0x10, 0x3b, 0xbe, 0x91, 0x8b, 0x7e, 0xbe, 0xa3, 0xfb, 0xd5, 0xbe, 0x76, 0xaf, 0x59, 0xbe, 0x00, 0xba, 0x93, 0x3c, 0xde, 0x19, 0x88, 0xbe, 0x09, 0x6a, 0x40, 0xbe, 0xa6, 0x5b, 0x9b, 0xbe, 0x9a, 0x94, 0x5e, 0xbe, 0x73, 0x3f, 0xa1, 0x3e, 0x9a, 0xac, 0x14, 0xbe, 0x03, 0x0a, 0x61, 0xbe, 0xfe, 0x7c, 0x04, 0x3e, 0x38, 0xa6, 0xc9, 0xbe, 0x64, 0x2c, 0xab, 0xbd, 0x8c, 0x47, 0xc6, 0xbe, 0x56, 0xb8, 0xa7, 0xbe, 0xaf, 0x36, 0x48, 0xbe, 0x1d, 0x71, 0xb6, 0x3e, 0xae, 0x1d, 0x48, 0x3e, 0x4c, 0x7a, 0x80, 0x3d, 0x44, 0x40, 0x8a, 0xbe, 0x6e, 0xb7, 0x13, 0x3e, 0x96, 0x4a, 0x46, 0x3e, 0xf2, 0x44, 0xc5, 0xbe, 0xc0, 0x16, 0x8c, 0x3c, 0x6b, 0x85, 0x8d, 0x3e, 0x5f, 0xc7, 0xc9, 0xbe, 0xdd, 0xfd, 0xd1, 0xbe, 0xa8, 0x79, 0x8b, 0xbe, 0x91, 0xfb, 0x91, 0xbe, 0x0f, 0x1d, 0xd3, 0x3e, 0x00, 0x74, 0x36, 0x3d, 0x57, 0x84, 0x4d, 0xbe, 0xdb, 0xef, 0x68, 0xbe, 0x0a, 0x70, 0x2d, 0xbe, 0x47, 0xf0, 0x90, 0x3e, 0x68, 0x2f, 0xb6, 0xbe, 0x88, 0xa8, 0xb2, 0xbd, 0xfa, 0xae, 0x3c, 0x3e, 0x54, 0xb9, 0x90, 0xbd, 0x7a, 0xa7, 0x9b, 0x3e, 0xb0, 0x99, 0x3c, 0x3d, 0xb1, 0xa1, 0x96, 0x3e, 0x81, 0x94, 0x2b, 0xbe, 0xfa, 0xa5, 0x61, 0xbe, 0xc0, 0x32, 0x76, 0xbc, 0xfc, 0xcc, 0x70, 0xbe, 0x03, 0x8c, 0xa5, 0x3e, 0x38, 0x46, 0x75, 0xba, 0xcc, 0x73, 0x9d, 0xbe, 0x64, 0x62, 0xc6, 0xbe, 0xa4, 0xab, 0xc1, 0xbe, 0x50, 0x40, 0xd5, 0xbc, 0x6e, 0x28, 0x36, 0x3e, 0xfc, 0x99, 0xa7, 0xbd, 0x41, 0x34, 0x83, 0xbd, 0xd4, 0x9c, 0x95, 0xbe, 0x74, 0xd9, 0xd4, 0xbe, 0x60, 0x47, 0xcc, 0xbd, 0x80, 0xeb, 0x2a, 0xbc, 0xd2, 0x0e, 0x0e, 0x3e, 0x16, 0x10, 0x73, 0xbe, 0xcf, 0x86, 0x80, 0xbe, 0x8d, 0x0a, 0xc4, 0x3e, 0x8e, 0xd9, 0x75, 0xbe, 0x4c, 0x46, 0x1e, 0xbe, 0x75, 0x01, 0x8e, 0x3e, 0x6b, 0x1e, 0x93, 0x3e, 0x6b, 0x2b, 0x8b, 0x3e, 0xf0, 0xa3, 0x87, 0x3c, 0xfe, 0x32, 0x23, 0x3e, 0xa5, 0x13, 0xd9, 0xbe, 0x6d, 0xee, 0xb5, 0xbe, 0x12, 0x9c, 0x00, 0x3e, 0x5e, 0x8f, 0x84, 0xbe, 0x8d, 0xc7, 0xd4, 0x3e, 0x44, 0x8e, 0x97, 0xbd, 0x34, 0x78, 0xc1, 0xbd, 0x87, 0xe2, 0x95, 0xbe, 0x04, 0xd7, 0x13, 0xbe, 0x56, 0x9c, 0x21, 0xbe, 0xc0, 0x7f, 0x38, 0x3c, 0x20, 0x8d, 0x9a, 0xbd, 0x6e, 0x10, 0x7a, 0x3e, 0x98, 0x35, 0x56, 0xbe, 0x0d, 0x91, 0xb1, 0xbe, 0x20, 0x4a, 0x24, 0xbc, 0x3a, 0x75, 0x18, 0x3e, 0x5e, 0xb8, 0xfe, 0x3e, 0x30, 0x7d, 0x82, 0x3c, 0x55, 0x7b, 0x2e, 0xbf, 0x6f, 0xf9, 0x04, 0xbf, 0x37, 0x30, 0x0d, 0xbe, 0x65, 0x8e, 0x8f, 0x3e, 0x3b, 0xa9, 0xdd, 0xbe, 0x16, 0x82, 0x30, 0x3e, 0xe3, 0xc4, 0xc9, 0x3e, 0x40, 0xfe, 0x3c, 0xbd, 0xf8, 0x8c, 0xb8, 0xbd, 0x63, 0x73, 0xb8, 0x3e, 0x80, 0x32, 0x19, 0xbd, 0xed, 0xeb, 0x9b, 0x3e, 0x5e, 0xdb, 0x5f, 0xbf, 0xca, 0x7b, 0xbf, 0xbd, 0x56, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xd6, 0x71, 0x5f, 0x3e, 0x50, 0x48, 0x87, 0xbd, 0x70, 0x88, 0x8b, 0x3e, 0xe6, 0xc2, 0x3e, 0x3e, 0xc7, 0x8e, 0xdf, 0x3e, 0x40, 0xec, 0x6a, 0xbc, 0xe6, 0xb2, 0xe7, 0xbe, 0xf0, 0x9b, 0x22, 0xbd, 0xf9, 0x13, 0x1c, 0x3f, 0x0c, 0xb8, 0xbb, 0xbe, 0xd4, 0xdc, 0x03, 0x3f, 0xe4, 0xaa, 0xd3, 0xbd, 0xc2, 0xc5, 0x89, 0xbe, 0xf2, 0x4a, 0xf8, 0xbe, 0x11, 0x2e, 0xa6, 0x3e, 0x11, 0xf3, 0xa7, 0x3e, 0xa2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xb4, 0x52, 0xb1, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x18, 0xe8, 0xbe, 0x56, 0x43, 0x54, 0xbe, 0x36, 0x0d, 0x8a, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x9d, 0x33, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xe1, 0xa9, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xb9, 0x4c, 0xbf, 0xbb, 0x63, 0x1c, 0xbd, 0xee, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc6, 0x4f, 0xe0, 0xbe, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7f, 0x35, 0xd9, 0x3d, 0xd6, 0x1a, 0x9d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x9f, 0x97, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xbd, 0x88, 0x3e, 0xff, 0x0e, 0x44, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x62, 0x77, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3b, 0x8f, 0x3e, 0x20, 0xfb, 0xff, 0xff, 0x24, 0xfb, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, 0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9a, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9c, 0xfb, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xba, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x8c, 0x03, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0xac, 0x02, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb2, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x9c, 0xfc, 0xff, 0xff, 0x19, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xf4, 0xfc, 0xff, 0xff, 0x4c, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x96, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x80, 0xfd, 0xff, 0xff, 0x46, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x86, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf4, 0xfd, 0xff, 0xff, 0x19, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xce, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3c, 0xfe, 0xff, 0xff, 0x19, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x16, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x84, 0xfe, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5a, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x29, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x18, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x29, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }; /** * Wrapper around the EloquentTinyML library */ template<uint32_t arenaSize> class TensorFlowPorter { public: Eloquent::TinyML::TensorFlow::AllOpsTensorFlow<1, 1, arenaSize> tf; /** * Init model */ bool begin() { return tf.begin(modelData); } /** * Proxy */ uint8_t predict(uint8_t *input, uint8_t *output = NULL) { return tf.predict(input, output); } /** * Proxy */ int8_t predict(int8_t *input, int8_t *output = NULL) { return tf.predict(input, output); } /** * Proxy */ float predict(float *input, float *output = NULL) { return tf.predict(input, output); } /** * Proxy */ template<typename T> uint8_t predictClass(T *input) { return tf.predictClass(input); } /** * Proxy */ float getScoreAt(uint8_t index) { return tf.getScoreAt(index); } /** * Proxy */ String getErrorMessage() { return tf.getErrorMessage(); } }; TensorFlowPorter<ARENA_SIZE> modelo_seno; #endif
Finalmente, com o script em C++ em mãos, podemos carregá-lo para o Arduino IDE e, então, para a placa. Os passos para uso do ESP32 através do IDE do Arduino já foram abordados de forma mais extensiva em diversos posts aqui do blog, como este aqui.
Iremos usar a biblioteca EloquentTinyML para que não seja necessário baixar a estrutura completa do TensorFlow Lite e compilá-la em sua própria máquina. Para baixá-la, abra o Arduino IDE e vá para Sketch > Incluir Biblioteca > Gerenciar Bibliotecas e procure por EloquentTinyML. Selecione a versão a partir da 2.4.4 e então clique em instalar.
Finalmente, podemos carregar nosso código principal para o ESP32.
// importe o arquivo c++ gerado na etapa anterior #include "modelo_seno.h" void setup() { Serial.begin(115200); while (!modelo_seno.begin()) { Serial.print("Erro ao carregar modelo_seno: "); Serial.println(modelo_seno.getErrorMessage()); } } void loop() { for (int i = 0; i < 20; i++) { // escolha aleatória entre 0 e pi float x = 3.14f * i / 20.0f; // criando array float input[1] = { x }; // gerar valor real do seno do número float y_true = sin(x); // gerando valor do seno a partir do modelo float y_pred = modelo_seno.predict(input); // printar o valor real do seno e o valor gerador pelo modelo para comparação Serial.print("seno de "); Serial.print(x); Serial.print(" = "); Serial.print(y_true); Serial.print("\t seno previsto: "); Serial.println(y_pred); delay(1000); } }
É possível que, na hora de compilar o código, a biblioteca EloquentTinyML retorne um erro do tipo “No such file or directory”. Nesse caso, será necessário trocar a versão do Arduino IDE para a 1.8.18, 1.8.9 ou anterior, de forma a não gerar mais incompatibilidades com a biblioteca.
Finalmente, é só compilar o código e carregá-lo para a placa! No vídeo abaixo, é possível ver o projeto em execução através do simulador Wokwi, cujo uso também já foi explicado em outro post do blog. A simulação é conferida neste link.
Ao combinar o poder dos algoritmos de IA com a interconectividade de dispositivos IoT, os sistemas AIoT podem desbloquear níveis sem precedentes de automação, tomada de decisão e análise de dados. Neste artigo, exploramos os conceitos essenciais de AIoT e redes neurais e demonstramos como construir uma rede neural simples usando o TensorFlow Lite para prever o seno de um número que varia de 0 a π.
Embora o exemplo fornecido seja direto, ele mostra o potencial dos aplicativos AIoT. Ao aproveitar o TensorFlow Lite, você pode implantar modelos de aprendizado de máquina em dispositivos com recursos limitados, abrindo um mundo de possibilidades para soluções AIoT e permitindo uma tomada de decisão mais inteligente e eficiente para seus projetos futuros!
Caso tenha alguma dúvida ou sugestão, deixe um comentário abaixo! E, caso execute o projeto, não deixe de nos mostrar e marcar no Instagram @eletrogate.
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!