JavaScript e Machine Learning: TensorFlow.js Está Democratizando a IA
Olá HaWkers, imagine treinar um modelo de Machine Learning e executá-lo diretamente no navegador, sem backend Python, sem servidores pesados. Parece futurista? É realidade com TensorFlow.js.
Você, desenvolvedor JavaScript, agora tem acesso a capacidades de IA que antes eram exclusivas de cientistas de dados. Vamos explorar como isso funciona, casos de uso reais e código prático que você pode rodar hoje.
Por Que Machine Learning no Navegador?
Vantagens do TensorFlow.js:
- Privacidade: Dados nunca saem do dispositivo do usuário
- Latência zero: Sem roundtrip para servidor
- Custo: Processamento distribuído nos clientes (não seu servidor)
- Acessibilidade: Qualquer dev JavaScript pode começar
- Multiplataforma: Browser, Node.js, React Native, Electron
Casos de uso reais em 2025:
- Filtros de câmera em tempo real (Instagram, Snapchat)
- Transcrição de áudio offline (Zoom, Meet)
- Detecção de fraude em pagamentos
- Recomendações personalizadas sem enviar dados
- Acessibilidade (legendas, tradução em tempo real)
Setup Básico: Seu Primeiro Modelo
Vamos criar um detector de sentimento de texto — classifica se uma frase é positiva ou negativa.
Instalação:
npm install @tensorflow/tfjs
# Ou via CDN:
# <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>Modelo pré-treinado simples:
import * as tf from '@tensorflow/tfjs';
// 1. Criar modelo sequencial simples
const model = tf.sequential({
layers: [
// Input: Texto convertido em números (embedding)
tf.layers.dense({ inputShape: [100], units: 16, activation: 'relu' }),
// Hidden layer
tf.layers.dense({ units: 8, activation: 'relu' }),
// Output: 2 classes (positivo/negativo)
tf.layers.dense({ units: 2, activation: 'softmax' })
]
});
// 2. Compilar modelo
model.compile({
optimizer: tf.train.adam(0.001),
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});
// 3. Treinar com dados
async function trainModel(reviews, labels) {
// reviews: array de textos
// labels: array de [0, 1] ou [1, 0]
const xs = tf.tensor2d(reviews);
const ys = tf.tensor2d(labels);
await model.fit(xs, ys, {
epochs: 50,
batchSize: 32,
validationSplit: 0.2,
callbacks: {
onEpochEnd: (epoch, logs) => {
console.log(`Epoch ${epoch}: loss = ${logs.loss.toFixed(4)}`);
}
}
});
console.log('✓ Modelo treinado!');
}
// 4. Fazer predições
function predict(text) {
// Converter texto em vetor numérico (simplificado)
const vector = textToVector(text);
const input = tf.tensor2d([vector]);
const prediction = model.predict(input);
const scores = prediction.dataSync();
return {
positive: scores[0],
negative: scores[1],
sentiment: scores[0] > scores[1] ? 'Positivo' : 'Negativo'
};
}
// Exemplo de uso
const result = predict('Adorei este produto, muito bom!');
console.log(result);
// { positive: 0.89, negative: 0.11, sentiment: 'Positivo' }
Caso Prático: Reconhecimento de Imagens em Tempo Real
Vamos usar um modelo pré-treinado (MobileNet) para classificar imagens da webcam.
import * as tf from '@tensorflow/tfjs';
import * as mobilenet from '@tensorflow-models/mobilenet';
class ImageClassifier {
constructor() {
this.model = null;
this.video = null;
}
async init() {
// 1. Carregar modelo (download automático)
console.log('Carregando MobileNet...');
this.model = await mobilenet.load();
console.log('✓ Modelo carregado!');
// 2. Configurar webcam
this.video = document.getElementById('webcam');
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: 640, height: 480 }
});
this.video.srcObject = stream;
await new Promise(resolve => {
this.video.onloadedmetadata = resolve;
});
this.video.play();
}
async classify() {
if (!this.model || !this.video) return;
// 3. Fazer predição em tempo real
const predictions = await this.model.classify(this.video);
return predictions.map(p => ({
class: p.className,
probability: (p.probability * 100).toFixed(2) + '%'
}));
}
async classifyLoop() {
const resultsDiv = document.getElementById('results');
setInterval(async () => {
const predictions = await this.classify();
resultsDiv.innerHTML = predictions
.map(p => `<p>${p.class}: ${p.probability}</p>`)
.join('');
}, 1000); // Classifica a cada 1 segundo
}
}
// HTML correspondente
/*
<video id="webcam" autoplay></video>
<div id="results"></div>
<script>
const classifier = new ImageClassifier();
classifier.init().then(() => {
classifier.classifyLoop();
});
</script>
*/Resultado: Aplicação identifica objetos na câmera sem enviar dados para servidor!
Transfer Learning: Treinando Seu Próprio Classificador
E se você quiser classificar coisas específicas? Use Transfer Learning — pegue modelo pré-treinado e ajuste para seu caso.
Exemplo: Classificador de poses (exercícios físicos)
import * as tf from '@tensorflow/tfjs';
import * as mobilenet from '@tensorflow-models/mobilenet';
class PoseClassifier {
constructor() {
this.baseModel = null;
this.model = null;
this.classes = ['agachamento', 'flexao', 'prancha', 'pulo'];
}
async loadBaseModel() {
// Carregar MobileNet sem a última camada
const mobilenet = await tf.loadLayersModel(
'https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_0.25_224/model.json'
);
// Remover última camada (classificação genérica)
const layer = mobilenet.getLayer('conv_pw_13_relu');
this.baseModel = tf.model({
inputs: mobilenet.inputs,
outputs: layer.output
});
}
createCustomModel() {
// Adicionar novas camadas para suas classes
const model = tf.sequential({
layers: [
tf.layers.flatten({
inputShape: this.baseModel.outputs[0].shape.slice(1)
}),
tf.layers.dense({
units: 128,
activation: 'relu',
kernelInitializer: 'varianceScaling'
}),
tf.layers.dropout({ rate: 0.5 }),
tf.layers.dense({
units: this.classes.length,
activation: 'softmax'
})
]
});
model.compile({
optimizer: tf.train.adam(0.0001),
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});
this.model = model;
}
async train(images, labels) {
// images: array de elementos <img>
// labels: array de índices [0, 1, 2, 3]
// Extrair features com modelo base
const features = tf.tidy(() => {
const imageTensors = images.map(img => {
return tf.browser.fromPixels(img)
.resizeBilinear([224, 224])
.toFloat()
.div(127.5)
.sub(1);
});
const batched = tf.stack(imageTensors);
return this.baseModel.predict(batched);
});
// Converter labels para one-hot
const ys = tf.oneHot(tf.tensor1d(labels, 'int32'), this.classes.length);
// Treinar apenas as novas camadas
await this.model.fit(features, ys, {
epochs: 20,
batchSize: 32,
validationSplit: 0.2,
callbacks: {
onEpochEnd: (epoch, logs) => {
console.log(
`Epoch ${epoch + 1}: ` +
`loss = ${logs.loss.toFixed(4)}, ` +
`accuracy = ${logs.acc.toFixed(4)}`
);
}
}
});
features.dispose();
ys.dispose();
}
async predict(imageElement) {
const processed = tf.tidy(() => {
const img = tf.browser.fromPixels(imageElement)
.resizeBilinear([224, 224])
.toFloat()
.div(127.5)
.sub(1)
.expandDims(0);
const features = this.baseModel.predict(img);
return this.model.predict(features);
});
const probabilities = await processed.data();
const classIndex = processed.argMax(-1).dataSync()[0];
processed.dispose();
return {
class: this.classes[classIndex],
confidence: (probabilities[classIndex] * 100).toFixed(2) + '%',
allProbabilities: this.classes.map((name, i) => ({
name,
probability: (probabilities[i] * 100).toFixed(2) + '%'
}))
};
}
}
// Uso
const classifier = new PoseClassifier();
await classifier.loadBaseModel();
classifier.createCustomModel();
// Coletar dados (tirar fotos de cada exercício)
const agachamentoImgs = [img1, img2, img3]; // 3 exemplos
const flexaoImgs = [img4, img5, img6];
// ... mais exemplos
const allImages = [...agachamentoImgs, ...flexaoImgs, ...];
const labels = [0, 0, 0, 1, 1, 1, ...]; // Índices das classes
await classifier.train(allImages, labels);
// Fazer predição em nova imagem
const result = await classifier.predict(newImageElement);
console.log(result);
// {
// class: 'agachamento',
// confidence: '94.32%',
// allProbabilities: [...]
// }
Performance: Aceleração GPU
TensorFlow.js usa WebGL para computação na GPU — crucial para modelos grandes.
Otimizações importantes:
// 1. Usar tf.tidy() para gerenciar memória
function processData(input) {
return tf.tidy(() => {
// Todos os tensors criados aqui são liberados automaticamente
const normalized = input.div(255);
const reshaped = normalized.reshape([1, 224, 224, 3]);
return model.predict(reshaped);
});
}
// 2. Batch processing para múltiplas imagens
async function classifyMultiple(images) {
const batch = tf.tidy(() => {
const tensors = images.map(img =>
tf.browser.fromPixels(img).resizeBilinear([224, 224])
);
return tf.stack(tensors);
});
const predictions = await model.predict(batch).array();
batch.dispose();
return predictions;
}
// 3. Quantização para modelos menores
async function loadQuantizedModel() {
// Modelo com 4x menos peso
const model = await tf.loadGraphModel(
'https://example.com/model_quantized/model.json'
);
return model;
}
// 4. Web Workers para não bloquear UI
// worker.js
importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs');
self.onmessage = async (e) => {
const { imageData } = e.data;
const tensor = tf.browser.fromPixels(imageData);
const prediction = await model.predict(tensor);
self.postMessage({ prediction: await prediction.array() });
tensor.dispose();
prediction.dispose();
};Casos de Uso Avançados
1. Detecção de Poses (PoseNet):
import * as posenet from '@tensorflow-models/posenet';
const net = await posenet.load({
architecture: 'MobileNetV1',
outputStride: 16,
inputResolution: { width: 640, height: 480 },
multiplier: 0.75
});
const pose = await net.estimateSinglePose(video);
// pose.keypoints contém 17 pontos (nariz, olhos, ombros, etc)
const nose = pose.keypoints.find(kp => kp.part === 'nose');
console.log(`Nariz em: x=${nose.position.x}, y=${nose.position.y}`);2. Segmentação de Pessoas (BodyPix):
import * as bodyPix from '@tensorflow-models/body-pix';
const net = await bodyPix.load();
const segmentation = await net.segmentPerson(video);
// Aplicar blur no fundo (tipo Zoom)
const foregroundColor = { r: 0, g: 0, b: 0, a: 0 };
const backgroundColor = { r: 0, g: 0, b: 0, a: 255 };
const backgroundBlurAmount = 15;
const backgroundBlur = await bodyPix.blurBodyPart(
canvas,
video,
segmentation,
backgroundBlurAmount,
foregroundColor,
backgroundColor
);3. Reconhecimento de Fala:
import * as speechCommands from '@tensorflow-models/speech-commands';
const recognizer = speechCommands.create('BROWSER_FFT');
await recognizer.ensureModelLoaded();
// Escutar comandos
recognizer.listen(result => {
const scores = result.scores;
const maxScore = Math.max(...scores);
const command = recognizer.wordLabels()[scores.indexOf(maxScore)];
console.log(`Comando detectado: ${command} (${(maxScore * 100).toFixed(2)}%)`);
}, {
includeSpectrogram: true,
probabilityThreshold: 0.75
});
Limitações e Considerações
O que TensorFlow.js NÃO é ideal para:
- Treinamento de modelos gigantes (GPT, DALL-E)
- Processamento batch massivo (milhões de imagens)
- Pesquisa de ML de ponta
Ideal para:
- Inferência em tempo real no cliente
- Modelos pequenos/médios (<50MB)
- Protótipos rápidos
- Aplicações que precisam de privacidade
Trade-offs:
- Performance: ~2-5x mais lento que Python/C++ nativo
- Tamanho: Modelos precisam ser leves para web
- Compatibilidade: Nem todas APIs Python estão disponíveis
O Futuro do ML no JavaScript
Tendências 2025:
- WebGPU para performance ainda melhor
- Modelos cada vez menores (técnicas de compressão)
- Edge computing (ML em IoT devices com JS)
- Integração com frameworks (React, Vue components com ML)
Se você quer explorar mais sobre como JavaScript está se expandindo para áreas inovadoras, veja JavaScript e o Mundo do IoT: Integrando a Web ao Ambiente Físico.
Bora pra cima! 🦅
📚 Quer Aprofundar Seus Conhecimentos em JavaScript?
Este artigo cobriu Machine Learning com JavaScript, mas há muito mais para explorar no mundo do desenvolvimento moderno.
Desenvolvedores que investem em conhecimento sólido e estruturado tendem a ter mais oportunidades no mercado.
Material de Estudo Completo
Se você quer dominar JavaScript do básico ao avançado, preparei um guia completo:
Opções de investimento:
- R$9,90 (pagamento único)
💡 Material atualizado com as melhores práticas do mercado

