Testes de modelos de IA da Web no Google Colab

François Beaufort
François Beaufort

Configurar um ambiente de teste consistente com GPUs pode ser mais difícil do que o esperado. Estas são as etapas para testar modelos de IA do lado do cliente baseados no navegador em ambientes reais de navegador, além de serem escalonáveis, automatizáveis e dentro de uma configuração de hardware padronizada conhecida.

Nesse caso, o navegador é um navegador Chrome real com suporte a hardware, e não à emulação de software.

Se você é um desenvolvedor de IA da Web, jogos na Web ou gráficos ou tem interesse em testes de modelos de IA da Web, este guia é para você.

Etapa 1: criar um bloco do Google Colab

1. Acesse colab.new para criar um novo bloco do Colab. Deve ser semelhante à figura 1. 2. Siga as instruções para fazer login na sua Conta do Google.
Captura de tela de um novo Colab
Figura 1: um novo bloco do Colab.

Etapa 2: conectar-se a um servidor ativado para GPU T4

  1. Clique em Conectar perto do canto superior direito do notebook.
  2. Selecione Alterar o tipo de ambiente de execução:
    Uma captura de tela em primeiro plano que mostra as etapas para mudar o ambiente de execução.
    Figura 2. Altere o ambiente de execução na interface do Colab.
  3. Na janela modal, selecione GPU T4 como seu acelerador de hardware. Quando você se conectar, o Colab vai usar uma instância do Linux com uma GPU NVIDIA T4 anexada.
    Captura de tela do módulo "Alterar o tipo de ambiente de execução".
    Figura 3: em "Acelerador de hardware", selecione GPU T4.
  4. Clique em Salvar.
  5. Clique no botão Conectar para se conectar ao ambiente de execução. Depois de um tempo, o botão vai mostrar uma marca de seleção verde, assim como gráficos de uso de RAM e disco. Isso indica que um servidor foi criado com o hardware necessário.

Bom trabalho. Você acabou de criar um servidor com uma GPU anexada.

Etapa 3: instalar drivers e dependências corretos

  1. Copie e cole as duas linhas de código a seguir na primeira célula de código do notebook. Em um ambiente do Colab, a execução da linha de comando é precedida por um ponto de exclamação.

    !git clone https://github.com/jasonmayes/headless-chrome-nvidia-t4-gpu-support.git
    !cd headless-chrome-nvidia-t4-gpu-support && chmod +x scriptyMcScriptFace.sh && ./scriptyMcScriptFace.sh
    
    # Update, install correct drivers, and remove the old ones.
    apt-get install -y vulkan-tools libnvidia-gl-525
    
    # Verify NVIDIA drivers can see the T4 GPU and that vulkan is working correctly.
    nvidia-smi
    vulkaninfo --summary
    
    # Now install latest version of Node.js
    npm install -g n
    n lts
    node --version
    npm --version
    
    # Next install Chrome stable
    curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/googlechrom-keyring.gpg
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrom-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list
    sudo apt update
    sudo apt install -y google-chrome-stable
    
    # Start dbus to avoid warnings by Chrome later.
    export DBUS_SESSION_BUS_ADDRESS="unix:path=/var/run/dbus/system_bus_socket"
    /etc/init.d/dbus start
    
  2. Clique em ao lado da célula para executar o código.

    Captura de tela de um novo Colab
    Figura 4.

  3. Quando o código terminar a execução, verifique se nvidia-smi imprimiu algo semelhante à captura de tela a seguir para confirmar se você realmente tem uma GPU anexada e ela foi reconhecida no seu servidor. Talvez seja necessário rolar para uma parte anterior dos registros para ver essa saída.

    Figura 5: procure a saída que começa com "NVIDIA-SMI".

Etapa 4: usar e automatizar a versão headless do Chrome

  1. Clique no botão Código para adicionar uma nova célula de código.
  2. Em seguida, escreva o código personalizado para chamar um projeto Node.js com seus parâmetros preferidos (ou apenas chame google-chrome-stable diretamente na linha de comando). Temos exemplos para os dois casos a seguir.

Parte A: usar a Headless Chrome diretamente na linha de comando

# Directly call Chrome to dump a PDF of WebGPU testing page
# and store it in /content/gpu.pdf
!google-chrome-stable \
--no-sandbox \
--headless=new \
--use-angle=vulkan \
--enable-features=Vulkan \
--disable-vulkan-surface \
--enable-unsafe-webgpu \
--print-to-pdf=/content/gpu.pdf https://webgpureport.org

No exemplo, armazenamos a captura de PDF resultante em /content/gpu.pdf. Para visualizar esse arquivo, expanda o conteúdo . Em seguida, clique em para fazer o download do arquivo PDF para sua máquina local.

Captura de tela de um novo Colab
Figura 6: veja as etapas para fazer o download do PDF nesta captura de tela da interface do Colab.

Parte B: Comando o Chrome com o Puppeteer

Fornecemos um exemplo minimalista que usa o Puppeteer para controlar o Headless Chrome (em inglês), que pode ser executado da seguinte maneira:

# Call example node.js project to perform any task you want by passing
# a URL as a parameter
!node headless-chrome-nvidia-t4-gpu-support/examples/puppeteer/jPuppet.js chrome://gpu

No exemplo do jPuppet, é possível chamar um script em Node.js para criar uma captura de tela. Mas como isso funciona? Confira esta apresentação do código Node.js em jPuppet.js.

Detalhamento do código do nó jPuppet.js

Primeiro, importe o Puppeteer. Isso permite controlar remotamente o Chrome com Node.js:

import puppeteer from 'puppeteer';

Em seguida, verifique quais argumentos de linha de comando foram passados para o aplicativo Node. Verifique se o terceiro argumento está definido, que representa um URL para navegar. Você precisa inspecionar o terceiro argumento aqui, porque os dois primeiros argumentos chamam o próprio Node e o script que estamos executando. Na verdade, o terceiro elemento contém o 1o parâmetro transmitido ao programa Node:

const url = process.argv[2];
if (!url) {
  throw "Please provide a URL as the first argument";
}

Agora defina uma função assíncrona com o nome runWebpage(). Isso cria um objeto de navegador que é configurado com os argumentos de linha de comando para executar o binário do Chrome da maneira necessária para que a WebGL e a WebGPU funcionem, conforme descrito em Ativar suporte a WebGPU e WebGL.

async function runWebpage() {
  const browser = await puppeteer.launch({
    headless: 'new',
    args:  [
        '--no-sandbox',
        '--headless=new',
        '--use-angle=vulkan',
        '--enable-features=Vulkan',
        '--disable-vulkan-surface',
        '--enable-unsafe-webgpu'
      ]
  });

Crie um novo objeto de página do navegador que você pode usar mais tarde para visitar qualquer URL:

const page = await browser.newPage();

Em seguida, adicione um listener de eventos para detectar eventos console.log quando a página da Web executar o JavaScript. Isso permite registrar mensagens na linha de comando do Node e também inspecionar o texto do console em busca de uma frase especial (neste caso, captureAndEnd) que aciona uma captura de tela e encerra o processo do navegador no Node. Isso é útil para páginas da Web que precisam realizar um certo trabalho antes de fazer uma captura de tela e tem um tempo de execução não determinístico.

page.on('console', async function(msg) {
  console.log(msg.text());
  if (msg.text() === 'captureAndEnd') {
    await page.screenshot({ path: '/content/screenshotEnd.png' });
    await browser.close();
  }
});

Por fim, comande a página para que visite o URL especificado e faça uma captura de tela inicial quando a página for carregada.

Se você fizer uma captura de tela de chrome://gpu, feche a sessão do navegador imediatamente em vez de esperar qualquer saída do console, já que essa página não é controlada pelo seu código.

  await page.goto(url,  { waitUntil: 'networkidle2' });
  await page.screenshot({path: '/content/screenshot.png'});
  if (url === 'chrome://gpu') {
    await browser.close();
  }
}
runWebpage();

Modificar o package.json

Você deve ter notado que usamos uma instrução de importação no início do arquivo jPuppet.js. Seu package.json precisa definir os valores de tipo como module. Caso contrário, você receberá um erro informando que o módulo é inválido.

 {
    "dependencies":  {
      "puppeteer": "*"
    },
    "name": "content",
    "version": "1.0.0",
    "main": "jPuppet.js",
    "devDependencies": {},
    "keywords": [],
    "type": "module",
    "description": "Node.js Puppeteer application to interface with headless Chrome with GPU support to capture screenshots and get console output from target webpage"
}

Isso é tudo. Com o Puppeteer, fica mais fácil interagir com o Chrome de maneira programática.

Concluído

Agora, podemos verificar se o classificador MNIST do TensorFlow.js Fashion consegue reconhecer corretamente um par de calças em uma imagem, com processamento do lado do cliente no navegador usando a GPU.

É possível usar isso para qualquer carga de trabalho baseada em GPU do lado do cliente, de modelos de machine learning a testes de gráficos e jogos.

Captura de tela de um novo Colab
Figura 7: uma captura bem-sucedida de um modelo acelerado por GPU do TensorFlow.js capaz de reconhecer o lado do cliente de vestuário no navegador em tempo real.

Recursos

Adicione uma estrela ao repositório do GitHub para receber atualizações futuras.