Machine Learning com Node.js usando a biblioteca Tensorflow.js

Olá pessoal, colegas!

Talvez os fãs da biblioteca Tensorflow, que já notaram este livro em nossa pré-encomenda, também tenham analisado atentamente as possibilidades de aprendizado de máquina e profundo no navegador, principalmente porque o próprio François Schollet não ignorou o tópico. Convidamos os interessados ​​no gato, que informa como as imagens são reconhecidas usando a biblioteca Tensorflow.js.

O TensorFlow.js é uma nova versão da popular biblioteca de código aberto que enriquece o JavaScript com recursos de aprendizado profundo. Os desenvolvedores agora podem definir, treinar e executar modelos usando a API da biblioteca de alto nível .

Graças aos modelos pré-treinados, os desenvolvedores agora podem resolver facilmente tarefas complexas, como reconhecimento de padrões , geração de música ou determinação de posições humanas em apenas algumas linhas de JavaScript.

O Tensorflow.js começou como uma biblioteca front-end para trabalhar em um navegador, mas este ano foi adicionado suporte experimental ao Node.js. Portanto, o TensorFlow.js também pode ser usado em aplicativos de back-end JavaScript, o que evita completamente a necessidade de recorrer ao Python.

Lendo sobre esta biblioteca, decidi experimentá-la em uma tarefa simples ...
Use TensorFlow.js para reconhecimento visual de imagens em imagens ao usar JavaScript do Node.js.
Infelizmente, os exemplos de documentação e código descrevem principalmente o uso dessa biblioteca no navegador.Os utilitários de projeto projetados para simplificar o carregamento e o uso de modelos pré-treinados no momento da redação não suportavam o Node.js. Eu tive que gastar muito tempo para ler bem as fontes Typescript desta biblioteca.

No entanto, depois de alguns dias de sacudidela, eu ainda consegui! Viva!

Antes de passar para uma análise detalhada do código, vamos falar sobre outras implementações da biblioteca TensorFlow.

Tensorflow

O TensorFlow é uma biblioteca de software livre para aplicativos de aprendizado de máquina. O TensorFlow pode ser usado para criar redes neurais e implementar outros algoritmos de aprendizado profundo.

Esta é uma biblioteca lançada pelo Google em novembro de 2015, originalmente escrita em Python . Para treinamento e avaliação de modelos criados, ele usa cálculos em uma CPU ou GPU. Inicialmente, essa biblioteca foi criada para funcionar em servidores de alto desempenho usando GPUs com muitos recursos.

Atualizações recentes tornaram possível otimizar essa biblioteca e usá-la em ambientes com recursos mais limitados - por exemplo, em dispositivos móveis e navegadores da web.

TensorFlow Lite

O Tensorflow Lite , a versão lite desta biblioteca para dispositivos móveis e sistemas embarcados, foi lançado em maio de 2017. Juntamente com ele, é fornecido um novo conjunto de modelos profundos pré-treinados para tarefas relacionadas ao reconhecimento de padrões; essa coleção é chamada MobileNet . Os modelos MobileNet foram projetados especificamente para operação eficiente em ambientes com uma quantidade limitada de recursos, como dispositivos móveis.

TensorFlow.js

Após o Tensorflow Lite, o TensorFlow.js foi anunciado em março de 2018. Esta versão da biblioteca foi projetada para ser executada em um navegador e é baseada em um projeto anterior chamado deeplearn.js . O WebGL fornece acesso de GPU à biblioteca. Os desenvolvedores usam a API JavaScript para treinar, carregar e executar modelos.

Posteriormente, o TensorFlow.js foi expandido para funcionar com o Node.js, o add tfjs-node biblioteca do tfjs-node é usado para isso.

Importar modelos existentes para o TensorFlow.js

Os modelos TensorFlow e Keras prontos para execução podem ser executados usando a biblioteca TensorFlow.js. Antes de executar o modelo, você deve converter para um novo formato usando esta ferramenta . Modelos pré-treinados e transformados para classificar imagens, definir poses e detectar vizinhos k-mais próximos estão disponíveis no Github .

Usando TensorFlow.js com Node.js

Instalar bibliotecas do TensorFlow

O TensorFlow.js pode ser instalado a partir do registro do NPM .


 npm install @tensorflow/tfjs @tensorflow/tfjs-node // ... npm install @tensorflow/tfjs @tensorflow/tfjs-node-gpu 

Ambas as extensões do Node.js usam dependências nativas, que serão compiladas sob demanda.

Download de bibliotecas do TensorFlow

A API JavaScript para Tensorflow é fornecida na biblioteca principal. Nenhuma API de extensão é fornecida nos módulos de extensão que oferecem suporte ao Node.js.

  const tf = require('@tensorflow/tfjs') //   ( CPU) require('@tensorflow/tfjs-node') //    ( GPU) require('@tensorflow/tfjs-node-gpu') 

Download dos modelos TensorFlow

O TensorFlow.js fornece uma biblioteca NPM ( tfjs-models ) que simplifica o carregamento de tfjs-models pré-treinados e transformados para classificar imagens , definir poses e detectar os vizinhos mais próximos .

O modelo de classificação de imagens da MobileNet é uma rede neural profunda treinada para distinguir entre 1000 classes diferentes de imagens .

No arquivo LEIA-ME para o projeto, o código a seguir é usado como exemplo , usado para carregar o modelo.

 import * as mobilenet from '@tensorflow-models/mobilenet'; //   const model = await mobilenet.load(); 

Um dos primeiros problemas que encontrei é que esse código não funciona com o Node.js.

 Error: browserHTTPRequest is not supported outside the web browser. 

Após examinar o código fonte , vemos que a biblioteca mobilenet é um invólucro para a classe tf.Model . Quando chamado, o método load() baixa automaticamente os arquivos de modelo necessários localizados em um endereço HTTP externo e instancia o modelo TensorFlow.

A extensão Node.js no momento da gravação ainda não suportava solicitações HTTP para recuperação de modelo dinâmico. Tudo o que restava era carregar manualmente os modelos no sistema de arquivos.

No entanto, depois de ler o código fonte da biblioteca, encontrei uma solução alternativa ...

Fazendo Download de Modelos do Sistema de Arquivos

Se a classe MobileNet for criada manualmente, não será possível chamar o método de load do módulo, mas reescrever o path variável gerado automaticamente path contém o endereço HTTP do modelo, substituindo esse endereço pelo caminho local no sistema de arquivos. Depois disso, quando o método load for chamado na instância da classe, a classe loader do sistema de arquivos será acionada; nesse caso, nos recusamos a usar um downloader HTTP baseado em navegador.

 const path = "mobilenet/model.json" const mn = new mobilenet.MobileNet(1, 1); mn.path = `file://${path}` await mn.load() 

Legal, tudo funciona!

Mas de onde vêm os arquivos de modelo?

Modelos MobileNet

Modelos para TensorFlow.js consistem em dois tipos de arquivos: um arquivo de configuração de modelo armazenado no formato JSON e os pesos do modelo armazenados no formato binário. Os pesos do modelo geralmente são fragmentados em várias partes para otimizar o cache do navegador.

Tendo considerado o código de download automático dos modelos MobileNet, vemos que os modelos, suas configurações e fragmentos de peso são extraídos do contêiner público no seguinte endereço.

 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v${version}_${alpha}_${size}/ 

Os parâmetros do modelo na URL descrevem as versões do modelo listadas aqui . A precisão da classificação resultante também é exibida na mesma página.

O código fonte indica que apenas os modelos do MobileNet v1 podem ser baixados usando a tensorflow-models/mobilenet .

O código de extração HTTP baixa o arquivo model.json do local de armazenamento e, em seguida, seleciona recursivamente todos os fragmentos de modelos com pesos referenciados. Esses são arquivos no formato groupX-shard1of1 .

Download manual de modelos

Se desejar salvar todos os arquivos de modelo no sistema de arquivos, faça o seguinte: extraia o arquivo de configuração do modelo, analise a sintaxe de todos os arquivos ponderados mencionados no arquivo de configuração e faça o download manual de cada arquivo ponderado.
Eu usaria o módulo MobileNet V1 com um valor alfa de 1,0 e uma imagem de 224 pixels . Então, recebo o seguinte URL para o arquivo de configuração do modelo.

 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/model.json 

Depois que o arquivo é baixado localmente, você pode usar a ferramenta jq para analisar os nomes de todos os arquivos ponderados.

 $ cat model.json | jq -r ".weightsManifest[].paths[0]" group1-shard1of1 group2-shard1of1 group3-shard1of1 ... 

Usando a ferramenta sed , você pode prefixar o nome de cada elemento HTTP com uma URL para gerar uma URL para cada arquivo de peso.

 $ cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group1-shard1of1 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group2-shard1of1 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group3-shard1of1 ... 

Os comandos parallel e curl permitem baixar todos esses arquivos no meu diretório local.

 cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' | parallel curl -O 

Classificação da imagem

Este código de exemplo fornecido com o TensorFlow.js demonstra como retornar o resultado da classificação da imagem.

 const img = document.getElementById('img'); //   const predictions = await model.classify(img); 

Isso não funciona no Node.js devido à falta de suporte do DOM.

O método classify aceita vários elementos DOM ( canvas , video , image ) e extrai e converte automaticamente os bytes "de imagem" desses elementos na classe tf.Tensor3D , usada como entrada de modelo. Como alternativa, a tf.Tensor3D pode ser transmitida diretamente.

Decidi não tentar usar um pacote externo para simular um elemento DOM manualmente, mas achei que tf.Tensor3D mais fácil de montar manualmente .

Geramos Tensor3D a partir da imagem

Lendo o código fonte do método usado para converter elementos DOM em classes Tensor3D, descobrimos que os seguintes parâmetros de entrada são usados ​​para gerar a classe Tensor3D.

 const values = new Int32Array(image.height * image.width * numChannels); //     ,    const outShape = [image.height, image.width, numChannels]; const input = tf.tensor3d(values, outShape, 'int32'); 

pixels é uma matriz bidimensional do tipo (Int32Array) contém uma lista seqüencial de valores de canal para cada pixel. numChannels é o número de valores de canal por pixel.

Criando valores de entrada para JPEG

A biblioteca jpeg-js é um codificador / decodificador JPEG para Node.js escrito em JavaScript puro. Usando esta biblioteca, você pode extrair valores RGB para cada pixel.

 const pixels = jpeg.decode(buffer, true); 

Como resultado, obtemos um Uint8Array com quatro valores de canal ( RGBA ) para cada pixel ( width * height ). O modelo MobileNet usa apenas três canais de cores ( RGB ) para classificação, o canal alfa é ignorado. Esse código converte uma matriz de quatro canais em uma versão verdadeira de três canais.

  const numChannels = 3; const numPixels = image.width * image.height; const values = new Int32Array(numPixels * numChannels); for (let i = 0; i < numPixels; i++) { for (let channel = 0; channel < numChannels; ++channel) { values[i * numChannels + channel] = pixels[i * 4 + channel]; } } 

Requisitos de entrada para modelos MobileNet

O modelo MobileNet usado aqui classifica imagens de 224 pixels de altura e largura. Os tensores de entrada devem conter valores de ponto flutuante no intervalo de -1 a 1 para cada um dos três valores de canal de cada pixel.

Os valores de entrada para imagens com uma dimensão diferente devem ser convertidos no tamanho correto antes da classificação. Além disso, os valores de pixel obtidos do decodificador JPEG estão no intervalo de 0 a 255, e não de -1 a 1. Esses valores também precisam ser convertidos antes da classificação.

O TensorFlow.js possui métodos de biblioteca para simplificar esse processo, mas, melhor ainda, existe uma tfjs-models/mobilenet que resolve automaticamente esse problema !

O desenvolvedor pode transmitir Tensor3Ds de entrada do tipo int32 , bem como várias dimensões para o método classify , que converte os valores de entrada no formato correto antes da classificação. Ou seja, não temos nada a fazer aqui. Ótimo!

Obtendo previsões

Os modelos MobileNet da Tensorflow aprendem a reconhecer objetos das 1000 classes mais importantes do conjunto de dados do ImageNet . Na saída do modelo, forneça valores probabilísticos caracterizando quais são as chances de encontrar esses objetos na imagem classificada.

Uma lista completa de classes treinadas para o modelo usado está neste arquivo .

A tfjs-models/mobilenet oferece o método classify na classe MobileNet , que retorna o top-X das classes mais prováveis, com base no que é mostrado na figura.

 const predictions = await mn_model.classify(input, 10); 

predictions é uma matriz de X classes e probabilidades no seguinte formato.

  { className: 'panda', probability: 0.9993536472320557 } 

Exemplo

Então, descobrimos como usar a biblioteca TensorFlow.js e os modelos MobileNet no Node.js, e agora vamos ver como esse script classifica a imagem especificada como um argumento da linha de comando.

Código fonte

Salve este arquivo de script e o descritor de pacotes nos arquivos locais.

 { "name": "tf-js", "version": "1.0.0", "main": "script.js", "license": "MIT", "dependencies": { "@tensorflow-models/mobilenet": "^0.2.2", "@tensorflow/tfjs": "^0.12.3", "@tensorflow/tfjs-node": "^0.1.9", "jpeg-js": "^0.3.4" } } 

 const tf = require('@tensorflow/tfjs') const mobilenet = require('@tensorflow-models/mobilenet'); require('@tensorflow/tfjs-node') const fs = require('fs'); const jpeg = require('jpeg-js'); const NUMBER_OF_CHANNELS = 3 const readImage = path => { const buf = fs.readFileSync(path) const pixels = jpeg.decode(buf, true) return pixels } const imageByteArray = (image, numChannels) => { const pixels = image.data const numPixels = image.width * image.height; const values = new Int32Array(numPixels * numChannels); for (let i = 0; i < numPixels; i++) { for (let channel = 0; channel < numChannels; ++channel) { values[i * numChannels + channel] = pixels[i * 4 + channel]; } } return values } const imageToInput = (image, numChannels) => { const values = imageByteArray(image, numChannels) const outShape = [image.height, image.width, numChannels]; const input = tf.tensor3d(values, outShape, 'int32'); return input } const loadModel = async path => { const mn = new mobilenet.MobileNet(1, 1); mn.path = `file://${path}` await mn.load() return mn } const classify = async (model, path) => { const image = readImage(path) const input = imageToInput(image, NUMBER_OF_CHANNELS) const mn_model = await loadModel(model) const predictions = await mn_model.classify(input) console.log('classification results:', predictions) } if (process.argv.length !== 4) throw new Error('incorrect arguments: node script.js <MODEL> <IMAGE_FILE>') classify(process.argv[2], process.argv[3]) 

Teste

Faça o download dos arquivos de modelo para o diretório mobilenet seguindo as instruções acima.
Definir dependências do projeto usando o NPM

npm install

Faça o download do arquivo JPEG de amostra para classificação

wget http://bit.ly/2JYSal9 -O panda.jpg



Execute o script, cujos argumentos serão o arquivo de modelo e a imagem de entrada.

node script.js mobilenet/model.json panda.jpg

Se tudo funcionou corretamente, a seguinte saída deve aparecer no console.

  classification results: [ { className: 'giant panda, panda, panda bear, coon bear', probability: 0.9993536472320557 } ] 

A imagem está corretamente classificada como contendo um panda com uma probabilidade de 99,93%!

Conclusão

A biblioteca TensorFlow.js abre oportunidades profundas de aprendizado para desenvolvedores de JavaScript. O uso de modelos pré-treinados com a biblioteca TensorFlow.js permite criar facilmente em aplicativos JavaScript novos recursos para resolver problemas complexos de aprendizado de máquina, com esforço mínimo e código conciso.

A biblioteca TensorFlow.js foi criada exclusivamente para trabalhar em um navegador, mas agora interage com o Node.js, embora nem todas as ferramentas e utilitários suportem esse novo tempo de execução. Tendo mexido com a biblioteca por vários dias, aprendi a usá-la com os modelos MobileNet para reconhecimento visual de imagens de um arquivo local.

Source: https://habr.com/ru/post/pt432984/


All Articles