Webworkers中的tensorflow.js

时间:2019-01-25 06:00:09

标签: javascript web-worker tensorflow.js tensorflowjs-converter

我想通过importScripts()如下导入webWorker中的2个脚本,但是导入失败。如何处理?

self.importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs');
self.importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter');

error figure

2 个答案:

答案 0 :(得分:2)

当前,无法在web-worker上使用webgl实现,offlineCanvas是实验性功能。但是,可以使用CPU后端。

这里是委派给网络工作者执行计算的示例

<head>
	<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
    <script>
        const worker_function = () => {

            onmessage =  () => {
                console.log('from web worker')
                    this.window = this
                    importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
                    importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
                    tf.setBackend('cpu')
                    
                    const res = tf.zeros([1, 2]).add(tf.ones([1, 2]))
                    res.print()
                    
                    postMessage({res: res.dataSync(), shape: res.shape})
            };
        }
        if (window != self)
            worker_function();
    </script>
    <script>
        const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
        worker.postMessage({});
        worker.onmessage = (message) => {
        	console.log('from main thread')
        	const {data} = message
        	tf.tensor(data.res, data.shape).print()
        }
    </script>
</head>

使用张量,在主线程和Web Worker之间共享的数据可能很大。可以克隆或传输此数据。

区别在于,如果克隆了数据,Web Worker将仍然保留数据的副本以进行进一步处理。传输时,数据的所有权也会被传输。与克隆相比,它的优点是传输速度快,实际上它可以看作是引用的传递(如果引用来自具有指针语言的背景)

让我们用这两个片段讨论性能

<head>
	<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
    <script>
        const worker_function = () => {

            onmessage =  () => {
                console.log('from web worker')
                    this.window = this
                    importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
                    importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
                    tf.setBackend('cpu')
                    
                    const res = tf.randomNormal([2000, 2000, 3])
                    const t0 = performance.now()
                    postMessage({res: res.dataSync().buffer, shape: res.shape}, [res.dataSync().buffer])
                    console.log(`Prediction took ${(performance.now() - t0).toFixed(1)} ms`)
            };
        }
        if (window != self)
            worker_function();
    </script>
    <script>
        const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
        worker.postMessage({});
        worker.onmessage = (message) => {
        	console.log('from main thread')
        	const {data} = message
        	tf.tensor(new Float32Array(message.data.res), message.data.shape)
        }
    </script>
</head>

<head>
	<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
    <script>
        const worker_function = () => {

            onmessage =  () => {
                console.log('from web worker')
                    this.window = this
                    importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
                    importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
                    tf.setBackend('cpu')
                    
                    const res = tf.randomNormal([2000, 2000, 3])
                    const t0 = performance.now()
                    postMessage({res: res.dataSync(), shape: res.shape})
                    console.log(`Prediction took ${(performance.now() - t0).toFixed(1)} ms`)
            };
        }
        if (window != self)
            worker_function();
    </script>
    <script>
        const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
        worker.postMessage({});
        worker.onmessage = (message) => {
        	console.log('from main thread')
        	const {data} = message
        	tf.tensor(message.data.res, message.data.shape)
        }
    </script>
</head>

我们可以看到两个摘要之间相差约10毫秒。如果以性能为代价,那么必须克隆或传输数据时,应考虑如何共享数据。

答案 1 :(得分:0)

TensorflowJS需要画布来执行GPU计算,并且工作人员当前没有画布。

OffscreenCanvas是一项正在使用的功能,但是在TFJS使用它之前,它可能需要足够广泛的浏览器支持。