Skip to content
1 change: 1 addition & 0 deletions .ai/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Follow the style introduced in [#14113](https://github.com/huggingface/diffusers
- **These are pytest-style, not `unittest`** — no `unittest.TestCase` subclassing, no `setUp`/`tearDown` (a `cleanup` fixture handles VRAM), and skips use `pytest.skip` / `@pytest.mark.skip`, never `@unittest.skip`. Fixtures like `tmp_path` and the cached `base_pipe_output` are injected into test methods as arguments.
- **Define one config class**, `<Pipeline>PipelineTesterConfig`, subclassing `BasePipelineTesterConfig` (from `..testing_utils`). It holds the whole testing contract and performs no assertions:
- Set `pipeline_class`, `required_input_params_in_call_signature` (params that must appear in `__call__`'s signature), and `batch_input_params` (params that get batched). Use the canonical sets in `..pipeline_params` where one fits, or an inline `frozenset([...])`.
- Set `output_shape` — the per-sample output shape for `get_dummy_inputs()`, i.e. `(channels, height, width)` for an image pipeline and `(num_frames, channels, height, width)` for a video one. Assert against `self.output_shape` in pipeline-specific tests instead of repeating the literal.
- Implement `get_dummy_components(...)` — build every sub-module from the **real classes** at tiny config, each preceded by `torch.manual_seed(0)`.
- Implement `get_dummy_inputs()` — **no `device` / `seed` arguments** (unlike the old style). Use `self.get_generator(0)` for the generator, keep sizes tiny, and set `output_type="pt"` so tests compare torch tensors directly with `assert_tensors_close` (no numpy round-trip). Remember `"pt"` images are `(batch, channels, height, width)`.
- **Compose the config with one mixin per concern**, one test class each, named `Test<Pipeline>...`. Add only the mixins that apply:
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/cogvideo/test_cogvideox.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class CogVideoXPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (8, 3, 16, 16)
# CogVideoX is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -134,7 +135,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (8, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4370, 0.3687, 0.3268, 0.3554, 0.3712, 0.3622, 0.3604, 0.3981, 0.5380, 0.5220, 0.5235, 0.5247, 0.5405, 0.5487, 0.5489, 0.5326])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/cogvideo/test_cogvideox_fun_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class CogVideoXFunControlPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt", "control_video"])
output_shape = (8, 3, 16, 16)
# CogVideoX is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -128,7 +129,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (8, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5921, 0.6076, 0.6015, 0.6024, 0.6140, 0.5966, 0.5870, 0.6079, 0.5049, 0.5086, 0.4891, 0.4783, 0.4770, 0.4738, 0.4537, 0.4508])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/cogvideo/test_cogvideox_image2video.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class CogVideoXImageToVideoPipelineTesterConfig(BasePipelineTesterConfig):
]
)
batch_input_params = frozenset(["prompt", "image"])
output_shape = (8, 3, 16, 16)
# CogVideoX is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -154,7 +155,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (8, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4367, 0.4802, 0.5403, 0.5509, 0.5595, 0.5698, 0.5206, 0.5207, 0.5930, 0.5178, 0.4597, 0.4430, 0.4488, 0.4766, 0.5003, 0.4865])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/cogvideo/test_cogvideox_video2video.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class CogVideoXVideoToVideoPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt", "video"])
output_shape = (8, 3, 16, 16)
# CogVideoX is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -129,7 +130,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (8, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5644, 0.6029, 0.6017, 0.5937, 0.5991, 0.5907, 0.6141, 0.5340, 0.3184, 0.4219, 0.4406, 0.4330, 0.4692, 0.4547, 0.4562, 0.5092])
Expand Down
1 change: 1 addition & 0 deletions tests/pipelines/flux/test_pipeline_flux.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class FluxPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "height", "width", "guidance_scale", "prompt_embeds", "pooled_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (3, 8, 8)

def get_dummy_components(self, num_layers: int = 1, num_single_layers: int = 1):
torch.manual_seed(0)
Expand Down
1 change: 1 addition & 0 deletions tests/pipelines/flux2/test_pipeline_flux2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Flux2PipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (3, 8, 8)

def get_dummy_components(self, num_layers: int = 1, num_single_layers: int = 1):
torch.manual_seed(0)
Expand Down
1 change: 1 addition & 0 deletions tests/pipelines/flux2/test_pipeline_flux2_klein.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Flux2KleinPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (3, 8, 8)

def get_dummy_components(self, num_layers: int = 1, num_single_layers: int = 1):
torch.manual_seed(0)
Expand Down
1 change: 1 addition & 0 deletions tests/pipelines/flux2/test_pipeline_flux2_klein_inpaint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Flux2KleinInpaintPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "image", "image_reference", "mask_image", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt", "image", "image_reference", "mask_image"])
output_shape = (3, 32, 32)

def get_dummy_components(self, num_layers: int = 1, num_single_layers: int = 1):
torch.manual_seed(0)
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/flux2/test_pipeline_flux2_klein_kv.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Flux2KleinKVPipelineTesterConfig(BasePipelineTesterConfig):
pipeline_class = Flux2KleinKVPipeline
required_input_params_in_call_signature = frozenset(["prompt", "height", "width", "prompt_embeds", "image"])
batch_input_params = frozenset(["prompt"])
output_shape = (3, 8, 8)

def get_dummy_components(self, num_layers: int = 1, num_single_layers: int = 1):
torch.manual_seed(0)
Expand Down Expand Up @@ -164,7 +165,7 @@ def test_without_image(self):
inputs = self.get_dummy_inputs()
del inputs["image"]
image = pipe(**inputs).images
assert image.shape == (1, 3, 8, 8)
assert image.shape == (1, *self.output_shape)

@pytest.mark.skip("Needs to be revisited")
def test_encode_prompt_works_in_isolation(self):
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/qwenimage/test_qwenimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class QwenImagePipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "true_cfg_scale", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (3, 32, 32)

def get_dummy_components(self, num_layers: int = 2):
torch.manual_seed(0)
Expand Down Expand Up @@ -129,7 +130,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5633, 0.6368, 0.6015, 0.5637, 0.5817, 0.5528, 0.5718, 0.6326, 0.4147, 0.3556, 0.5623, 0.4833, 0.4971, 0.5262, 0.4087, 0.5021])
Expand Down
5 changes: 3 additions & 2 deletions tests/pipelines/qwenimage/test_qwenimage_controlnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class QwenImageControlNetPipelineTesterConfig(BasePipelineTesterConfig):
]
)
batch_input_params = frozenset(["prompt", "control_image"])
output_shape = (3, 32, 32)

def get_dummy_components(self):
torch.manual_seed(0)
Expand Down Expand Up @@ -165,7 +166,7 @@ def test_qwen_controlnet(self):
inputs = self.get_dummy_inputs()
image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4726, 0.5549, 0.6324, 0.6548, 0.4968, 0.4639, 0.4749, 0.4898, 0.4725, 0.4645, 0.4435, 0.3339, 0.3400, 0.4630, 0.3879, 0.4406])
Expand All @@ -188,7 +189,7 @@ def test_qwen_controlnet_multicondition(self):

image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.6239, 0.6642, 0.5768, 0.6039, 0.5270, 0.5070, 0.5006, 0.5271, 0.4506, 0.3085, 0.3435, 0.5152, 0.5096, 0.5422, 0.4286, 0.5752])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/qwenimage/test_qwenimage_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class QwenImageEditPipelineTesterConfig(BasePipelineTesterConfig):
["image", "prompt", "negative_prompt", "true_cfg_scale", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt", "image"])
output_shape = (3, 32, 32)

def get_dummy_components(self):
tiny_ckpt_id = "hf-internal-testing/tiny-random-Qwen2VLForConditionalGeneration"
Expand Down Expand Up @@ -134,7 +135,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5637, 0.6341, 0.6001, 0.5620, 0.5794, 0.5498, 0.5757, 0.6389, 0.4174, 0.3597, 0.5649, 0.4894, 0.4969, 0.5255, 0.4083, 0.4986])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/qwenimage/test_qwenimage_edit_plus.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class QwenImageEditPlusPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "true_cfg_scale", "height", "width", "guidance_scale", "prompt_embeds"]
)
batch_input_params = frozenset(["prompt", "image"])
output_shape = (3, 32, 32)

def get_dummy_components(self):
tiny_ckpt_id = "hf-internal-testing/tiny-random-Qwen2VLForConditionalGeneration"
Expand Down Expand Up @@ -131,7 +132,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5640, 0.6339, 0.5997, 0.5607, 0.5799, 0.5496, 0.5760, 0.6393, 0.4172, 0.3595, 0.5655, 0.4896, 0.4971, 0.5255, 0.4088, 0.4987])
Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/qwenimage/test_qwenimage_img2img.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class QwenImageImg2ImgPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "image", "height", "width", "guidance_scale", "true_cfg_scale", "strength"]
)
batch_input_params = frozenset(["prompt", "image"])
output_shape = (3, 32, 32)

def get_dummy_components(self):
torch.manual_seed(0)
Expand Down Expand Up @@ -133,7 +134,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
image = pipe(**inputs).images
generated_image = image[0]
assert generated_image.shape == (3, 32, 32)
assert generated_image.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.5832, 0.6525, 0.5760, 0.5546, 0.5763, 0.5743, 0.4986, 0.4591, 0.4371, 0.4667, 0.4898, 0.3232, 0.4333, 0.5274, 0.4735, 0.4937])
Expand Down
1 change: 1 addition & 0 deletions tests/pipelines/qwenimage/test_qwenimage_inpaint.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class QwenImageInpaintPipelineTesterConfig(BasePipelineTesterConfig):
]
)
batch_input_params = frozenset(["prompt", "image", "mask_image"])
output_shape = (3, 32, 32)

def get_dummy_components(self):
torch.manual_seed(0)
Expand Down
17 changes: 17 additions & 0 deletions tests/pipelines/testing_utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ def callback_cfg_params(self) -> frozenset:
"callback function when dynamically adjusting `guidance_scale`."
)

@property
def output_shape(self) -> tuple:
raise NotImplementedError(
"You need to set the attribute `output_shape` in the child test class. `output_shape` is the expected "
"per-sample shape of the pipeline output for the standard dummy inputs — the shape of a single element "
"of `pipeline(**get_dummy_inputs())[0]` (i.e. with the batch dimension dropped). For an image pipeline "
"requesting `output_type='pt'` it is `(channels, height, width)`; for a video pipeline it is "
"`(num_frames, channels, height, width)`. Analogous to the model-level `BaseModelTesterConfig.output_shape`."
)

# ==================== Shared helpers ====================

def get_generator(self, seed=0):
Expand Down Expand Up @@ -212,6 +222,13 @@ def test_save_load_local(self, tmp_path, base_pipe_output, expected_max_differen
output_loaded, base_pipe_output, atol=expected_max_difference, msg="Loaded pipeline output changed."
)

def test_output(self, base_pipe_output):
output = base_pipe_output
assert output is not None, "Pipeline output is None."
assert output[0].shape == self.output_shape, (
f"Output sample shape does not match expected. Expected {self.output_shape}, got {tuple(output[0].shape)}."
)

def test_pipeline_call_signature(self):
assert hasattr(self.pipeline_class, "__call__"), f"{self.pipeline_class} should have a `__call__` method"

Expand Down
3 changes: 2 additions & 1 deletion tests/pipelines/wan/test_wan.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class WanPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (9, 3, 16, 16)
# Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -99,7 +100,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (9, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4525, 0.452, 0.4485, 0.4534, 0.4524, 0.4529, 0.454, 0.453, 0.5127, 0.5326, 0.5204, 0.5253, 0.5439, 0.5424, 0.5133, 0.5078])
Expand Down
6 changes: 4 additions & 2 deletions tests/pipelines/wan/test_wan_22.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Wan22PipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (9, 3, 16, 16)
# Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -115,7 +116,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (9, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4525, 0.452, 0.4485, 0.4534, 0.4524, 0.4529, 0.454, 0.453, 0.5127, 0.5326, 0.5204, 0.5253, 0.5439, 0.5424, 0.5133, 0.5078])
Expand Down Expand Up @@ -163,6 +164,7 @@ class Wan225BPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (9, 3, 32, 32)
# Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -243,7 +245,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (9, 3, 32, 32)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4814, 0.4298, 0.5094, 0.4289, 0.5061, 0.4301, 0.5043, 0.4284, 0.5375, 0.5965, 0.5527, 0.6014, 0.5228, 0.6076, 0.6644, 0.5651])
Expand Down
6 changes: 4 additions & 2 deletions tests/pipelines/wan/test_wan_22_image_to_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Wan22ImageToVideoPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (9, 3, 16, 16)
# Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -123,7 +124,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (9, 3, 16, 16)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4527, 0.4526, 0.4498, 0.4539, 0.4521, 0.4524, 0.4533, 0.4535, 0.5154, 0.5353, 0.5200, 0.5174, 0.5434, 0.5301, 0.5199, 0.5216])
Expand Down Expand Up @@ -175,6 +176,7 @@ class Wan225BImageToVideoPipelineTesterConfig(BasePipelineTesterConfig):
["prompt", "negative_prompt", "height", "width", "guidance_scale", "prompt_embeds", "negative_prompt_embeds"]
)
batch_input_params = frozenset(["prompt"])
output_shape = (9, 3, 32, 32)
# Wan is a video pipeline: it exposes `num_videos_per_prompt`, not the base default `num_images_per_prompt`.
optional_input_params = frozenset(
["num_inference_steps", "num_videos_per_prompt", "generator", "latents", "output_type", "return_dict"]
Expand Down Expand Up @@ -261,7 +263,7 @@ def test_inference(self):
inputs = self.get_dummy_inputs()
video = pipe(**inputs).frames
generated_video = video[0]
assert generated_video.shape == (9, 3, 32, 32)
assert generated_video.shape == self.output_shape

# fmt: off
expected_slice = torch.tensor([0.4833, 0.4305, 0.5100, 0.4299, 0.5056, 0.4298, 0.5052, 0.4332, 0.5550, 0.6092, 0.5536, 0.5928, 0.5199, 0.5864, 0.6705, 0.5493])
Expand Down
Loading
Loading