You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jun 10, 2024. It is now read-only.
Repository navigation
This repository was archived by the owner on Jun 10, 2024. It is now read-only.
I'm researching into CuPy's capabilities and how it might operate together with VPF. With VPF there are direct ways to convert a Surface to a PyTorch Tensor on the GPU with minimal costs (using the PyTorch extension). According to the CuPy docs, both PyTorch and CuPy support __cuda_array_interface__, so they can also be converted to each other with minimal cost.
To my limited understanding, does this mean that technically a VPF Surface can directly be converted to a CuPy mat? If so, do you know a way how to do this or if this is possible with VPF?
@gedoensmax is now PIC for everything VPF and I'm continuing to support it as a community member. Max is a CUDA expert so this question will go to him anyway ;)
WRT the CuPy interop. I'm not 100% sure if I understand you correctly but this is a sample which shows the pytorch tensor <> pycuda interop. Is it same for CuPy?
Hi @RomanArzumanyan thanks for the update and your support in the past!
I unfortunately do not know exactly if something similar is possible with CuPy. I did find support for low-level CUDA operations in their docs on this page, where they provide functions/classes for interacting with CUDA memory. It also appears there are some objects related to memory management, e.g. cupy.cuda.MemoryPointer or cupy.cuda.UnownedMemory, but I don't know how I can use these to access my VPF Surface's contents.
I tried accessing the memory location of the Surface as follows:
I did not have any luck so far to convert this to a CuPy mat/ndarray or if I'm doing this the right way at all, so I was hoping perhaps you or @gedoensmax would be more familiar with CuPy. If not, I'll try at the CuPy issue board. I'd like to prevent having to convert Surface <-> PyTorch <-> CuPy and instead convert Surface <-> CuPy. Luckily these steps are not very costly, but it would be nice if I could skip the extra step :)
Hey i can definetly take a look, but will be on vacation the next 2 weeks.
Have you tried simply using vpf_mem = rgb_planar.PlanePtr() as pointer ? Because that should be supported if i understand this correctly: cupy/cupy#4644
Sorry for not being able to investigate further right now but i will get back to it if the problem persists
@gedoensmax Thanks for your reply!
It seems the CuPy functions expect an integer, so that's why I did vpf_mem = rgb_planar.PlanePtr().GpuMem().
No worries, enjoy your vacation! If I manage to find the solution in the meantime, I'll close this issue with what I found!
After a small test, your piece of code seems to do the trick on my end, so thank you so much!
I would like to encode the frames again to a new video using VPF after doing various CuPy operations on the decoded video frames. Do you perhaps know if it's also possible to convert back from CuPy -> Surface?
If so, I can completely remove PyTorch from my pipeline and get back a bit of claimed CUDA memory as a bonus :)
Hey @Renzzauw. You can modify the cupy_frame like a regular ndarray the changes you'd make will be in the Suface as well, since they share the same underlying Memory and CuPy doesn't own it.
As long as you don't go outside the valid pixel - When done you can simply re-encode the Surface (rgb_frame)
Thanks for the help so far! I had a small question regarding this topic, since my knowledge is a bit limited about the way CUDA surfaces exactly work or are structured, I hope you are able to help me out with perhaps a simple issue.
For my use-case I am doing various operations on each frame of a video, which also includes down-scaling a video 1920x1080 -> 1280x720 and encoding to a 1280x720 video file. I'm aware of the PySurfaceResizer, but I have per-frame logic how I want to crop frames, so it's a bit more technical compared to simply downscaling a video frame, so I cannot apply it in my use-case.
Since this output ndarray does not have the same size as the input surface, I think this means I have to create a new VPF Surface with this size and then in some way copy the data in formatting the VPF surface understands.
I do not know exactly how to do this last step from my new CuPy ndarray to a VPF Surface. I took some inspiration from the sample code for the PyTorch Plugin and tried creating a new Surface with the size of this ndarray, but I do not exactly know how to get the ndarray data into this Surface. Do you perhaps know how this can be done?
Yes this is possible within VPF. In fact you don't need to take the CuPy route at all. VPF exposes a convenient callback for cropping Surfaces.
Here's code to shed light on this.
import PyNvCodec as nvc
# you'd replace surface with frame you read from video file
# rgb/rgb_planar/nv12 etc
surface = nvc.Surface.Make(nvc.PixelFormat.RGB, 1920, 1080, 0)
# call `.Crop` instead of cupy_frame[:720, :1280, :]
cropped_surface = surface.Crop(0, 0, 1280, 720, 0)
cropped_surface.Width()
1280
cropped_surface.Height()
720
here's the docstring to help with arguments.
import inspect
print(inspect.getdoc(surface.Crop))
Crop(*args, **kwargs)
Overloaded function.
1. Crop(self: PyNvCodec.Surface, x: int, y: int, w: int, h: int, gpu_id: int) -> PyNvCodec.Surface
Crop = select ROI + CUDA mem alloc + CUDA mem copy
:param x: ROI top left X coordinate
:param y: ROI top left Y coordinate
:param w: ROI width in pixels
:param h: ROI height in pixels
:param gpu_id: GPU to use
2. Crop(self: PyNvCodec.Surface, x: int, y: int, w: int, h: int, context: int, stream: int) -> PyNvCodec.Surface
Crop = select ROI + CUDA mem alloc + CUDA mem copy
:param x: ROI top left X coordinate
:param y: ROI top left Y coordinate
:param w: ROI width in pixels
:param h: ROI height in pixels
:param context: CUDA contet to use
:param stream: CUDA stream to use
Hope I don't bother with another question regarding CuPy.
I'm currently in a situation where I don't decode a Surface from a video, but combine various assets (.png layers) myself without VPF and create a CuPy array out of these, so I don't have an existing Surface on the GPU I can manipulate as in the examples above. I would like to write the result of my CuPy operations to a video file using VPF.
This means I probably would have to create a Surface object myself and somehow reference my CuPy array's memory location. Is this possible with VPF? If so, how can I achieve this or what steps should I take to transform it into a format that can be read as a Surface (I don't fully understand how strides/pitch work, so I guess the array data should have a specific layout in memory as well).
Hi there. Interesting use case. If you don't mind multiple copies of your assets i'd do the following. Let's says your assets in CuPy is of the shape NHWC. calling it assets_arr_cupy
Create a N x Surfaces nvc.Surface.Make(format, width, height, gpu_id)
Use the function above to get a CuPy array for each Suface and stack them call the resulting array vpf_surfaces_cupy
copy data over cupy.copyto(vpf_surfaces_cupy, assets_arr_cupy)
Another option would be read your assets into the vpf_surfaces_cupy directly and then encode the video with VPF. Hope this helps.
Activity
RomanArzumanyan commentedon Oct 27, 2022
Hi @Renzzauw
@gedoensmax is now PIC for everything VPF and I'm continuing to support it as a community member. Max is a CUDA expert so this question will go to him anyway ;)
WRT the CuPy interop. I'm not 100% sure if I understand you correctly but this is a sample which shows the pytorch tensor <> pycuda interop. Is it same for CuPy?
VideoProcessingFramework/SampleTensorRTResnet.py
Lines 1064 to 1147 in 2b69dc5
Renzzauw commentedon Oct 28, 2022
Hi @RomanArzumanyan thanks for the update and your support in the past!
I unfortunately do not know exactly if something similar is possible with CuPy. I did find support for low-level CUDA operations in their docs on this page, where they provide functions/classes for interacting with CUDA memory. It also appears there are some objects related to memory management, e.g.
cupy.cuda.MemoryPointerorcupy.cuda.UnownedMemory, but I don't know how I can use these to access my VPF Surface's contents.I tried accessing the memory location of the Surface as follows:
I did not have any luck so far to convert this to a CuPy mat/ndarray or if I'm doing this the right way at all, so I was hoping perhaps you or @gedoensmax would be more familiar with CuPy. If not, I'll try at the CuPy issue board. I'd like to prevent having to convert Surface <-> PyTorch <-> CuPy and instead convert Surface <-> CuPy. Luckily these steps are not very costly, but it would be nice if I could skip the extra step :)
gedoensmax commentedon Oct 28, 2022
Hey i can definetly take a look, but will be on vacation the next 2 weeks.
Have you tried simply using
vpf_mem = rgb_planar.PlanePtr()as pointer ? Because that should be supported if i understand this correctly: cupy/cupy#4644Sorry for not being able to investigate further right now but i will get back to it if the problem persists
Renzzauw commentedon Nov 1, 2022
@gedoensmax Thanks for your reply!
It seems the CuPy functions expect an integer, so that's why I did
vpf_mem = rgb_planar.PlanePtr().GpuMem().No worries, enjoy your vacation! If I manage to find the solution in the meantime, I'll close this issue with what I found!
sandhawalia commentedon Nov 9, 2022
Hi there, I have been using this, maybe it will help.
rgb_frameisSurfaceof typenvc.PixelFormat.RGB.Renzzauw commentedon Nov 9, 2022
@sandhawalia hi, thanks for your reply!
After a small test, your piece of code seems to do the trick on my end, so thank you so much!
I would like to encode the frames again to a new video using VPF after doing various CuPy operations on the decoded video frames. Do you perhaps know if it's also possible to convert back from CuPy -> Surface?
If so, I can completely remove PyTorch from my pipeline and get back a bit of claimed CUDA memory as a bonus :)
sandhawalia commentedon Nov 9, 2022
Hey @Renzzauw. You can modify the
cupy_framelike a regularndarraythe changes you'd make will be in theSufaceas well, since they share the same underlyingMemoryand CuPy doesn't own it.As long as you don't go outside the valid pixel - When done you can simply re-encode the
Surface(rgb_frame)Renzzauw commentedon Nov 9, 2022
Hi @sandhawalia, that makes a lot of sense, thank you for clarifying. Really happy to hear I can remove my dependency on PyTorch via this way.
I'll be closing this issue as for now my questions have been answered!
Renzzauw commentedon Nov 11, 2022
Hi @sandhawalia,
Thanks for the help so far! I had a small question regarding this topic, since my knowledge is a bit limited about the way CUDA surfaces exactly work or are structured, I hope you are able to help me out with perhaps a simple issue.
For my use-case I am doing various operations on each frame of a video, which also includes down-scaling a video 1920x1080 -> 1280x720 and encoding to a 1280x720 video file. I'm aware of the PySurfaceResizer, but I have per-frame logic how I want to crop frames, so it's a bit more technical compared to simply downscaling a video frame, so I cannot apply it in my use-case.
Since this output ndarray does not have the same size as the input surface, I think this means I have to create a new VPF Surface with this size and then in some way copy the data in formatting the VPF surface understands.
I do not know exactly how to do this last step from my new CuPy ndarray to a VPF Surface. I took some inspiration from the sample code for the PyTorch Plugin and tried creating a new Surface with the size of this ndarray, but I do not exactly know how to get the ndarray data into this Surface. Do you perhaps know how this can be done?
Thanks in advance!
See my code example below:
sandhawalia commentedon Nov 13, 2022
Hey there.
Yes this is possible within VPF. In fact you don't need to take the CuPy route at all. VPF exposes a convenient callback for cropping Surfaces.
Here's code to shed light on this.
here's the
docstringto help with arguments.Renzzauw commentedon Dec 1, 2022
Hi @sandhawalia,
Hope I don't bother with another question regarding CuPy.
I'm currently in a situation where I don't decode a Surface from a video, but combine various assets (.png layers) myself without VPF and create a CuPy array out of these, so I don't have an existing Surface on the GPU I can manipulate as in the examples above. I would like to write the result of my CuPy operations to a video file using VPF.
This means I probably would have to create a Surface object myself and somehow reference my CuPy array's memory location. Is this possible with VPF? If so, how can I achieve this or what steps should I take to transform it into a format that can be read as a Surface (I don't fully understand how strides/pitch work, so I guess the array data should have a specific layout in memory as well).
Thanks!
sandhawalia commentedon Dec 6, 2022
Hi there. Interesting use case. If you don't mind multiple copies of your assets i'd do the following. Let's says your assets in CuPy is of the shape
NHWC. calling itassets_arr_cupyNx Surfacesnvc.Surface.Make(format, width, height, gpu_id)vpf_surfaces_cupycupy.copyto(vpf_surfaces_cupy, assets_arr_cupy)Another option would be read your assets into the
vpf_surfaces_cupydirectly and then encode the video with VPF. Hope this helps.Renzzauw commentedon Dec 8, 2022
@sandhawalia Thanks for the extensive explanation, this is really useful!
gedoensmax commentedon Dec 8, 2022
I feel like this is helpful for more people and i will transition this issue to a discussion !