2

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

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

错误图

4

2 回答 2

3

目前,无法在 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 毫秒。当以性能为代价时,如果必须克隆或传输数据,则需要考虑如何共享数据。

于 2019-01-25T22:54:55.300 回答
0

TensorflowJS 需要画布来进行 GPU 计算,而工作人员目前没有画布。

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

于 2019-01-25T09:22:43.187 回答