Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Para obter uma introdução ao WebNN, incluindo informações sobre suporte ao sistema operacional, suporte a modelos e muito mais, visite a Visão geral do WebNN.
Este tutorial mostrará como usar o WebNN com o ONNX Runtime Web para criar um sistema de classificação de imagem na Web que é acelerado por hardware usando GPU no dispositivo. Vamos aproveitar o modelo MobileNetV2 , que é um modelo de código aberto no Hugging Face usado para classificar imagens.
Se você quiser visualizar e executar o código final deste tutorial, você pode encontrá-lo em nosso WebNN Developer Preview GitHub.
Observação
A API WebNN é uma Recomendação Candidata do W3C e está nos estágios iniciais de uma visualização para programadores. Algumas funcionalidades são limitadas. Temos uma lista do status atual de suporte e implementação.
Requisitos e configuração:
Configuração do Windows
Verifique se você tem as versões corretas do Edge, do Windows e dos drivers de hardware, conforme detalhado na seção Requisitos do WebNN.
Configurando o Edge
Baixe e instale o Microsoft Edge Dev.
Inicie o Edge Beta e navegue até a
about:flagsbarra de endereço.Procure por "WebNN API", clique na lista suspensa e defina como 'Ativado'.
Reinicie o Edge, conforme solicitado.
Configurando o ambiente do desenvolvedor
Baixe e instale o Visual Studio Code (VSCode).
Inicie o VSCode.
Transfira e instale a extensão Live Server para VSCode no VSCode.
Selecione
File --> Open Foldere crie uma pasta em branco no local desejado.
Etapa 1: inicializar o aplicativo Web
- Para começar, crie uma nova
index.htmlpágina. Adicione o seguinte código clichê à sua nova página:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Website</title>
</head>
<body>
<main>
<h1>Welcome to My Website</h1>
</main>
</body>
</html>
- Verifique se o código clichê e a configuração do desenvolvedor funcionaram selecionando o botão Go Live no canto inferior direito do VSCode. Isso deve iniciar um servidor local no Edge Beta executando o código clichê.
- Agora, crie um novo arquivo chamado
main.js. Isso conterá o código javascript para seu aplicativo. - Em seguida, crie uma subpasta fora do diretório raiz chamado
images. Transfira e guarde qualquer imagem dentro da pasta. Para esta demonstração, usaremos o nome padrão deimage.jpg. - Faça o download do modelo mobilenet do ONNX Model Zoo. Para este tutorial, você usará o arquivo mobilenet2-10.onnx . Salve este modelo na pasta raiz do seu aplicativo Web.
- Finalmente, baixe e salve este arquivo de classes de imagem,
imagenetClasses.js. Isso fornece 1000 classificações comuns de imagens para seu modelo usar.
Etapa 2: Adicionar elementos da interface de utilizador e função pai
- No corpo das tags html adicionadas
<main>na etapa anterior, substitua o código existente pelos seguintes elementos. Eles criarão um botão e exibirão uma imagem padrão.
<h1>Image Classification Demo!</h1>
<div><img src="./images/image.jpg"></div>
<button onclick="classifyImage('./images/image.jpg')" type="button">Click Me to Classify Image!</button>
<h1 id="outputText"> This image displayed is ... </h1>
- Agora, você adicionará o ONNX Runtime Web à sua página, que é uma biblioteca JavaScript que você usará para acessar a API WebNN. Dentro do corpo das
<head>tags html, adicione os seguintes links de origem javascript.
<script src="./main.js"></script>
<script src="imagenetClasses.js"></script>
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.18.0-dev.20240311-5479124834/dist/ort.webgpu.min.js"></script>
- Abra o
main.jsarquivo e adicione o seguinte trecho de código.
async function classifyImage(pathToImage){
var imageTensor = await getImageTensorFromPath(pathToImage); // Convert image to a tensor
var predictions = await runModel(imageTensor); // Run inference on the tensor
console.log(predictions); // Print predictions to console
document.getElementById("outputText").innerHTML += predictions[0].name; // Display prediction in HTML
}
Etapa 3: Pré-processar dados
- A função que acabaste de adicionar chama
getImageTensorFromPath, outra função que tens de implementar. Você irá adicioná-lo abaixo, bem como outra função assíncrona que ele chama para recuperar a própria imagem.
async function getImageTensorFromPath(path, width = 224, height = 224) {
var image = await loadImagefromPath(path, width, height); // 1. load the image
var imageTensor = imageDataToTensor(image); // 2. convert to tensor
return imageTensor; // 3. return the tensor
}
async function loadImagefromPath(path, resizedWidth, resizedHeight) {
var imageData = await Jimp.read(path).then(imageBuffer => { // Use Jimp to load the image and resize it.
return imageBuffer.resize(resizedWidth, resizedHeight);
});
return imageData.bitmap;
}
- Você também precisa adicionar a
imageDataToTensorfunção mencionada acima, que renderizará a imagem carregada em um formato tensor que funcionará com nosso modelo ONNX. Esta é uma função mais envolvida, embora possa parecer familiar se você já trabalhou com aplicativos de classificação de imagem semelhantes antes. Para uma explicação detalhada, você pode ver este tutorial ONNX.
function imageDataToTensor(image) {
var imageBufferData = image.data;
let pixelCount = image.width * image.height;
const float32Data = new Float32Array(3 * pixelCount); // Allocate enough space for red/green/blue channels.
// Loop through the image buffer, extracting the (R, G, B) channels, rearranging from
// packed channels to planar channels, and converting to floating point.
for (let i = 0; i < pixelCount; i++) {
float32Data[pixelCount * 0 + i] = imageBufferData[i * 4 + 0] / 255.0; // Red
float32Data[pixelCount * 1 + i] = imageBufferData[i * 4 + 1] / 255.0; // Green
float32Data[pixelCount * 2 + i] = imageBufferData[i * 4 + 2] / 255.0; // Blue
// Skip the unused alpha channel: imageBufferData[i * 4 + 3].
}
let dimensions = [1, 3, image.height, image.width];
const inputTensor = new ort.Tensor("float32", float32Data, dimensions);
return inputTensor;
}
Etapa 4: Chamar o ONNX Runtime Web
- Agora você adicionou todas as funções necessárias para recuperar sua imagem e renderizá-la como um tensor. Agora, usando a biblioteca da Web ONNX Runtime que você carregou acima, você executará seu modelo. Observe que para usar o WebNN aqui, basta especificar
executionProvider = "webnn"- o suporte do ONNX Runtime torna muito simples habilitar o WebNN.
async function runModel(preprocessedData) {
// Set up environment.
ort.env.wasm.numThreads = 1;
ort.env.wasm.simd = true;
// Uncomment for additional information in debug builds:
// ort.env.wasm.proxy = true;
// ort.env.logLevel = "verbose";
// ort.env.debug = true;
// Configure WebNN.
const modelPath = "./mobilenetv2-10.onnx";
const devicePreference = "gpu"; // Other options include "npu" and "cpu".
const options = {
executionProviders: [{ name: "webnn", deviceType: devicePreference, powerPreference: "default" }],
freeDimensionOverrides: {"batch": 1, "channels": 3, "height": 224, "width": 224}
// The key names in freeDimensionOverrides should map to the real input dim names in the model.
// For example, if a model's only key is batch_size, you only need to set
// freeDimensionOverrides: {"batch_size": 1}
};
modelSession = await ort.InferenceSession.create(modelPath, options);
// Create feeds with the input name from model export and the preprocessed data.
const feeds = {};
feeds[modelSession.inputNames[0]] = preprocessedData;
// Run the session inference.
const outputData = await modelSession.run(feeds);
// Get output results with the output name from the model export.
const output = outputData[modelSession.outputNames[0]];
// Get the softmax of the output data. The softmax transforms values to be between 0 and 1.
var outputSoftmax = softmax(Array.prototype.slice.call(output.data));
// Get the top 5 results.
var results = imagenetClassesTopK(outputSoftmax, 5);
return results;
}
Etapa 5: Pós-processamento de dados
- Finalmente, você adicionará uma
softmaxfunção e, em seguida, adicionará sua função final para retornar a classificação de imagem mais provável. Osoftmaxtransforma seus valores para estar entre 0 e 1, que é a forma de probabilidade necessária para esta classificação final.
Primeiro, adicione os seguintes arquivos de origem para bibliotecas auxiliares Jimp e Lodash na tag head de main.js.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jimp/0.22.12/jimp.min.js" integrity="sha512-8xrUum7qKj8xbiUrOzDEJL5uLjpSIMxVevAM5pvBroaxJnxJGFsKaohQPmlzQP8rEoAxrAujWttTnx3AMgGIww==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
Agora, adicione estas seguintes funções ao main.js.
// The softmax transforms values to be between 0 and 1.
function softmax(resultArray) {
// Get the largest value in the array.
const largestNumber = Math.max(...resultArray);
// Apply the exponential function to each result item subtracted by the largest number, using reduction to get the
// previous result number and the current number to sum all the exponentials results.
const sumOfExp = resultArray
.map(resultItem => Math.exp(resultItem - largestNumber))
.reduce((prevNumber, currentNumber) => prevNumber + currentNumber);
// Normalize the resultArray by dividing by the sum of all exponentials.
// This normalization ensures that the sum of the components of the output vector is 1.
return resultArray.map((resultValue, index) => {
return Math.exp(resultValue - largestNumber) / sumOfExp
});
}
function imagenetClassesTopK(classProbabilities, k = 5) {
const probs = _.isTypedArray(classProbabilities)
? Array.prototype.slice.call(classProbabilities)
: classProbabilities;
const sorted = _.reverse(
_.sortBy(
probs.map((prob, index) => [prob, index]),
probIndex => probIndex[0]
)
);
const topK = _.take(sorted, k).map(probIndex => {
const iClass = imagenetClasses[probIndex[1]]
return {
id: iClass[0],
index: parseInt(probIndex[1].toString(), 10),
name: iClass[1].replace(/_/g, " "),
probability: probIndex[0]
}
});
return topK;
}
- Agora você adicionou todos os scripts necessários para executar a classificação de imagem com WebNN em seu aplicativo Web básico. Usando a extensão Live Server para VS Code, agora podes iniciar a tua página web básica na aplicação para ver os resultados da classificação por ti mesmo.