[Core] introduce videoprocessor. - #7776
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
| """Simple video processor.""" | ||
|
|
||
| @staticmethod | ||
| def tensor2vid(video: torch.Tensor, processor: "VaeImageProcessor", output_type: str = "np"): |
There was a problem hiding this comment.
can you have the methods like frames2gif or frames2mpeg in here as well
There was a problem hiding this comment.
I think we can add this functionality to the export functions we have. Generally the pipelines always return an np array, a torch tensor or PIL image/ PIL image list.
There was a problem hiding this comment.
I don't think so. Here's an example where tensor2vid is being used when returning the output:
|
|
||
| def preprocess_video(self, video: List[Union[PIL.Image.Image, np.ndarray, torch.Tensor]]) -> torch.FloatTensor: | ||
| """Preprocesses input video(s).""" | ||
| supported_formats = (np.ndarray, torch.Tensor, PIL.Image.Image) |
There was a problem hiding this comment.
let's first decide what should be video input format we accept here, I think
- list of list of images (or a list of images, in that case, we expand it as list of list of images)
- list of list of 4d tensors (or a list of 4d tensor, in this case, we expand)
- list of 5d tensors (or 5d tensor, we expand)
- list of list of 4d numpy arrays (or a list of 4d array, we expand)
- list of 5d numpy arrays (or 5d numpy array, we expand)
cc @DN6 here, anything we would add or remove?
There was a problem hiding this comment.
cc @a-r-r-o-w too since you worked on a lot of video pipelines
There was a problem hiding this comment.
Okay, so I think all of those are covered. supported_formats here refer to the core base format which can be used to create lists, 4d or 5d tensors, etc.
Let me provide concrete lines of code that I think ensure all the formats listed above are supported:
- and
- and 3.
- and 5.
There was a problem hiding this comment.
Thanks for looping me in. I think that list[list[image]], list[fchw_tensor] and bfchw_tensor are most common to end up with as a user, and all cases you mentioned seem to be handled well and the code makes sense to me.
A small explanation of expected inputs to video processor in the docstrings, order of tensor dims, and some more documentation, like in image processor, would be helpful for newer users imo.
There was a problem hiding this comment.
Thank you, @a-r-r-o-w! Added a bit of documentation and type annotation to hopefully make it clearer. LMK your thoughts.
There was a problem hiding this comment.
a lot of the work here is overlapping with preprocess though
once we make sure the inputs are accepted as one of below (and expanded)
- list of list of images (or a list of images, in that case, we expand it as list of list of images)
- list of list of 4d tensors (or a list of 4d tensor, in this case, we expand)
- list of 5d tensors (or 5d tensor, we expand)
- list of list of 4d numpy arrays (or a list of 4d array, we expand)
- list of 5d numpy arrays (or 5d numpy array, we expand)
can we try:
video = [self.image_processor.preprocess(vid) for vid in videos]after that we check if all the tensors has same shape in the list and throw an error if not
There was a problem hiding this comment.
a lot of the work here is overlapping with preprocess though
Help me understand this a bit better? From what I understand, the current preprocess_video() is first checking if we have the inputs in the accepted format and is performing the expansion if needed. And then it's passing off the video to preprocess() like you suggested:
diffusers/src/diffusers/video_processor.py
Line 125 in c5d22e6
There was a problem hiding this comment.
The only overlap I see is this:
diffusers/src/diffusers/video_processor.py
Line 106 in c5d22e6
But I see this more as a safeguard rather than an overlap.
There was a problem hiding this comment.
i think something like this should work (made up code, but roughly the logic)
if isinstance(video, supported_formats):
video = [video]
if isinstance(video[0], PIL.Image.Image)or if isinstance(video[0], ( np.ndarray, torch.tensor) and video[0].ndim ==4):
video = [video]
video = torch.stack([self.preprocess(f) for f in video],..)
video = video.permute(0, 2, 1, 3, 4)How about let's first add tests like this https://github.com/huggingface/diffusers/blob/main/tests/others/test_image_processor.py
once we have the test, I can help look into refactoring this function?
There was a problem hiding this comment.
Done. LMK what you think. I had to add a bit of code to deal with 5D stuff. But rest has been simplified a lot IMO.
|
The failing test is completely unexpected. Need to look deeper. @yiyixuxu WDYT about the |
| elif isinstance(video, list) and isinstance(video[0], PIL.Image.Image): | ||
| if isinstance(video, list) and isinstance(video[0], np.ndarray) and video[0].ndim == 5: | ||
| warnings.warn( | ||
| "Passing `video` as a list of 5d np.ndarray is deprecated." |
There was a problem hiding this comment.
Technically not deprecated since we didn't support it before right? I think we just raise an error here.
There was a problem hiding this comment.
it was kinda supported before
this code, if you pass a list of 5d tensors, it would work; I think it is because of the way the code was written, here the first thing it does is to check if it is a tensor, and if so add it to a list; so in order to support a 5d tensor, it has to support a list of 5d tensor as well. This is same situation with image processor as well
| if video and not isinstance(video[0], list): | ||
| video = [video] |
There was a problem hiding this comment.
| if video and not isinstance(video[0], list): | |
| video = [video] |
There was a problem hiding this comment.
But why do we want to do this? I don't think a single-frame video would get represented properly otherwise. We don't have any special treatment for that from preprocess_video either.
There was a problem hiding this comment.
why do they need video-to-video pipeline if it is single-frame? i.e. an image?
There was a problem hiding this comment.
I don’t know honestly. I tried to follow the original implementation (i.e., the implementation before the refactor) as faithfully as possible.
From the documentation though, it seems like it supports multi-frame videos too:
https://huggingface.co/docs/diffusers/en/api/pipelines/animatediff
So, my best guess is that it supports both — single-frame video and multi-frame video.
| # as a list of images | ||
| if video and not isinstance(video[0], list): | ||
| video = [video] | ||
| if latents is None: |
There was a problem hiding this comment.
maybe raise an error in check_inputs when both latents and video is not None
There was a problem hiding this comment.
Already there:
|
@yiyixuxu could you look into the failing test? It's likely coming from image processor. But if not, let me know. |
@sayakpaul can confirm that test failure is due to image processor, I will fix it! |
|
@yiyixuxu I think I have addressed your comments. LMK if this is good to merge. |
|
i left one comment https://github.com/huggingface/diffusers/pull/7776/files#r1597075529 |
Okay. I will delete the block that listifies a single image. |
|
feel free to merge once the tests pass :) |
* introduce videoprocessor. * fix quality * address yiyi's feedback * fix preprocess_video call. * video_processor -> image_processor * fix * fix more. * quality * image_processor -> video_processor * support List[List[PIL.Image.Image]] * change to video_processor. * documentation * Apply suggestions from code review * changes * remove print. * refactor video processor (part # 7776) (#7861) * update * update remove deprecate * Update src/diffusers/video_processor.py * update * Apply suggestions from code review * deprecate list of 5d for video and list of 4d for image + apply other feedbacks * up --------- Co-authored-by: Sayak Paul <spsayakpaul@gmail.com> * add doc. * tensor2vid -> postprocess_video. * refactor preprocess with preprocess_video * set default values. * empty commit * more refactoring of prepare_latents in animatediff vid2vid * checking documentation * remove documentation for now. * fix animatediff sdxl * fix test failure [part of video processor PR] (#7905) up * remove preceed_with_frames. * doc * fix * fix * remove video input as a single-frame video. --------- Co-authored-by: YiYi Xu <yixu310@gmail.com>
What does this PR do?
Introduces a
VideoProcessorakin toVaeImageProcessorto encapsulate the logic of dealing with videos.TODOs