|
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | | -import unittest |
16 | 15 |
|
| 16 | +import pytest |
17 | 17 | import torch |
18 | 18 | from PIL import Image |
19 | 19 | from transformers import AutoConfig, AutoTokenizer, T5EncoderModel |
20 | 20 |
|
21 | 21 | from diffusers import AutoencoderKLWan, UniPCMultistepScheduler, WanTransformer3DModel, WanVideoToVideoPipeline |
22 | 22 |
|
23 | | -from ...testing_utils import ( |
24 | | - enable_full_determinism, |
25 | | -) |
26 | | -from ..pipeline_params import TEXT_TO_IMAGE_IMAGE_PARAMS, TEXT_TO_IMAGE_PARAMS |
27 | | -from ..test_pipelines_common import ( |
28 | | - PipelineTesterMixin, |
29 | | -) |
| 23 | +from ..testing_utils import BasePipelineTesterConfig, MemoryTesterMixin, PipelineTesterMixin |
30 | 24 |
|
31 | 25 |
|
32 | | -enable_full_determinism() |
33 | | - |
34 | | - |
35 | | -class WanVideoToVideoPipelineFastTests(PipelineTesterMixin, unittest.TestCase): |
| 26 | +class WanVideoToVideoPipelineTesterConfig(BasePipelineTesterConfig): |
36 | 27 | pipeline_class = WanVideoToVideoPipeline |
37 | | - params = TEXT_TO_IMAGE_PARAMS - {"cross_attention_kwargs"} |
38 | | - batch_params = frozenset(["video", "prompt", "negative_prompt"]) |
39 | | - image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS |
40 | | - required_optional_params = frozenset( |
41 | | - [ |
42 | | - "num_inference_steps", |
43 | | - "generator", |
44 | | - "latents", |
45 | | - "return_dict", |
46 | | - "callback_on_step_end", |
47 | | - "callback_on_step_end_tensor_inputs", |
48 | | - ] |
| 28 | + required_input_params_in_call_signature = frozenset( |
| 29 | + ["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"] |
| 30 | + ) |
| 31 | + batch_input_params = frozenset(["prompt", "video"]) |
| 32 | + # Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`. |
| 33 | + optional_input_params = frozenset( |
| 34 | + ["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"] |
49 | 35 | ) |
50 | | - test_xformers_attention = False |
51 | 36 |
|
52 | 37 | def get_dummy_components(self): |
53 | 38 | torch.manual_seed(0) |
@@ -81,69 +66,61 @@ def get_dummy_components(self): |
81 | 66 | rope_max_seq_len=32, |
82 | 67 | ) |
83 | 68 |
|
84 | | - components = { |
| 69 | + return { |
85 | 70 | "transformer": transformer, |
86 | 71 | "vae": vae, |
87 | 72 | "scheduler": scheduler, |
88 | 73 | "text_encoder": text_encoder, |
89 | 74 | "tokenizer": tokenizer, |
90 | 75 | } |
91 | | - return components |
92 | | - |
93 | | - def get_dummy_inputs(self, device, seed=0): |
94 | | - if str(device).startswith("mps"): |
95 | | - generator = torch.manual_seed(seed) |
96 | | - else: |
97 | | - generator = torch.Generator(device=device).manual_seed(seed) |
98 | 76 |
|
| 77 | + def get_dummy_inputs(self): |
99 | 78 | video = [Image.new("RGB", (16, 16))] * 17 |
100 | | - inputs = { |
| 79 | + return { |
101 | 80 | "video": video, |
102 | 81 | "prompt": "dance monkey", |
103 | 82 | "negative_prompt": "negative", # TODO |
104 | | - "generator": generator, |
| 83 | + "generator": self.get_generator(0), |
105 | 84 | "num_inference_steps": 4, |
106 | 85 | "guidance_scale": 6.0, |
107 | 86 | "height": 16, |
108 | 87 | "width": 16, |
109 | 88 | "max_sequence_length": 16, |
| 89 | + # Request torch outputs so tests compare torch tensors directly (see `BasePipelineTesterConfig`). |
110 | 90 | "output_type": "pt", |
111 | 91 | } |
112 | | - return inputs |
113 | 92 |
|
114 | | - def test_inference(self): |
115 | | - device = "cpu" |
116 | 93 |
|
117 | | - components = self.get_dummy_components() |
118 | | - pipe = self.pipeline_class(**components) |
119 | | - pipe.to(device) |
120 | | - pipe.set_progress_bar_config(disable=None) |
| 94 | +class TestWanVideoToVideoPipeline(WanVideoToVideoPipelineTesterConfig, PipelineTesterMixin): |
| 95 | + def test_inference(self): |
| 96 | + # Run on CPU: the expected slice below is CPU-specific. |
| 97 | + pipe = self.get_pipeline() |
121 | 98 |
|
122 | | - inputs = self.get_dummy_inputs(device) |
| 99 | + inputs = self.get_dummy_inputs() |
123 | 100 | video = pipe(**inputs).frames |
124 | 101 | generated_video = video[0] |
125 | | - self.assertEqual(generated_video.shape, (17, 3, 16, 16)) |
| 102 | + assert generated_video.shape == (17, 3, 16, 16) |
126 | 103 |
|
127 | 104 | # fmt: off |
128 | 105 | expected_slice = torch.tensor([0.4522, 0.4534, 0.4532, 0.4553, 0.4526, 0.4538, 0.4533, 0.4547, 0.513, 0.5176, 0.5286, 0.4958, 0.4955, 0.5381, 0.5154, 0.5195]) |
129 | | - # fmt:on |
| 106 | + # fmt: on |
130 | 107 |
|
131 | 108 | generated_slice = generated_video.flatten() |
132 | 109 | generated_slice = torch.cat([generated_slice[:8], generated_slice[-8:]]) |
133 | | - self.assertTrue(torch.allclose(generated_slice, expected_slice, atol=1e-3)) |
134 | | - |
135 | | - @unittest.skip("Test not supported") |
136 | | - def test_attention_slicing_forward_pass(self): |
137 | | - pass |
| 110 | + assert torch.allclose(generated_slice, expected_slice, atol=1e-3) |
138 | 111 |
|
139 | | - @unittest.skip( |
140 | | - "WanVideoToVideoPipeline has to run in mixed precision. Casting the entire pipeline will result in errors" |
| 112 | + @pytest.mark.skip( |
| 113 | + reason="WanVideoToVideoPipeline has to run in mixed precision. Casting the entire pipeline will result in errors" |
141 | 114 | ) |
142 | | - def test_float16_inference(self): |
| 115 | + def test_half_precision_inference_no_nan(self): |
143 | 116 | pass |
144 | 117 |
|
145 | | - @unittest.skip( |
146 | | - "WanVideoToVideoPipeline has to run in mixed precision. Save/Load the entire pipeline in FP16 will result in errors" |
| 118 | + @pytest.mark.skip( |
| 119 | + reason="WanVideoToVideoPipeline has to run in mixed precision. Save/Load the entire pipeline in FP16 will result in errors" |
147 | 120 | ) |
148 | 121 | def test_save_load_float16(self): |
149 | 122 | pass |
| 123 | + |
| 124 | + |
| 125 | +class TestWanVideoToVideoPipelineMemory(WanVideoToVideoPipelineTesterConfig, MemoryTesterMixin): |
| 126 | + pass |
0 commit comments