2021-09-25 17:51:15 +02:00
|
|
|
/** TFJS backend initialization and customization */
|
|
|
|
|
2021-09-27 19:58:13 +02:00
|
|
|
import { log, now } from '../util/util';
|
2021-09-13 00:37:06 +02:00
|
|
|
import * as humangl from './humangl';
|
2021-09-27 19:58:13 +02:00
|
|
|
import * as env from '../util/env';
|
2020-12-13 00:34:30 +01:00
|
|
|
import * as tf from '../../dist/tfjs.esm.js';
|
|
|
|
|
2021-09-21 03:59:49 +02:00
|
|
|
export async function check(instance, force = false) {
|
|
|
|
instance.state = 'backend';
|
|
|
|
if (force || env.env.initial || (instance.config.backend && (instance.config.backend.length > 0) && (tf.getBackend() !== instance.config.backend))) {
|
2021-09-13 00:37:06 +02:00
|
|
|
const timeStamp = now();
|
2020-12-13 00:34:30 +01:00
|
|
|
|
2021-09-13 00:37:06 +02:00
|
|
|
if (instance.config.backend && instance.config.backend.length > 0) {
|
|
|
|
// detect web worker
|
|
|
|
// @ts-ignore ignore missing type for WorkerGlobalScope as that is the point
|
|
|
|
if (typeof window === 'undefined' && typeof WorkerGlobalScope !== 'undefined' && instance.config.debug) {
|
2021-09-17 17:23:00 +02:00
|
|
|
if (instance.config.debug) log('running inside web worker');
|
2021-09-13 00:37:06 +02:00
|
|
|
}
|
2021-06-11 22:12:24 +02:00
|
|
|
|
2021-09-13 00:37:06 +02:00
|
|
|
// force browser vs node backend
|
|
|
|
if (env.env.browser && instance.config.backend === 'tensorflow') {
|
2021-09-17 17:23:00 +02:00
|
|
|
if (instance.config.debug) log('override: backend set to tensorflow while running in browser');
|
2021-09-13 00:37:06 +02:00
|
|
|
instance.config.backend = 'humangl';
|
|
|
|
}
|
|
|
|
if (env.env.node && (instance.config.backend === 'webgl' || instance.config.backend === 'humangl')) {
|
2021-09-17 17:23:00 +02:00
|
|
|
if (instance.config.debug) log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
2021-09-13 00:37:06 +02:00
|
|
|
instance.config.backend = 'tensorflow';
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle webgpu
|
|
|
|
if (env.env.browser && instance.config.backend === 'webgpu') {
|
|
|
|
if (typeof navigator === 'undefined' || typeof navigator['gpu'] === 'undefined') {
|
|
|
|
log('override: backend set to webgpu but browser does not support webgpu');
|
|
|
|
instance.config.backend = 'humangl';
|
|
|
|
} else {
|
|
|
|
const adapter = await navigator['gpu'].requestAdapter();
|
|
|
|
if (instance.config.debug) log('enumerated webgpu adapter:', adapter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check available backends
|
2021-09-17 17:23:00 +02:00
|
|
|
if (instance.config.backend === 'humangl') await humangl.register(instance);
|
2021-09-13 00:37:06 +02:00
|
|
|
const available = Object.keys(tf.engine().registryFactory);
|
|
|
|
if (instance.config.debug) log('available backends:', available);
|
|
|
|
|
|
|
|
if (!available.includes(instance.config.backend)) {
|
|
|
|
log(`error: backend ${instance.config.backend} not found in registry`);
|
|
|
|
instance.config.backend = env.env.node ? 'tensorflow' : 'humangl';
|
2021-09-17 17:23:00 +02:00
|
|
|
if (instance.config.debug) log(`override: setting backend ${instance.config.backend}`);
|
2021-09-13 00:37:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (instance.config.debug) log('setting backend:', instance.config.backend);
|
|
|
|
|
|
|
|
// handle wasm
|
|
|
|
if (instance.config.backend === 'wasm') {
|
|
|
|
if (instance.config.debug) log('wasm path:', instance.config.wasmPath);
|
|
|
|
if (typeof tf?.setWasmPaths !== 'undefined') await tf.setWasmPaths(instance.config.wasmPath);
|
2021-09-17 20:07:44 +02:00
|
|
|
else throw new Error('wasm backend is not loaded');
|
2021-09-13 00:37:06 +02:00
|
|
|
const simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
|
|
|
|
const mt = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
|
|
|
|
if (instance.config.debug) log(`wasm execution: ${simd ? 'SIMD' : 'no SIMD'} ${mt ? 'multithreaded' : 'singlethreaded'}`);
|
|
|
|
if (instance.config.debug && !simd) log('warning: wasm simd support is not enabled');
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await tf.setBackend(instance.config.backend);
|
|
|
|
await tf.ready();
|
|
|
|
} catch (err) {
|
|
|
|
log('error: cannot set backend:', instance.config.backend, err);
|
2021-09-17 20:07:44 +02:00
|
|
|
return false;
|
2021-09-13 00:37:06 +02:00
|
|
|
}
|
2021-01-13 15:35:31 +01:00
|
|
|
}
|
2021-09-13 00:37:06 +02:00
|
|
|
|
|
|
|
// handle webgl & humangl
|
|
|
|
if (tf.getBackend() === 'humangl') {
|
|
|
|
tf.ENV.set('CHECK_COMPUTATION_FOR_ERRORS', false);
|
|
|
|
tf.ENV.set('WEBGL_CPU_FORWARD', true);
|
|
|
|
tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', false);
|
|
|
|
tf.ENV.set('WEBGL_USE_SHAPES_UNIFORMS', true);
|
2021-09-27 20:39:54 +02:00
|
|
|
tf.ENV.set('CPU_HANDOFF_SIZE_THRESHOLD', 128);
|
2021-09-13 00:37:06 +02:00
|
|
|
// if (!instance.config.object.enabled) tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true); // safe to use 16bit precision
|
|
|
|
if (typeof instance.config['deallocate'] !== 'undefined' && instance.config['deallocate']) { // hidden param
|
|
|
|
log('changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:', true);
|
|
|
|
tf.ENV.set('WEBGL_DELETE_TEXTURE_THRESHOLD', 0);
|
|
|
|
}
|
|
|
|
// @ts-ignore getGPGPUContext only exists on WebGL backend
|
|
|
|
const gl = await tf.backend().getGPGPUContext().gl;
|
|
|
|
if (instance.config.debug) log(`gl version:${gl.getParameter(gl.VERSION)} renderer:${gl.getParameter(gl.RENDERER)}`);
|
2021-01-13 15:35:31 +01:00
|
|
|
}
|
2021-09-13 00:37:06 +02:00
|
|
|
|
|
|
|
// wait for ready
|
|
|
|
tf.enableProdMode();
|
|
|
|
await tf.ready();
|
|
|
|
instance.performance.backend = Math.trunc(now() - timeStamp);
|
|
|
|
instance.config.backend = tf.getBackend();
|
|
|
|
|
|
|
|
env.get(); // update env on backend init
|
|
|
|
instance.env = env.env;
|
2020-12-13 00:34:30 +01:00
|
|
|
}
|
2021-09-17 20:07:44 +02:00
|
|
|
return true;
|
2020-12-13 00:34:30 +01:00
|
|
|
}
|
2021-09-23 20:09:41 +02:00
|
|
|
|
|
|
|
// register fake missing tfjs ops
|
|
|
|
export function fakeOps(kernelNames: Array<string>, config) {
|
|
|
|
// if (config.debug) log('registerKernel:', kernelNames);
|
|
|
|
for (const kernelName of kernelNames) {
|
|
|
|
const kernelConfig = {
|
|
|
|
kernelName,
|
|
|
|
backendName: config.backend,
|
|
|
|
kernelFunc: () => { if (config.debug) log('kernelFunc', kernelName, config.backend); },
|
|
|
|
// setupFunc: () => { if (config.debug) log('kernelFunc', kernelName, config.backend); },
|
|
|
|
// disposeFunc: () => { if (config.debug) log('kernelFunc', kernelName, config.backend); },
|
|
|
|
};
|
|
|
|
tf.registerKernel(kernelConfig);
|
|
|
|
}
|
|
|
|
env.env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase()); // re-scan registered ops
|
|
|
|
}
|