Skip to content

Commit

Permalink
Remove Wasm and WebGL backends (WebNN-Polyfill) (#281)
Browse files Browse the repository at this point in the history
* Remove Wasm and WebGL backends (WebNN-Polyfill)

* update README

* Remove css class which does not exist in page
  • Loading branch information
ibelem authored Oct 11, 2024
1 parent ce57ba9 commit a7a7d6b
Show file tree
Hide file tree
Showing 45 changed files with 59 additions and 380 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ We welcome contributions from the community to make webnn-samples even better! I
### WebNN Resources
To learn more about Web Neural Network API (WebNN) and its capabilities, check out the following resources:
* [Web Neural Network API Specification](https://webmachinelearning.github.io/webnn/)
* [WebNN Polyfill](https://github.com/webmachinelearning/webnn-polyfill)
* [WebNN Community Group](https://webmachinelearning.github.io/)
* [W3C WebML Working Group and Community Group](https://webmachinelearning.github.io/)

### WebNN API Samples
* [WebNN code editor](https://webmachinelearning.github.io/webnn-samples/code/)
Expand Down
2 changes: 1 addition & 1 deletion code/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
<script src="./libs/codemirror/codemirror.js"></script>
<script src="./libs/codemirror/javascript.js"></script>
<script src="./libs/codemirror/sublime.js"></script>
<script src="https://webmachinelearning.github.io/webnn-polyfill/dist/webnn-polyfill.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"></script>
<script type="module">
import {main} from './main.js';
window.onload = async () => {
Expand Down
8 changes: 4 additions & 4 deletions code/main.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {samplesRepo} from './samples_repo.js';
import * as utils from '../common/utils.js';
import {addAlert} from '../common/ui.js';

window.sizeOfShape = utils.sizeOfShape;

export async function main() {
// Set backend
if (await utils.isWebNN()) {
await utils.setBackend('webnn', 'cpu');
} else {
await utils.setBackend('polyfill', 'cpu');
if (!await utils.isWebNN()) {
console.log(utils.webNNNotSupportMessage());
addAlert(utils.webNNNotSupportMessageHTML());
}
const selectElement = document.getElementById('example-select');
for (const name of samplesRepo.names()) {
Expand Down
7 changes: 0 additions & 7 deletions common/component/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -599,13 +599,6 @@ $(document).ready(async () => {
$("#footer").html(footer());
if (await isWebNN()) {
if ($("#backendBtns")) {
$('label[name="polyfill"]').addClass("disabled");
$('label[name="polyfill"]').addClass("btn-outline-secondary");
$('label[name="polyfill"]').removeClass("btn-outline-info");
$('label[name="polyfill"]').attr(
"title",
"WebNN is supported, disable WebNN Polyfill."
);
// Disable WebNN NPU backend if failed to find a capable NPU adapter.
try {
await navigator.ml.createContext({deviceType: 'npu'});
Expand Down
103 changes: 8 additions & 95 deletions common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,48 +269,6 @@ export function getMedianValue(array) {
(array[array.length / 2 - 1] + array[array.length / 2]) / 2;
}

// Set tf.js backend based WebNN's 'MLDeviceType' option
export async function setPolyfillBackend(device) {
// Simulate WebNN's device selection using various tf.js backends.
// MLDeviceType: ['default', 'gpu', 'cpu']
// 'default' or 'gpu': tfjs-backend-webgl, 'cpu': tfjs-backend-wasm
if (!device) device = 'gpu';
// Use 'webgl' by default for better performance.
// Note: 'wasm' backend may run failed on some samples since
// some ops aren't supported on 'wasm' backend at present
const backend = device === 'cpu' ? 'wasm' : 'webgl';
const context = await navigator.ml.createContext();
const tf = context.tf;
if (tf) {
if (backend == 'wasm') {
const wasm = context.wasm;
// Force to use Wasm SIMD only
wasm.setWasmPath(`https://unpkg.com/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/tfjs-backend-wasm-simd.wasm`);
}
if (!(await tf.setBackend(backend))) {
throw new Error(`Failed to set tf.js backend ${backend}.`);
}
await tf.ready();
let backendInfo = backend == 'wasm' ? 'WASM' : 'WebGL';
if (backendInfo == 'WASM') {
const hasSimd = tf.env().features['WASM_HAS_SIMD_SUPPORT'];
const hasThreads = tf.env().features['WASM_HAS_MULTITHREAD_SUPPORT'];
if (hasThreads && hasSimd) {
backendInfo += ' (SIMD + threads)';
} else if (hasThreads && !hasSimd) {
backendInfo += ' (threads)';
} else if (!hasThreads && hasSimd) {
backendInfo += ' (SIMD)';
}
}
addAlert(
`This sample is running on ` +
`<a href='https://github.com/webmachinelearning/webnn-polyfill'>` +
`WebNN-polyfill</a> with tf.js ${tf.version_core} ` +
`<b>${backendInfo}</b> backend.`, 'info');
}
}

// Get url params
export function getUrlParams() {
const params = new URLSearchParams(location.search);
Expand Down Expand Up @@ -346,59 +304,6 @@ export function getUrlParams() {
return [numRuns, powerPreference, numThreads];
}

// Set backend for using WebNN-polyfill or WebNN
export async function setBackend(backend, device) {
const webnnPolyfillId = 'webnn_polyfill';
const webnnNodeId = 'webnn_node';
const webnnPolyfillElem = document.getElementById(webnnPolyfillId);
const webnnNodeElem = document.getElementById(webnnNodeId);

if (backend === 'polyfill') {
if (webnnNodeElem) {
document.body.removeChild(webnnNodeElem);
// Unset global objects defined in node_setup.js
global.navigator.ml = undefined;
global.MLContext = undefined;
global.MLGraphBuilder = undefined;
global.MLGraph = undefined;
global.MLOperand = undefined;
}
if (!webnnPolyfillElem) {
const webnnPolyfillUrl =
'https://webmachinelearning.github.io/webnn-polyfill/dist/webnn-polyfill.js';
if (typeof(tf) != 'undefined') {
// Reset tf.ENV to avoid environments from tf.min.js
// affect webnn-polyfill.js
tf.engine().reset();
}
// Create WebNN-polyfill script
await loadScript(webnnPolyfillUrl, webnnPolyfillId);
}
await setPolyfillBackend(device);
} else if (backend === 'webnn') {
if (!await isWebNN()) {
addAlert(`WebNN is not supported!`, 'warning');
}
} else {
addAlert(`Unknow backend: ${backend}`, 'warning');
}
}

// Promise to load script with url and id
async function loadScript(url, id) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.onload = resolve;
script.onerror = reject;
script.src = url;
script.id = id;
if (url.startsWith('http')) {
script.crossOrigin = 'anonymous';
}
document.body.appendChild(script);
});
}

export async function isWebNN() {
if (typeof MLGraphBuilder !== 'undefined') {
const context = await navigator.ml.createContext();
Expand All @@ -408,6 +313,14 @@ export async function isWebNN() {
}
}

export function webNNNotSupportMessage() {
return 'Your browser does not support WebNN.';
}

export function webNNNotSupportMessageHTML() {
return 'Your browser does not support WebNN. Please refer to <a href="https://github.com/webmachinelearning/webnn-samples/#webnn-installation-guides">WebNN Installation Guides</a> for more details.';
}

// Derive from
// https://github.com/webmachinelearning/webnn-baseline/blob/main/src/lib/compute-padding.js
/**
Expand Down
8 changes: 0 additions & 8 deletions face_recognition/facenet_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,6 @@ export class FaceNetNchw {
this.graph_ = await this.builder_.build({'output': outputOperand});
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
8 changes: 0 additions & 8 deletions face_recognition/facenet_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,6 @@ export class FaceNetNhwc {
this.graph_ = await this.builder_.build({'output': outputOperand});
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
6 changes: 0 additions & 6 deletions face_recognition/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@
</div>
<div class="col-md-auto">
<div class="btn-group-toggle" data-toggle="buttons" id="backendBtns">
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_cpu" autocomplete="off">Wasm (CPU)
</label>
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_gpu" autocomplete="off">WebGL (GPU)
</label>
<label class="btn btn-outline-info custom" name="webnn">
<input type="radio" name="backend" id="webnn_cpu" autocomplete="off">WebNN (CPU)
</label>
Expand Down
12 changes: 2 additions & 10 deletions face_recognition/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ $(document).ready(async () => {
if (await utils.isWebNN()) {
$('#webnn_cpu').click();
} else {
$('#polyfill_cpu').click();
console.log(utils.webNNNotSupportMessage());
ui.addAlert(utils.webNNNotSupportMessageHTML());
}
});

Expand Down Expand Up @@ -307,19 +308,10 @@ async function main() {
lastdeviceType != deviceType || lastBackend != backend) {
if (lastdeviceType != deviceType || lastBackend != backend) {
// Set backend and device
await utils.setBackend(backend, deviceType);
lastdeviceType = lastdeviceType != deviceType ?
deviceType : lastdeviceType;
lastBackend = lastBackend != backend ? backend : lastBackend;
}
if (frInstance !== null) {
// Call dispose() to and avoid memory leak
frInstance.dispose();
}
if (fdInstance !== null) {
// Call dispose() to and avoid memory leak
fdInstance.dispose();
}
fdInstanceType = fdModelName + layout;
frInstanceType = frModelName + layout;
fdInstance = constructNetObject(fdInstanceType);
Expand Down
8 changes: 0 additions & 8 deletions facial_landmark_detection/face_landmark_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,6 @@ export class FaceLandmarkNchw {
this.graph_ = await this.builder_.build({'output': outputOperand});
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
8 changes: 0 additions & 8 deletions facial_landmark_detection/face_landmark_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,6 @@ export class FaceLandmarkNhwc {
this.graph_ = await this.builder_.build({'output': outputOperand});
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
6 changes: 0 additions & 6 deletions facial_landmark_detection/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@
</div>
<div class="col-md-auto">
<div class="btn-group-toggle" data-toggle="buttons" id="backendBtns">
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_cpu" autocomplete="off">Wasm (CPU)
</label>
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_gpu" autocomplete="off">WebGL (GPU)
</label>
<label class="btn btn-outline-info custom" name="webnn">
<input type="radio" name="backend" id="webnn_cpu" autocomplete="off">WebNN (CPU)
</label>
Expand Down
12 changes: 2 additions & 10 deletions facial_landmark_detection/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ $(document).ready(async () => {
if (await utils.isWebNN()) {
$('#webnn_cpu').click();
} else {
$('#polyfill_cpu').click();
console.log(utils.webNNNotSupportMessage());
ui.addAlert(utils.webNNNotSupportMessageHTML());
}
});

Expand Down Expand Up @@ -243,19 +244,10 @@ async function main() {
lastdeviceType != deviceType || lastBackend != backend) {
if (lastdeviceType != deviceType || lastBackend != backend) {
// Set backend and device
await utils.setBackend(backend, deviceType);
lastdeviceType = lastdeviceType != deviceType ?
deviceType : lastdeviceType;
lastBackend = lastBackend != backend ? backend : lastBackend;
}
if (fldInstance !== null) {
// Call dispose() to and avoid memory leak
fldInstance.dispose();
}
if (fdInstance !== null) {
// Call dispose() to and avoid memory leak
fdInstance.dispose();
}
fdInstanceType = fdModelName + layout;
fldInstanceType = fldModelName + layout;
fdInstance = constructNetObject(fdInstanceType);
Expand Down
8 changes: 0 additions & 8 deletions facial_landmark_detection/ssd_mobilenetv2_face_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,6 @@ ${nameArray[1]}`;
this.graph_ = await this.builder_.build(outputOperand);
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
8 changes: 0 additions & 8 deletions facial_landmark_detection/ssd_mobilenetv2_face_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,6 @@ ${nameArray[1]}`;
this.graph_ = await this.builder_.build(outputOperand);
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
8 changes: 0 additions & 8 deletions image_classification/efficientnet_fp16_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,6 @@ export class EfficientNetFP16Nchw {
this.graph_ = await this.builder_.build({'output': outputOperand});
}

// Release the constant tensors of a model
dispose() {
// dispose() is only available in webnn-polyfill
if (this.graph_ !== null && 'dispose' in this.graph_) {
this.graph_.dispose();
}
}

async compute(inputBuffer) {
this.context_.writeTensor(this.inputTensor_, inputBuffer);
const inputs = {'input': this.inputTensor_};
Expand Down
6 changes: 0 additions & 6 deletions image_classification/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@
</div>
<div class="col-md-auto">
<div class="btn-group-toggle" data-toggle="buttons" id="backendBtns">
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_cpu" autocomplete="off">Wasm (CPU)
</label>
<label class="btn btn-outline-info custom" name="polyfill">
<input type="radio" name="backend" id="polyfill_gpu" autocomplete="off">WebGL (GPU)
</label>
<label class="btn btn-outline-info custom" name="webnn">
<input type="radio" name="backend" id="webnn_cpu" autocomplete="off">WebNN (CPU)
</label>
Expand Down
Loading

0 comments on commit a7a7d6b

Please sign in to comment.