Classificando áudios com I.A. em seu app Flutter (TensorFlow e Teachable Machine)

Utilizando Aprendizado de Máquina para distinguir músicas de podcasts

Gustavo Duregger
suamusicatech
10 min readMar 4, 2022

--

O que faremos

Construir modelos assertivos de Machine Learning pode ser algo bastante complexo para iniciantes e até para aqueles que já mexeram com sistemas baseados em I.A. Motivado nessa premissa, a ferramenta Teachable Machine foi criada para elaborar esses modelos de uma forma bastante didática e rápida, abstraindo muitos passos que você faria se construísse a I.A. de um jeito mais tradicional. No fim a ferramenta nos dará um arquivo gerado do TensorFlow prontinho para gente implementar no Flutter e é isso que faremos hoje nesse artigo.

O Projeto que a gente irá criar aqui tem o objetivo de classificar se um áudio é uma música ou uma fala de uma pessoa, como por exemplo em um podcast.

Sobre o tutorial

Nesse artigo, quero te mostrar como criei um classificador de músicas e podcasts no Flutter e o potencial do TensorFlow em fazer isto. Talvez esse artigo possa te ajudar a criar um classificador entre diferentes tipos de áudios (e não somente entre as classes aqui abordadas), se esse é seu objetivo, acredito que esse artigo será bastante útil para você. 😁

Abaixo você encontra o repositório GitHub com tudo que será feito aqui.

Nesse tutorial eu suponho que você já esteja familiarizado com o básico do Flutter, coisas como criar um projeto, configurar permissões, trabalhar com pacotes externos e construir telas simples.

No final teremos algo parecido com isso

  1. Um botão que grava o áudio do microfone do dispositivo
  2. Cards apresentando o resultado da classificação do áudio pelo TensorFlow
Figura 1. Gif representando o resultado final do projeto.

O que é o TensorFlow e o Teachable Machine

TensorFlow é uma biblioteca para construção de modelos baseados em Machine Learning, com ele você consegue criar e treinar redes neurais artificiais para encontrar padrões e correlações em objetos (imagens, números, sons, etc). O Teachable Machine é uma ferramenta que abstrai essa criação e treinamento de modelos, tornando isso muito mais rápido e fácil de se fazer.

Se você não faz idéia de como funciona esses modelos, recomendo a leitura do artigo "A Beginner’s Guide to Machine Learning" do Randy Lao, onde ele explica de uma forma bem didática como funciona, mas apesar de ser algo legal de saber, esse conhecimento não é um pré-requisito para a construção do nosso projeto aqui, pois como mencionei, o Teachable Machine abstrai muito desses processos para gente.

Criando Modelo no Teachable Machine

Colocado as expectativas e as tecnologias na mesa, é hora da gente por mão na massa!. Vamos começar criando nosso modelo no Teachable Machine. Entrando na plataforma você poderá escolher entre três tipos de projetos, você conseguirá classificar imagens, áudios ou poses. Aqui a gente irá escolher um projeto de áudio, mas o processo de ensinar a máquina é bem parecido nos três.

Figura 2. Página de criação de projeto do Teachable Machine.

Inclusive caso queira explorar os outros modelos de projeto do Teachable Machine, no repositório que disponibilizei no GitHub, você irá encontrar tanto a implementação da classificação de áudio quanto uma implementação de classificação de imagens.

Ao selecionar um projeto de áudio, você cairá nessa tela (Figura 3), aqui é onde a mágica acontece. Na primeira etapa você criará as classes na qual você quer classificar, ou seja, se você quer distinguir, na sua classificação, um miado de um gato e um latido de cachorro por exemplo, você pode criar uma classe chamada miado (onde está Class 2) e uma outra classe chamada latido.

Figura 3. Página de criação de modelo no Teachable Machine

No nosso caso a ideia é classificar músicas e podcasts, então irei criar uma classe chamada Music e outra chamada Speech. Perceba que temos uma classe padrão na ferramenta chamada Background Noise, nela a gente vai alimentar com áudios de ruído (ambiente), assim nosso modelo não irá se confundir quando algum tipo de ruído estiver em uma das nossas classes.

Criada as classes, chegou a hora de alimenta-las com muitos dados, isto é, na classe de músicas enviar vários samples de músicas e na classe de podcast enviar vários samples de podcasts.

Uma limitação que encontrei neste momento foi o fato de eu não conseguir fazer um upload de um arquivo MP3 nas classes, o que dificultou bastante a criação do dataset, pois desta forma, precisei regravar cada sample pelo microfone do Teachable Machine para que o arquivo fosse compatível com a plataforma. Essa limitação teve um impacto real no desenvolvimento visto que, não seria tão viável criar um dataset com muitos exemplos para serem treinados, impactando no resultado da aplicação.

Figura 4. Erro apresentado pela ferramenta ao tentar enviar arquivos MP3.

Quando criei o modelo de imagens eu não tive esse tipo de limitação, o que facilitou bastante, pois bastou baixar um dataset pronto no Kaggle e enviar para cada uma das classes.

Figura 5. Classes de objeto alimentadas e modelo treinado.

Depois de enviar todos os áudios, chegou a hora de treinar nosso modelo, aqui eu posso determinar quantas Epochs eu quero fazer para treinar meu modelo, esse número irá determinar quantas vezes o algoritmo de aprendizado vai rodar em todo conjunto de dados.

Por baixo dos panos, basicamente a ferramenta está procurando padrões e semelhanças nos áudios que a gente enviou para ela, dessa forma, nosso modelo está aprendendo o que é uma música e o que é um podcast.

Um erro que cometi aqui é achar que quanto mais epochs tiver no nosso modelo, melhor treinado ele será e, consequentemente, teremos uma melhor acurácia.

De fato, quanto mais epochs você rodar, melhor seu modelo irá predizer e classificar um novo objeto. Mas um ponto muito importante é que essa melhora não é linear, geralmente o maior aprendizado ocorre nas primeiras épocas e esse aprendizado vai decaindo conforme o tempo passa, ou seja, se você utilizar um número muito alto de épocas, você acabará desperdiçando tempo e processamento.

Figura 6. Gráfico da acurácia em relação as épocas.

Veja no gráfico que depois que o algoritmo rodou mais de 80 épocas, ele não aprendeu mais nada nas épocas seguintes. Acredito que um bom número no nosso caso de uso seria 50, onde teríamos praticamente os mesmos resultados com a melhor otimização entre tempo e processamento.

Modelo treinado, agora é só exportar. Na aba preview, além de você conseguir já testar seu modelo para ver se está tudo ok, você consegue exportar o modelo em um arquivo TensorFlow Lite.

Figura 7. Exportando modelo do Teachable Machine.

Você terá duas opções, a nossa é o TensorFlow Lite, no qual usaremos para aplicá-lo ao Flutter, portanto, basta selecionar e clicar em “download my model”, a ferramenta irá nos gerar um arquivo zip com dois arquivos, uma com as labels das nossas classes e outra que é nosso modelo de fato (.tflite).

Implementação no Flutter

Legal, com o modelo em mãos, temos tudo para começar a classificar nossas classes no Flutter. O primeiro passo é criar um projeto e uma pasta na mesma altura da lib chamada de assets. Aqui eu coloquei os arquivos gerados pelo Teachable Machine dentro de uma pasta chamada audio.

Figura 8. Pasta assets no projeto.

Além disso precisamos adicionar a rota desses arquivos e adicionar nossas dependências no projeto. Para isso, a gente vai até o arquivo pubspec.yaml e colocamos o pacote tflite_audio: ^0.2.2+4, além disso, vamos aproveitar para já colocar as rotas dos arquivos.

Para instalar o pacote basta escrever o comando no terminal.

Além disso precisaremos configurar algumas coisas nos arquivos nativos do Android para que tudo ocorra como estamos esperando. Primeiro temos que adicionar as permissões necessárias. Então você vai até o AndroidManifest.xml e adiciona as seguintes permissões.

O próximo passo é adicionar o tflite no aaptOtions, você irá encontrar ele em android/app/build.gradle

Ainda no build.gradle, precisamos mudar o targetSdkVersion e o compileSdkVersion para 31. Alterei também o minSdkVersion para 21. E ativei o select-ops nas dependências.

E é isso ai, se alguma coisa falhar nessa parte, recomendo você dar uma olhada na documentação do pacote do tflite_auldio (https://pub.dev/packages/tflite_audio), lá tem uma seção que entra em mais detalhes de como configurar essa parte, ou se preferir, pode ver meus arquivos no GitHub, são eles o AndroidManifest (debug), AndroidManifest (profile) e o build.gradle.

Projeto configurado agora começa a parte legal, vamos implementar de fato nosso modelo. Gosto de começar já estruturando todo o meu projeto, mas se preferir ir construindo ele no passo a passo fica a seu critério.

Figura 9. Estrutura de arquivos e pastas do projeto.

Eu separei desta forma, mas você pode fazer da maneira que for mais adequado ao seu contexto. Na pasta common eu colocarei os widgets que serão compartilhados entre as features, fiz desta maneira logo que estarei fazendo tanto a classificação por áudio quanto a de imagem, ou seja, features diferentes, mas se este não for seu caso, você pode alocar tudo isso dentro da sua feature, que no meu caso é a audio.mic. Dentro da minha feature de reconhecimento de áudio eu terei uma camada presentation onde estará a pagina e os widgets.

Agora vou construir os widgets que irão compor nossa tela, eles serão três, como mostro na imagem abaixo.

Figura 10. Composição da tela.

Primeiro vamos começar pelo inference_time, ele vai ser responsável por nos informar o tempo de inferência que está ocorrendo no momento da gravação do áudio, ele pode ajudar você a calibrar melhor a sua detecção, falarei sobre isso logo mais.

Agora o card_detector, ele vai ser responsável por mostrar a label em que esta sendo reconhecido.

Para construir a lista de cards com as labels, precisamos criar o label_list, que vai passar os objetos para o card_detector e construir o que vimos na tela anteriormente.

Perceba que ele faz uma verificação no nome da label para apresentar de uma forma mais bonita para o usuário.

Componentes criados, hora de juntar tudo e fazer nossa página. Criei um pagina chamada AudioMicPage (StatefulWidget) e nela irei criar um Scaffold, onde será construído um StreamBuilder, que vai receber os eventos do usuário e se comunicar com o tflite_audio.

Perceba que nossa tela está chamando métodos que ainda não existem, como o getResult no FloatActionButton, o que a gente vai fazer agora é criar esses métodos que serão responsáveis de fato em gravar o áudio e se comunicar com o tflite_audio para assim classificar esse áudio. Vamos começar inicializando as variáveis.

Aqui definimos a rota daqueles arquivos que estão nos nossos assets que foram gerados no Teachable Machine e carregamos nosso modelo com o package.

Agora vamos criar o getResult, ele vai chamar o um outro método do TfliteAudio que inicia o reconhecimento de áudio.

A ideia aqui é você ajustar esse valores até conseguir o melhor resultado da sua classificação. Caso esteja enfrentando dificuldades com sua classificação, tente alterar os valores de:

  • numThreads - Quanto mais threads, menor o tempo de inferência, porém aumenta o uso de CPU.
  • detectThreshold - Útil caso em seu contexto, você capture sons não intencionais, como ruídos externos. Caso o desempenho do modelo estiver indo mal é recomendado diminuir este valor.
  • bufferSize - O Valor desse parâmetro deve ser igual ou inferior à duração da gravação.
  • sampleRate - Uma taxa de amostragem mais alta pode melhorar a precisão. Os valores recomendados são 16000, 22050, 44100.

Agora vamos fazer o método fetchLabelList que será responsável por fazer o match das labels.

E por fim, um método para mostrar o resultado da classificação.

Nesse ponto você já deve ter percebido que defini constantes como cores e textos numa camada externa, elas não são necessárias mas deixam o código mais limpo e organizado.

Depois de juntar tudo, nossa classe referente a página do classificador ficará assim.

Por fim, é chamar a página na main.

Agora é testar e correr pro abraço 😁. O Resultado da tela será algo assim:

Figura 11. Resultado final da aplicação.

Considerações finais

Por fim conseguimos criar um classificador de músicas e podcasts de uma maneira simples e que nos trouxe resultados bem bacanas.

Apesar disso o Teachable Machine trouxe algumas limitações em relação ao envio de arquivos para o treinamento do modelo. Inicialmente a ideia era criar um classificador de Gêneros Musicais, que até funcionou bem em alguns casos como ao comparar o Piseiro com Rock, mas que falhou ao comparar, por exemplo, Piseiro e Forró. Acredito que estes problemas ocorreram por dois fatores, uma delas justamente pela impossibilidade de enviar um pacote de arquivos MP3 (o que torna inviável fazer um dataset grande para o aprendizado) e pelo fato da própria abstração criada pelo Teachable Machine, logo que não é possível ajustar parâmetros mais específicos do nosso contexto, algo que seria trivial se estivéssemos criando um modelo diretamente no TensorFlow.

Todavia as ferramentas apresentadas mostrou um enorme potencial tendo em vista a tamanha facilidade e velocidade em criar os modelos, principalmente quando aplicamos em outros tipos de projetos disponíveis no Teachable Machine, como o de reconhecimento de imagens, que não possui a limitação de upload apresentada ou em arquivos de áudios mais simples.

E ai gostaram? se tiverem alguma dúvida, se esse artigo te ajudou de alguma forma ou se apenas quiser dar um feedback, pode mandar um comentário aqui. Abaixo estarei colocando algumas referências que me ajudaram a elaborar o artigo, caso queira aprofundar um pouco mais no assunto, pode ser bastante útil para ti. Valeu!

Referências

Pub.dev — TFlite Audio Plugin for Flutter. (Acesso: 4 de março de 2022).

Randy Lao — A Beginner’s Guide to Machine Learning. (Acesso: 4 de março de 2022).

Teachable Machine — Train a computer to recognize your own images, sounds, & poses. (Acesso: 4 de março de 2022).

TensorFlow — Implante modelos de machine learning em dispositivos móveis e Internet das Coisas. (Acesso: 4 de março de 2022).

--

--