-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an API to keep data on GPU: dataToGPU #5953
Conversation
Very excited to see this new function. Will this be in v13? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @lina128)
tfjs-backend-webgl/src/backend_webgl.ts, line 809 at r3 (raw file):
size <= texSize, () => 'customTexShape is too small. ' + 'Row by column by 4 should be equal or larger than the ' +
Row * Column * 4
Code quote:
Row by column by 4
tfjs-backend-webgl/src/backend_webgl_test.ts, line 752 at r3 (raw file):
}); // TODO(lina128): Debug issue in CI. Code runs fine in Safari WebGL1 in local.
is this failing due to texture is float16? Since the difference is only the ENVS, we delete this section when we figure out CI issue for WebGL1.
tfjs-core/src/tensor.ts, line 369 at r3 (raw file):
/** * Synchronously copy the tensor's data to a new GPU resource. Comparing to
This is async copy in terms of JS, since it is runs a webGL program, the JS return does not guarantee completion of shader execution.
But for WebGL this is sync, since the GPU queue is synchronized.
tfjs-backend-webgl/src/gpgpu_util.ts, line 227 at r2 (raw file):
gl.TEXTURE_2D, 0, 0, 0, pixels.width, pixels.height, gl.RGBA, gl.UNSIGNED_BYTE, (pixels as PixelData).data)); gl.flush();
gl.flush()
I think this line should be removed, I guess I added by accident, this should not be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @pyu10055)
tfjs-backend-webgl/src/backend_webgl.ts, line 809 at r3 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
Row * Column * 4
Done.
tfjs-backend-webgl/src/backend_webgl_test.ts, line 752 at r3 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
is this failing due to texture is float16? Since the difference is only the ENVS, we delete this section when we figure out CI issue for WebGL1.
Fixed.
tfjs-core/src/tensor.ts, line 369 at r3 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
This is async copy in terms of JS, since it is runs a webGL program, the JS return does not guarantee completion of shader execution.
But for WebGL this is sync, since the GPU queue is synchronized.
Removed the confusing wording.
tfjs-backend-webgl/src/gpgpu_util.ts, line 227 at r2 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
gl.flush()
I think this line should be removed, I guess I added by accident, this should not be needed.
Will fix in a separate PR.
@danwexler , yes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't notice that you pass a canvas context to webgl backend. It seems that the returned GPUResource
is still limited in current tfjs context. How should users use this texture to another webgl program?
return gpuResouorce; | ||
} | ||
|
||
if (values != null && texture == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If values
is not null, can we just upload the data to a texture and return the texture?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Jiajia, yes, GPUResource is still limited in current tfjs context. We suggest them to pass the canvas to use when creating webgl backend. Here's the other PR that allows user to pass a canvas: #5983
Reviewable status: 0 of 1 approvals obtained (waiting on @pyu10055 and @qjia7)
tfjs-backend-webgl/src/backend_webgl.ts, line 415 at r5 (raw file):
Previously, qjia7 (Jiajia Qin) wrote…
If
values
is not null, can we just upload the data to a texture and return the texture?
I have thought about this, it's hard to say which way is more convenient to users, so we'll see. Normally, if values are not null, it's either a small amount of data or the values haven't been uploaded yet, in both cases, users may have their preferred way of using the data, not necessarily using TFJS formatted data on GPU, so I prefer to leave it to user for now. However, if there's such request to provide TFJS formatted texture in the future, we can definitely support it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @lina128, @pyu10055, and @qjia7)
tfjs-backend-webgl/src/backend_webgl.ts, line 415 at r5 (raw file):
Previously, lina128 (Na Li) wrote…
I have thought about this, it's hard to say which way is more convenient to users, so we'll see. Normally, if values are not null, it's either a small amount of data or the values haven't been uploaded yet, in both cases, users may have their preferred way of using the data, not necessarily using TFJS formatted data on GPU, so I prefer to leave it to user for now. However, if there's such request to provide TFJS formatted texture in the future, we can definitely support it.
might be good to throw error instead of returning null. given that we don't support reading on CPU data to GPU.
tfjs-backend-webgl/src/backend_webgl.ts, line 423 at r5 (raw file):
// Make engine track this tensor, so that we can dispose it later. engine().makeTensorFromDataId(
how user can track this tensor and dispose later?
tfjs-backend-webgl/src/backend_webgl_test.ts, line 682 at r5 (raw file):
}); describeWithFlags('keeping data on gpu ', WEBGL2_ENVS, () => {
can you add tests for memory leak check?
tfjs-core/src/tensor.ts, line 392 at r5 (raw file):
* @doc {heading: 'Tensors', subheading: 'Classes'} */ dataToGPU(options?: DataToGPUOptions): GPUResource {
should the GPUResource also contains reference to the tensor? so call can dispose it later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @lina128, @pyu10055, and @qjia7)
tfjs-backend-webgl/src/backend_webgl.ts, line 423 at r5 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
how user can track this tensor and dispose later?
The GPUResource has dataId, which is the only thing needed when disposing tensor. User can dispose it the same way as tensor, for typescript user, they may need to cast GPUResource to tensor first. So something like: tf.dispose(gpuResource as {} as Tensor)
.
tfjs-core/src/tensor.ts, line 392 at r5 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
should the GPUResource also contains reference to the tensor? so call can dispose it later?
It has reference to the tensor, dataId.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @lina128, @pyu10055, and @qjia7)
tfjs-core/src/tensor.ts, line 392 at r5 (raw file):
Previously, lina128 (Na Li) wrote…
It has reference to the tensor, dataId.
can tidy automatically dispose GPUResource?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @pyu10055 and @qjia7)
tfjs-backend-webgl/src/backend_webgl.ts, line 415 at r5 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
might be good to throw error instead of returning null. given that we don't support reading on CPU data to GPU.
Done.
tfjs-backend-webgl/src/backend_webgl_test.ts, line 682 at r5 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
can you add tests for memory leak check?
Done.
tfjs-core/src/tensor.ts, line 392 at r5 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
can tidy automatically dispose GPUResource?
It should behave the same as Tensor, added a test to verify.
tfjs-core/src/tensor.ts
Outdated
* | ||
* @doc {heading: 'Tensors', subheading: 'Classes'} | ||
*/ | ||
dataToGPU(options?: DataToGPUOptions): GPUResource { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, why support customTexShape
? Is there any special requirement for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 approvals obtained (waiting on @pyu10055 and @qjia7)
tfjs-backend-webgl/src/backend_webgl.ts, line 423 at r5 (raw file):
Previously, lina128 (Na Li) wrote…
The GPUResource has dataId, which is the only thing needed when disposing tensor. User can dispose it the same way as tensor, for typescript user, they may need to cast GPUResource to tensor first. So something like:
tf.dispose(gpuResource as {} as Tensor)
.
Hi Ping, you are right, it's better to track this tensor instead of just use dataId, I added the memory test. Previously, the tensor cannot be disposed properly because GPUResource is not recognized as instanceOf Tensor in one place in engine. After the latest change, it should work. Also see the memory test.
tfjs-core/src/tensor.ts, line 392 at r6 (raw file):
Previously, qjia7 (Jiajia Qin) wrote…
Just curious, why support
customTexShape
? Is there any special requirement for this?
The main use case is if user set the texShape to be the same as the canvas shape, then they can directly render the result on canvas. If they don't specify the texShape, we try to make a squarish texture.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status:
complete! 1 of 1 approvals obtained (waiting on @lina128, @pyu10055, and @qjia7)
tfjs-backend-webgl/src/backend_webgl_test.ts, line 802 at r7 (raw file):
const b = tf.add(a, 0); b.dataToGPU(); return b
missing ;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status:
complete! 1 of 1 approvals obtained (waiting on @pyu10055 and @qjia7)
tfjs-backend-webgl/src/backend_webgl_test.ts, line 802 at r7 (raw file):
Previously, pyu10055 (Ping Yu) wrote…
missing
;
Done.
Hi, @lina128 , you had replied Jiajia's as below, I have a confusion here, If canvas size is 44, and texture size is 22, we could directly render this texture to the canvas, and hardware will use texture LINEAR or NEAREST filter sampling to render the content. |
Hi @xhcao , I think for WebGL, if the texture is larger than the data size, the unused space will be 0. We try to store data in dense format, so the content will be [1, 2, 3, 4, 0, ..., 0]. |
Hi, @lina128 , I had tested unit case on webgl backend,
});
Float32Array(36) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, buffer: ArrayBuffer(144), byteLength: 144, byteOffset: 0, length: 36, Symbol(Symbol.toStringTag): 'Float32Array'] I am confusion why we need to change the shape. We could not ensure the filling content is correct and is expected by Users. What are rules to define the filling behaviors? I think it is incorrect to fill with 0. For example, if original texture is 2x2, and then call dataToGPU with shape 4x4 to create the new texture, most of the new texture is transparent, I think it is not the expected result. |
Hi @xhcao, you only take the first 12 elements, which is correct, right? This is the same approach we use for reading data to cpu in WebGL, we create the right size of the buffer and call readPixels: https://github.com/tensorflow/tfjs/blob/master/tfjs-backend-webgl/src/gpgpu_util.ts#L271 Data beyond the size doesn't matter whether it is 0 or some other values, we simply ignore them. |
@lina128 , Does it mean the data beyond the size of the new created texture must be written again before it could be rendered to canvas? There may be a wrong understanding of dataToGPU usage for me. Could you simply give an usage example of dataToGPU with custom size here. Thank you. |
Hi @xhcao, I see what you mean. There should be another shader to format how it wants to render if the size doesn't match the canvas size. Can you describe a real use case? It will help me prepare the example. Thanks. |
Hi, @lina128, actually, I did not know the scenarios which could gain the performance improvement by using custom size option, so I asked you why we needed the custom size option. We could also use the below steps to implement the above scenario. I am not sure whether [1] is better than [2], but I sort of agree to add the option to dataToGPU api if there is no side effect. |
Hi @xhcao, thank you for providing the imagined scenarios. The actual scenario of using customSize is more like the other way round, the customSize will fit exactly the data, whereas our default (the more squarish texture) will waste some space. |
This PR adds a convenient API to read data out as a texture, so that it can directly be rendered on canvas or used by downstream shaders.
To see the logs from the Cloud Build CI, please join either our discussion or announcement mailing list.
This change is