Este tutorial ensina como treinar um modelo personalizado de aprendizado de máquina com o Edge Impulse e realizar classificação de imagens no Arduino Nicla Vision. O modelo de aprendizado de máquina (ML) utilizará o formato TensorFlow Lite, e o exemplo de classificação será executado no OpenMV.
Objetivos e Materiais Necessários
Os objetivos do projeto estão listados abaixo:
- Aprender a criar conjuntos de dados para serem usados na classificação.
- Aprender a treinar um modelo de ML no Edge Impulse.
- Aprender a usar o OpenMV para executar um exemplo de classificação.
- Aprender a incorporar um modelo de ML no firmware do OpenMV.
Para completar este tutorial, você vai precisar de:
- Placa Nicla Vision.
- Cabo Micro USB.
- Uma conta Edge Impulse para treinar o modelo de ML.
- Frutas (ou outros objetos) para criar o modelo de classificação.
Aprendizado de Máquina na Borda
O aprendizado de máquina em computadores potentes existe há algum tempo. Em microcontroladores, isso é uma área relativamente nova. Microcontroladores podem não ser capazes de executar modelos de ML para processar imagens de alta resolução a taxas de quadros elevadas, mas há aspectos interessantes. Por um lado, microcontroladores podem operar com consumo de energia muito baixo em baterias por um longo período. Você pode até colocar o processador para dormir e acordá-lo apenas quando a câmera ou o sensor de proximidade a bordo registra atividade. Por outro lado, modelos de ML em um microcontrolador podem funcionar sem conexão com a internet, já que não precisam enviar dados para a nuvem. Isso significa que você pode instalar soluções de ML distribuídas em locais sem conexão com a internet (Computação na Borda). Além disso, processar dados localmente significa que os dados permanecem no dispositivo, garantindo a privacidade dos dados.
A Plataforma Edge Impulse
O Edge Impulse é uma plataforma que simplifica o processo de criação de modelos de aprendizado de máquina, escolhendo padrões razoáveis para os inúmeros parâmetros que você poderia configurar ao criar um modelo de ML. Ele fornece uma interface de usuário simples que não apenas permite treinar um modelo de ML, mas também inspecionar os dados e testar o modelo.
Treinando o Modelo de ML
Para treinar um modelo de ML para classificar uma imagem, precisamos alimentá-lo com dados de imagem desse objeto. Durante o processo de treinamento, o modelo será treinado usando um conceito chamado aprendizado supervisionado. Isso significa que treinamos o modelo com dados conhecidos e informamos enquanto ele está “praticando” suas previsões se estão corretas ou não.
Isso é semelhante ao que acontece quando você diz a uma criança pequena que está apontando para um burro dizendo “cavalo” e explica a ela que na verdade é um burro. Nas próximas vezes em que veem um burro, eles ainda podem errar, mas com o tempo, sob sua supervisão, aprenderão a identificar corretamente um burro. Conceitualmente, é assim que nosso modelo de ML aprende.
Overfitting
Uma coisa a considerar é o overfitting. Se um modelo de aprendizado de máquina está overfitting, significa que está muito bem ajustado aos seus dados de treinamento e não se sairá bem com dados de entrada não vistos.
Voltando ao exemplo acima, uma vez que a criança tenha visto muitos burros, todos com pelagem perfeitamente cinza, todos com 170 cm de comprimento e 127 cm de altura, eles aprendem que um burro deve ser exatamente assim, caso contrário, não é um burro. Se agora aparecer um burro ligeiramente mais alto, a criança teria que pensar que não é um burro. E mesmo que houvesse um burro marrom, ligeiramente mais alto, que a criança tenha visto muitas vezes, isso não ajudaria necessariamente, já que a criança pode simplesmente se lembrar daquele burro específico que parece um pouco estranho. Ela pode não ter aprendido que burros podem ter tons diferentes de cor na pelagem.
Você precisa de alguma variação no conjunto de dados de treinamento e ajustar os parâmetros para que o modelo não apenas memorize todos os dados de entrada e faça a classificação com base nisso, mas você quer que o modelo aprenda o conceito de um objeto. Felizmente, no mundo real, isso raramente acontece. No entanto, no aprendizado de máquina, é uma armadilha comum.
Encontrar a configuração certa para sua aplicação frequentemente requer tentativa e erro. O Edge Impulse mostra neste artigo como melhorar modelos de aprendizado de máquina com desempenho insatisfatório.
Criação de um Conjunto de Dados
O primeiro passo é criar um conjunto de dados representativo dos objetos que o modelo de ML deve identificar. A chave é ter o máximo de diversidade nos modelos quanto possível. Se mostrarmos, por exemplo, apenas uma maçã específica com um certo tamanho, forma e casca, o modelo não será muito bom em reconhecer outras maçãs que parecem diferentes. Isso é chamado de viés e deve ser evitado o máximo possível.
Além disso, você precisa ensinar ao modelo o que não é uma maçã. Para esse propósito, alimente-o com dados de imagem aleatórios de coisas que não são maçãs. Você pode nomear essa classe de dados de imagem como “desconhecido”. Se você não tiver essa classe e o modelo só tiver visto uma maçã, ele não saberá o que fazer se não houver uma maçã na imagem.
A criação de conjuntos de dados no OpenMV é simples, pois há uma função incorporada para criá-los. Antes de prosseguir, conecte sua placa Nicla Vision. Clique no botão de conexão na IDE do OpenMV.
Crie um novo conjunto de dados usando o comando de menu Tools > Dataset Editor > New Dataset e nomeie-o como Dataset-Fruits.
O próximo passo é criar classes de imagem. Uma classe representa um tipo único de objeto, neste caso, o tipo de fruta.
Primeiro, crie uma nova classe de imagem e nomeie-a laranja clicando em “New Class Folder” na barra de ferramentas. Execute o script de captura de imagem que já está aberto clicando no botão de reprodução. Foque na laranja com a câmera e clique em Capture Data para tirar uma foto dela. Para segurar convenientemente a câmera com o cabo voltado para baixo, você pode usar as seguintes linhas de código para inverter a imagem adequadamente:
sensor.set_vflip(True) # Inverte a imagem verticalmente sensor.set_hmirror(True) # Espelha a imagem horizontalmente
Capture-a de diferentes ângulos e com diferentes fundos para tornar o reconhecimento posterior mais robusto. Repita isso para outras frutas que você gostaria de classificar (por exemplo, uma pera e uma banana). Adicione uma classe desconhecida e capture algumas imagens com diferentes fundos sem as frutas que você gostaria de usar durante a classificação posterior.
Você pode ter notado que há também um arquivo de texto de rótulos. Este arquivo é usado para armazenar uma representação textual das classes para mais tarde classificar os objetos e imprimir os nomes das classes. As classes são adicionadas automaticamente a ele.
Importante! Observe que criar um modelo de aprendizado de máquina com dados de treinamento baseados apenas em uma fruta específica, sempre usando o mesmo fundo, não cria um modelo robusto. Ele se sairá bem em um ambiente controlado, mas terá dificuldades ao ser apresentado com novos dados.
Upload dos Dados para o Edge Impulse
Agora que todos os dados estão prontos para serem enviados, você precisa criar um novo projeto no Edge Impulse. Se ainda não tiver registrado uma conta no Edge Impulse, você pode criar uma em seu site. Faça login no Edge Impulse Studio e crie um novo projeto chamado Fruit-Detector.
Depois disso, você pode voltar para a IDE do OpenMV e selecionar Tools > Dataset Editor > Export > Log in to Edge Impulse Account and Upload to Project. A IDE do OpenMV pedirá suas credenciais de login do Edge Impulse. Selecione o projeto que você acabou de criar e clique em OK. Deixe as configurações de divisão do conjunto de dados no padrão. Isso manterá 20% das imagens de lado para testar o modelo assim que ele for treinado. Isso permite avaliar o desempenho do seu modelo na detecção dos objetos com dados que ele ainda não viu.
Aquisição de Dados no Edge Impulse
Abra seu projeto no estúdio Edge Impulse e vá para “Data Acquisition”. Você verá que as imagens foram enviadas e rotuladas de acordo com as classes que você criou. Com essa ferramenta, você pode navegar pelas amostras de imagem e remover aquelas que não considera valiosas para o treinamento (por exemplo, se uma das imagens estiver muito borrada). Você também pode fazer isso na IDE do OpenMV antes de enviar os dados.
Certifique-se de ter uma boa proporção de divisão entre dados de treinamento/teste, por volta de 80/20. Os dados de teste são usados para testar o modelo com dados “não vistos” após o término do treinamento. Se você tiver um modelo de sobreajuste, poderá ver alta precisão nos resultados do treinamento, mas baixo desempenho nos resultados do teste. Se for o caso, você pode ter que ajustar os parâmetros ou coletar mais/melhores dados de treinamento. Mais informações sobre isso podem ser encontradas na documentação do Edge Impulse mencionada acima.
Criação de um Impulso
Se você estiver satisfeito com as amostras de dados, pode passar para o design do seu impulso. Um impulso é, em essência, uma receita com a qual o modelo está sendo treinado. Ele define ações que são realizadas nos seus dados de entrada para torná-los mais adequados para aprendizado de máquina e um bloco de aprendizado que define o algoritmo para a classificação. No menu, vá para “Create Impulse” em “Impulse Design” e adicione um bloco de processamento de imagem e um bloco de aprendizado de transferência.
Recomenda-se ajustar o tamanho da imagem para 48×48 para melhor desempenho. Você pode tentar com resoluções mais altas, mas notará que a taxa de quadros durante a classificação diminuirá significativamente. Clique em Save Impulse para aplicar as configurações ajustadas.
Geração de Recursos
Nesta etapa, você ajustará as configurações da imagem e gerará os recursos a partir dos dados de entrada. Recursos são propriedades únicas que serão usadas pelo algoritmo de classificação para detectar os objetos. Um recurso pode ser a forma redonda de uma laranja ou o fato de que uma imagem de uma banana tem muitos pixels claros, já que as bananas são principalmente amarelas. No menu, vá para “Image” em “Impulse Design”. Defina a profundidade de cor para “RGB” e salve os parâmetros.
Em seguida, clique em “Generate Features”. O processo de análise levará algum tempo para ser concluído, dependendo da quantidade de imagens que você enviou. Quando estiver pronto, você pode inspecionar os resultados. No lado direito, você verá uma visualização dos recursos em um espaço 3D. Você pode ver que algumas bananas (pontos azuis) e peras (pontos verdes) são um pouco difíceis de distinguir, possivelmente devido à sua forma alongada e ao caule, e, portanto, têm alguns pontos de dados próximos. Uma laranja, por outro lado, é mais fácil de distinguir, pois parece bastante diferente.
O explorador de recursos permite inspecionar visualmente os aglomerados de imagens em relação às suas propriedades.
Treine o Modelo
Agora que as características dos seus dados de imagem estão prontas para serem usadas no treinamento real, você pode navegar até “Transfer Learning” no menu. Você precisa ajustar ligeiramente as configurações. Defina o “Número de ciclos de treinamento” para um número que produza bons resultados. Neste exemplo, escolhemos 80. Isso define quantas vezes o modelo está sendo treinado. O modelo melhora a cada ciclo da mesma forma que você melhora ao aprender a andar de bicicleta e praticá-lo nas primeiras tentativas.
Importante! Escolha MobileNetV2 96×96 0.1 como tipo de modelo. Isso usará aproximadamente 200 KB de memória flash. Um modelo com uso maior de ROM provavelmente não caberá na flash!
Neste exemplo, também aumentamos a taxa de descarte para 0,15 e os neurônios de saída para 12. Isso aumentou a precisão com os dados de treinamento/teste fornecidos. Você pode precisar adaptar esses valores com base nos seus próprios dados.
Clique em “Start Training” para treinar o modelo de aprendizado de máquina. Uma pequena quantidade de imagens, o conjunto de validação, é separada antes do início do treinamento para validar o modelo treinado. Não confunda com o conjunto de teste, que pode ser usado para avaliar o modelo final. Uma vez que o treinamento termina, você verá algumas estatísticas sobre o desempenho do modelo durante a validação. Idealmente, você obtém uma precisão de 100% para cada objeto. Se você obtiver resultados ruins, pode ter algumas imagens que não são representativas dos objetos que está tentando classificar e devem ser removidas do conjunto de dados.
Teste o Modelo
Após treinar o modelo, você terá uma ideia de quão bem ele se sai nos dados que conhece do treinamento. Isso é apenas metade da história. Você também precisa saber quão bem ele se sai em dados não vistos. Em quase qualquer aplicação do mundo real, um modelo será confrontado apenas com dados não vistos. Ser capaz de lidar com isso é crucial. O estúdio Edge Impulse fornece uma ferramenta para testar facilmente o modelo. Você pode encontrá-lo em “Model Testing”. Os resultados dos testes do modelo fornecerão uma visão sobre o desempenho. Se o modelo obtiver resultados ruins durante os testes, mas teve uma boa precisão após o treinamento, pode estar ocorrendo overfitting.
Você pode se perguntar por que esse modelo se sai tão bem, mesmo que o modelo não seja robusto. É porque os dados usados para teste vêm do mesmo ambiente controlado que os dados de aprendizado. As imagens de teste têm o mesmo fundo e apresentam exatamente as mesmas frutas que as imagens de treinamento. Se você esperar alguns dias até que a banana fique marrom, verá uma diminuição no desempenho.
Os resultados dos testes fornecem uma melhor compreensão de como o modelo se sai com dados não vistos.
Usando o Modelo de ML
O modelo de ML está treinado e otimizado para ser usado com microcontroladores. Isso é feito automaticamente em segundo plano por meio da quantização. Este é um processo onde os números nos modelos de aprendizado de máquina são limitados em sua faixa de valor para melhorar o desempenho, sacrificando um pouco da precisão.
Implementação
Implantar o modelo de ML na sua placa requer alguns passos simples. O Edge Impulse Studio fornece uma função de exportação para o OpenMV. Como a Nicla Vision não possui nenhum chip SRAM dedicado que forneceria memória suficiente para carregar o modelo de ML em tempo de execução, precisamos incorporar o modelo de aprendizado de máquina no firmware e carregá-lo da flash.
Mude para a seção de implantação no menu, selecione “OpenMV Firmware” em “Configure your deployment” e clique em “build”. Isso criará um firmware compatível com o OpenMV que inclui o modelo de aprendizado de máquina. Descompacte o arquivo assim que for baixado. O download deve começar automaticamente.
Coloque a placa no modo de inicialização e clique no símbolo de conexão na IDE do OpenMV. Na caixa de diálogo, selecione “Load a specific firmware”. Selecione edge_impulse_firmware_arduino_nicla_vision.bin na pasta que você criou ao descompactar o arquivo baixado e faça o flash na placa.
Execute o Script
O último passo é executar o script ei_image_classification.py. Abra-o na IDE do OpenMV.
Substitua a instrução de impressão no loop mais interno com o seguinte código:
confidence = predictions_list[i][1] label = predictions_list[i][0] print("%s = %f" % (label[2:], confidence)) if confidence > 0.9 and label != "unknown": print("It's a ", label, "!")
Este código imprimirá uma mensagem como por exemplo “It’s a orange!” caso a confiança esteja acima de 90%. Na captura de tela a seguir, você pode ver que a laranja foi detectada com um nível de confiança de 0,99, o que corresponde a 99%.
Aponte a câmera da sua placa para qualquer uma das suas frutas ou outros objetos que você usou para o treinamento e verifique se ela pode ser reconhecida com sucesso.
O script completo do exemplo de classificação é o seguinte:
import sensor, image, time, os, tf sensor.reset() # Reset and initialize the sensor. sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE) sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240) sensor.set_vflip(True) sensor.set_hmirror(True) sensor.set_windowing((240, 240)) # Set 240x240 window. sensor.skip_frames(time=2000) # Let the camera adjust. labels, net = tf.load_builtin_model('trained') clock = time.clock() while(True): clock.tick() img = sensor.snapshot()
# default settings just do one detection... change them to search the image... for obj in tf.classify(net, img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5): print("**********\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect()) img.draw_rectangle(obj.rect()) # This combines the labels and confidence values into a list of tuples predictions_list = list(zip(labels, obj.output())) for i in range(len(predictions_list)): confidence = predictions_list[i][1] label = predictions_list[i][0] print("%s = %f" % (label, confidence)) if confidence > 0.9 and label != "unknown": print("It's a", label, "!") print(clock.fps(), "fps")
Conclusão
Você aprendeu sobre classificação como um conceito de aprendizado de máquina que categoriza um conjunto de dados em classes. Você também aprendeu como funciona o aprendizado supervisionado e o que significa quantização de um modelo. Além disso, você aprendeu a treinar um modelo de aprendizado de máquina TFLite personalizado e implantá-lo em sua placa.
Este post é uma tradução adaptada do artigo escrito por Sebastian Romero. O artigo original pode ser encontrado aqui.