Recentemente Fritz Heartbeat publicou um artigo do Aayush Arora que mostra como a biblioteca TensorFlow.js do Google pode ser aproveitada no navegador para ensinar o computador a jogar o jogo do Chrome T-Rex Game.
O Chrome Dinosaur Game (chamado às vezes de T-Rex Game) surgiu cinco anos atrás no navegador Google Chrome, quando um usuário tentava visitar um site desconectado da Internet. O Chrome Dinosaur Game é um simples jogo de corrida infinita, na qual um jogador tem que pular sobre os cactos e evitar os obstáculos. Os controles são básicos: pressionar a barra de espaço para dar um salto, e a seta para baixo, para mergulhar. O objetivo é sobreviver o maior tempo possível, e um temporizador marca quanto tempo o jogador conseguiu se livrar dos obstáculos:
Um conjunto de características escolhida, dada a natureza do jogo, é a velocidade do jogo, a largura do obstáculo e a distância do obstáculo que se aproxima em relação ao T-Rex. O computador aprenderá a mapear essas três variáveis para saídas, das quais uma de duas decisões pode ser tomada: saltar ou não saltar (note que a versão original do jogo também permite que o dinossauro se agache, o que não é modelado aqui na lista de decisão). O computador aprenderá por tentativa e erro, reunindo os dados de treinamento toda vez que ele falhar no jogo e reiniciando o jogo com a experiência acumulada.
O Tensorflow.js é usado como uma biblioteca de aprendizado de máquina. Os tutoriais do TensorFlow identificam as seguintes etapas para uma implementação de aprendizado de máquina:
- Carregar, formatar e visualizar os dados de entrada
- Definir o modelo da arquitetura
- Preparar os dados para o treinamento
- Treinar o modelo
- Fazer previsões
Neste exemplo em particular, começamos o treinamento sem dados, então o primeiro passo é vazio. Para o segundo passo, o Arora utiliza uma rede neural, baseada em um modelo sequencial, com uma camada de entrada e saída, ambas com uma função de ativação sigmoide. A primeira camada inclui as três variáveis preditivas mencionadas anteriormente: velocidade do jogo, largura do obstáculo que se aproxima e distancia do T-Rex. A primeira camada calcula seis unidades que servem como entrada para a segunda e última camada. A camada final tem duas saídas, cujos valores correspondem respectivamente à probabilidade de saltar ou não saltar:
import * as tf from '@tensorflow/tfjs';
dino.model = tf.sequential();
dino.model.add(tf.layers.dense({
inputShape:[3],
activation:'sigmoid',
units:6
}))
dino.model.add(tf.layers.dense({
inputShape:[6],
activation:'sigmoid',
units:2
}))
A terceira etapa envolve a conversão de dados de entrada em tensores que o TensorFlow.js pode manipular:
dino.model.fit(
tf.tensor2d(dino.training.inputs),
tf.tensor2d(dino.training.labels)
);
Nenhum embaralhamento é implementado na terceira etapa, à medida que incrementamos as entradas em um conjunto de treinamento inicialmente vazio, e cada vez que o computador erra no jogo. A normalização é realizada aqui tendo os valores de saída no conjunto de treinamento entre 0 e 1. Na verdade, quando o T-Rex erra ao evitar um obstáculo, a entrada correspondente triplo (velocidade do jogo, largura do obstáculo que se aproxima e distancia do T-Rex) é mapeado para [1, 0]
ou [0, 1]
, que codifica as saídas da segunda camada. Se o T-Rex estivesse saltando e não conseguisse escapar do obstáculo, a decisão apropriada era não pular: [1, 0]
. Por outro lado, se o T-Rex não estava pulando e encontrando um obstáculo, a decisão apropriada era pular: [0, 1]
.
Como uma quarta etapa, quando os dados de treinamento são disponibilizados, é treinado um modelo com uma função de perda meanSquaredError
e a otimização de Adam com uma taxa de aprendizado de 0,1 (a otimização de Adam é bastante eficaz na prática e não requer configuração):
dino.model.compile({
loss:'meanSquaredError',
optimizer: tf.train.adam(0.1)
})
O quinto passo ocorre durante uma repetição do jogo: à medida que o jogo avança, novos valores do triplo de entrada são computados, previsões são executadas e decisões de salto/não salto são tomadas, quando faz sentido tomá-las (por exemplo, quando o T-Rex não está ocupado pulando):
if (!dino.jumping) {
// Sempre que o dino não estiver pulando, decida se ele precisa ou não pular
let action = 0;// Variável 1 para saltar e 0 para não
// chame o model.predict no vetor de estado depois de convertê-lo em objeto de tensor2d
const prediction = dino.model.predict(tf.tensor2d([convertStateToVector(state)]));
// com a função de previsão obtemos uma promessa de resultado do tensor
// e baseado no resultado decide a ação
const predictionPromise = prediction.data();
predictionPromise.then((result) => {
// convertendo previsão em ação
if (result[1] > result[0]) {
// queremos pular
action = 1;
// definir o último estado de salto para o estado atual
dino.lastJumpingState = state;
} else {
// definir o estado de corrida para o estado atual
dino.lastRunningState = state;
}
resolve(action);
});
O Fritz é uma plataforma de aprendizado de máquina para desenvolvedores de iOS e Android. O TensorFlow.js é um software de código aberto disponível sob a licença Apache 2.0. Contribuições e comentários são incentivados através do repositório no GitHub do TensorFlow e devem seguir as diretrizes de contribuição do TensorFlow.