Apply Generative Perturbations#

Warning

DiffusionPerturber is an experimental feature. Its API and behavior may change in future releases. GPU resources and large model downloads are required; it is not recommended for production use without thorough validation. In particular, bounding box correctness is not guaranteed.

This notebook demonstrates how to apply generative perturbations using diffusion models. Generative perturbers use pre-trained deep learning models to synthesize realistic modifications to images based on text prompts.

We use a sample image from the VisDrone dataset to demonstrate diffusion-based perturbations.

To run this notebook in Colab, use the link below:

Open In Colab

Set Up the Environment#

Note

We are suppressing warnings within this notebook to reduce visual clutter for demonstration purposes. If any issues arise while executing this notebook, we recommend that this cell is not executed so that any related warnings are shown.

import warnings

warnings.filterwarnings("ignore")

Important

This notebook requires NRTK with the following extra(s):

  • diffusion: Diffusion model dependencies for AI-powered generative perturbations

The next cell will install these extra(s). See Installation for alternatives.

Tip

The first time you run a diffusion perturber, it will download a pre-trained model (several gigabytes). Using a GPU is strongly recommended for performance.

%pip install -qU pip
print("Installing nrtk with required extras...")
%pip install -q "nrtk[diffusion]"
print("Installing notebook-specific packages...")
%pip install -q matplotlib
print("Done!")

from nrtk.utils._extras import print_extras_status  # noqa: E402 - intentionally after %pip install

print_extras_status()
Note: you may need to restart the kernel to use updated packages.
Installing nrtk with required extras...
Note: you may need to restart the kernel to use updated packages.
Installing notebook-specific packages...
Note: you may need to restart the kernel to use updated packages.
Done!
Detected status of NRTK extras and their dependencies:
[albumentations]
  - nrtk-albumentations       ✗ missing

[diffusion]
  - torch                     ✓ 2.11.0
  - diffusers                 ✓ 0.37.1
  - accelerate                ✓ 1.13.0
  - Pillow                    ✓ 12.2.0
  - transformers              ✓ 5.6.2
  - protobuf                  ✗ missing

[graphics]
  - opencv-python             ✗ missing

[headless]
  - opencv-python-headless    ✗ missing

[maite]
  - maite                     ✗ missing

[pillow]
  - Pillow                    ✓ 12.2.0

[pybsm]
  - pybsm                     ✗ missing

[skimage]
  - scikit-image              ✗ missing

[tools]
  - kwcoco                    ✗ missing
  - Pillow                    ✓ 12.2.0
  - click                     ✓ 8.3.3
  - fastapi                   ✗ missing
  - uvicorn                   ✗ missing
  - pydantic                  ✗ missing
  - pydantic-settings         ✗ missing
  - python-json-logger        ✗ missing

[waterdroplet]
  - scipy                     ✗ missing
  - numba                     ✗ missing


For details about installing NRTK extras, please visit:
    https://nrtk.readthedocs.io/en/stable/

Note

Colab users: After setting up the environment, you may need to “Restart Runtime” to resolve package version conflicts (see the README for more info).

%matplotlib inline
%config InlineBackend.figure_format = "jpeg"  # Use JPEG format for inline visualizations
import os
import urllib.request

import numpy as np
from matplotlib import pyplot as plt
from PIL import Image

from nrtk.impls.perturb_image.generative import DiffusionPerturber  # requires `diffusion` extra

device = "cuda"  # will fallback to cpu if cuda is unavailable
[transformers] `CLIPImageProcessor` requires torchvision (not installed); falling back to `CLIPImageProcessorPil` for backward compatibility. Install torchvision to use the default backend, or import `CLIPImageProcessorPil` directly to silence this warning.
[transformers] `SiglipImageProcessor` requires torchvision (not installed); falling back to `SiglipImageProcessorPil` for backward compatibility. Install torchvision to use the default backend, or import `SiglipImageProcessorPil` directly to silence this warning.

Select Initial Image#

We’ll carry out perturbations on a single image from VisDrone

data_dir = "./data"
os.makedirs(data_dir, exist_ok=True)

url = "https://data.kitware.com/api/v1/item/623880f14acac99f429fe3ca/download"
img_path = os.path.join(data_dir, "visdrone_img.jpg")
if not os.path.isfile(img_path):
    print("Downloading image...")
    _ = urllib.request.urlretrieve(url, img_path)

# Load image with PIL
img_pil = Image.open(img_path)

img_pil
../_images/2ba4e1dc3e4f7fe7719e300bdf73afb64c313138dcd5669f25de71637eb25fe6.png

Resize Image#

The diffusion perturber expects a resized image, so we will resize the image

def resize_image_for_diffusion(img_to_resize: Image.Image) -> Image.Image:
    """Resize image using the same logic as DiffusionPerturber._resize_image."""
    original_w, original_h = img_to_resize.size
    min_dimension = 256

    # Scale image down to the minimum dimension
    scale = min_dimension / min(original_w, original_h)
    new_w = int(original_w * scale)
    new_h = int(original_h * scale)

    # Round to the nearest multiple of 8 (required by the diffusion model)
    new_w = round(new_w / 8) * 8
    new_h = round(new_h / 8) * 8

    # Lanczos resampling improves image quality
    return img_to_resize.resize((new_w, new_h), Image.Resampling.LANCZOS)


# Resize the loaded image
img_pil_resized = resize_image_for_diffusion(img_pil)

print(f"Original image size: {img_pil.size}")
print(f"Resized image size: {img_pil_resized.size}")

img_resized_rgb = np.asarray(img_pil_resized)

# Display the resized image
plt.figure(figsize=(8, 8))
plt.axis("off")
plt.title("Resized Image")
_ = plt.imshow(img_resized_rgb)
plt.show()
Original image size: (960, 540)
Resized image size: (456, 256)
../_images/a8142fb7eda3e2e432e33694d2b44230c8c7ea18209a7c66062a559d744a1b6f.jpg

NRTK Diffusion Perturbation: Examples and Guidance#

The DiffusionPerturber uses powerful, pre-trained diffusion models to apply complex, realistic perturbations based on text prompts. By default, it uses a model from the Instruct-Pix2Pix family, which excels at editing images based on text instructions.

The perturber is configured by the following key parameters:

  • prompt: A natural language description of the desired change. This is the most important parameter for controlling the visual output. Examples include “add heavy rain”, “make it look like a winter scene”, or “change the time to night”.

  • model_name: The specific pre-trained model to use from the Hugging Face Hub. The default is "timbrooks/instruct-pix2pix".

  • seed: An integer to ensure that the “random” aspects of the diffusion process are reproducible.

  • num_inference_steps: The number of denoising steps in the diffusion process. Higher values can lead to higher quality results but increase computation time. Default is 50.

  • text_guidance_scale: Controls how much the model’s output is influenced by the text prompt. Higher values mean the model adheres more strictly to the prompt. Default is 8.0.

  • image_guidance_scale: Controls how much the model’s output preserves the structure of the original input image. Higher values mean more of the original image is retained. Default is 2.0.

  • device: Specifies the computation device ("cuda" or "cpu"). Using "cuda" is strongly recommended for performance. If not specified, it will auto-detect a GPU but fall back to CPU if one is not available.

Important Notes for this Notebook:

  • Performance: Diffusion models are computationally intensive. The first time you use the perturber, it will download the model (which can be several gigabytes). Running on a CPU will be significantly slower than on a GPU.

  • Focus: For this notebook, we will primarily change the prompt to generate different visual effects. We will keep the other parameters at their default values to demonstrate the core functionality.

  • Image Resizing: The input image is automatically resized to be compatible with the diffusion model’s expected input dimensions. This means the output image from the perturber will have different dimensions than the input image.

Generated Perturbed Image#

This is a helper function that contains logic to generate an perturbed image and plot it.

def generate_perturbed_image(
    prompt_text: str,
    input_image: np.ndarray,
    seed: int = 42,
    device: str | None = None,
) -> plt.Figure:
    """Generates a perturbed image based on a text prompt using DiffusionPerturber.

    Args:
        prompt_text (str): The text prompt to guide the perturbation.
        input_image (np.ndarray): The input image to be perturbed.
        seed (int): The random seed for reproducibility.
        device (str | None): The device to run the model on. None for auto-detection.

    Returns:
        plt.Figure: The matplotlib figure containing the perturbed image.
    """
    perturber = DiffusionPerturber(prompt=prompt_text, seed=seed, device=device)
    perturbed_img, _ = perturber(image=input_image)
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.imshow(perturbed_img)
    ax.axis("off")
    ax.set_title(prompt_text)
    return fig

Add smog to the image#

This prompt causes the diffusion model to add smog to the image

prompt = "add smog to the image"

img1 = generate_perturbed_image(prompt, img_resized_rgb)
  0%|                                                                                                     | 0/50 [00:00<?, ?it/s]
  2%|█▊                                                                                           | 1/50 [00:03<02:30,  3.07s/it]
  4%|███▋                                                                                         | 2/50 [00:05<02:17,  2.87s/it]
  6%|█████▌                                                                                       | 3/50 [00:08<02:12,  2.81s/it]
  8%|███████▍                                                                                     | 4/50 [00:11<02:08,  2.79s/it]
 10%|█████████▎                                                                                   | 5/50 [00:14<02:05,  2.78s/it]
 12%|███████████▏                                                                                 | 6/50 [00:16<02:02,  2.79s/it]
 14%|█████████████                                                                                | 7/50 [00:19<02:00,  2.80s/it]
 16%|██████████████▉                                                                              | 8/50 [00:22<01:57,  2.80s/it]
 18%|████████████████▋                                                                            | 9/50 [00:25<01:54,  2.80s/it]
 20%|██████████████████▍                                                                         | 10/50 [00:28<01:52,  2.80s/it]
 22%|████████████████████▏                                                                       | 11/50 [00:30<01:50,  2.83s/it]
 24%|██████████████████████                                                                      | 12/50 [00:33<01:49,  2.88s/it]
 26%|███████████████████████▉                                                                    | 13/50 [00:36<01:47,  2.91s/it]
 28%|█████████████████████████▊                                                                  | 14/50 [00:39<01:45,  2.93s/it]
 30%|███████████████████████████▌                                                                | 15/50 [00:42<01:42,  2.93s/it]
 32%|█████████████████████████████▍                                                              | 16/50 [00:45<01:40,  2.95s/it]
 34%|███████████████████████████████▎                                                            | 17/50 [00:48<01:37,  2.94s/it]
 36%|█████████████████████████████████                                                           | 18/50 [00:51<01:33,  2.94s/it]
 38%|██████████████████████████████████▉                                                         | 19/50 [00:54<01:30,  2.93s/it]
 40%|████████████████████████████████████▊                                                       | 20/50 [00:57<01:27,  2.93s/it]
 42%|██████████████████████████████████████▋                                                     | 21/50 [01:00<01:25,  2.93s/it]
 44%|████████████████████████████████████████▍                                                   | 22/50 [01:03<01:22,  2.95s/it]
 46%|██████████████████████████████████████████▎                                                 | 23/50 [01:06<01:19,  2.95s/it]
 48%|████████████████████████████████████████████▏                                               | 24/50 [01:09<01:16,  2.94s/it]
 50%|██████████████████████████████████████████████                                              | 25/50 [01:12<01:13,  2.94s/it]
 52%|███████████████████████████████████████████████▊                                            | 26/50 [01:15<01:10,  2.95s/it]
 54%|█████████████████████████████████████████████████▋                                          | 27/50 [01:18<01:07,  2.94s/it]
 56%|███████████████████████████████████████████████████▌                                        | 28/50 [01:21<01:05,  2.96s/it]
 58%|█████████████████████████████████████████████████████▎                                      | 29/50 [01:24<01:02,  2.96s/it]
 60%|███████████████████████████████████████████████████████▏                                    | 30/50 [01:27<00:59,  2.96s/it]
 62%|█████████████████████████████████████████████████████████                                   | 31/50 [01:30<00:56,  2.95s/it]
 64%|██████████████████████████████████████████████████████████▉                                 | 32/50 [01:33<00:53,  2.98s/it]
 66%|████████████████████████████████████████████████████████████▋                               | 33/50 [01:36<00:50,  2.99s/it]
 68%|██████████████████████████████████████████████████████████████▌                             | 34/50 [01:39<00:48,  3.01s/it]
 70%|████████████████████████████████████████████████████████████████▍                           | 35/50 [01:42<00:44,  2.98s/it]
 72%|██████████████████████████████████████████████████████████████████▏                         | 36/50 [01:45<00:41,  2.98s/it]
 74%|████████████████████████████████████████████████████████████████████                        | 37/50 [01:48<00:39,  3.01s/it]
 76%|█████████████████████████████████████████████████████████████████████▉                      | 38/50 [01:51<00:36,  3.03s/it]
 78%|███████████████████████████████████████████████████████████████████████▊                    | 39/50 [01:54<00:33,  3.01s/it]
 80%|█████████████████████████████████████████████████████████████████████████▌                  | 40/50 [01:57<00:29,  2.99s/it]
 82%|███████████████████████████████████████████████████████████████████████████▍                | 41/50 [02:00<00:27,  3.01s/it]
 84%|█████████████████████████████████████████████████████████████████████████████▎              | 42/50 [02:03<00:23,  3.00s/it]
 86%|███████████████████████████████████████████████████████████████████████████████             | 43/50 [02:06<00:21,  3.04s/it]
 88%|████████████████████████████████████████████████████████████████████████████████▉           | 44/50 [02:09<00:17,  3.00s/it]
 90%|██████████████████████████████████████████████████████████████████████████████████▊         | 45/50 [02:12<00:15,  3.01s/it]
 92%|████████████████████████████████████████████████████████████████████████████████████▋       | 46/50 [02:15<00:12,  3.04s/it]
 94%|██████████████████████████████████████████████████████████████████████████████████████▍     | 47/50 [02:18<00:09,  3.05s/it]
 96%|████████████████████████████████████████████████████████████████████████████████████████▎   | 48/50 [02:21<00:06,  3.05s/it]
 98%|██████████████████████████████████████████████████████████████████████████████████████████▏ | 49/50 [02:24<00:03,  3.05s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:27<00:00,  3.05s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:27<00:00,  2.95s/it]

../_images/ec77115de13cb30ba4dd31b908865ebd08daee0bb2494ef85c4500cfc7304ac8.jpg

Turn the image into night#

This prompt causes the diffusion model to take the daytime image and make it a night scene

prompt = "turn the image into night"

img2 = generate_perturbed_image(prompt, img_resized_rgb, device="cuda")
Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
  0%|                                                                                                     | 0/50 [00:00<?, ?it/s]
  2%|█▊                                                                                           | 1/50 [00:02<02:15,  2.77s/it]
  4%|███▋                                                                                         | 2/50 [00:05<02:15,  2.81s/it]
  6%|█████▌                                                                                       | 3/50 [00:08<02:11,  2.80s/it]
  8%|███████▍                                                                                     | 4/50 [00:11<02:09,  2.80s/it]
 10%|█████████▎                                                                                   | 5/50 [00:13<02:05,  2.80s/it]
 12%|███████████▏                                                                                 | 6/50 [00:16<02:03,  2.80s/it]
 14%|█████████████                                                                                | 7/50 [00:19<02:00,  2.81s/it]
 16%|██████████████▉                                                                              | 8/50 [00:22<01:58,  2.81s/it]
 18%|████████████████▋                                                                            | 9/50 [00:25<01:55,  2.81s/it]
 20%|██████████████████▍                                                                         | 10/50 [00:28<01:52,  2.81s/it]
 22%|████████████████████▏                                                                       | 11/50 [00:30<01:49,  2.82s/it]
 24%|██████████████████████                                                                      | 12/50 [00:33<01:47,  2.83s/it]
 26%|███████████████████████▉                                                                    | 13/50 [00:36<01:48,  2.93s/it]
 28%|█████████████████████████▊                                                                  | 14/50 [00:39<01:44,  2.91s/it]
 30%|███████████████████████████▌                                                                | 15/50 [00:42<01:42,  2.93s/it]
 32%|█████████████████████████████▍                                                              | 16/50 [00:45<01:38,  2.91s/it]
 34%|███████████████████████████████▎                                                            | 17/50 [00:48<01:35,  2.89s/it]
 36%|█████████████████████████████████                                                           | 18/50 [00:51<01:31,  2.87s/it]
 38%|██████████████████████████████████▉                                                         | 19/50 [00:54<01:29,  2.88s/it]
 40%|████████████████████████████████████▊                                                       | 20/50 [00:57<01:26,  2.89s/it]
 42%|██████████████████████████████████████▋                                                     | 21/50 [01:00<01:24,  2.90s/it]
 44%|████████████████████████████████████████▍                                                   | 22/50 [01:02<01:20,  2.89s/it]
 46%|██████████████████████████████████████████▎                                                 | 23/50 [01:05<01:18,  2.92s/it]
 48%|████████████████████████████████████████████▏                                               | 24/50 [01:08<01:15,  2.89s/it]
 50%|██████████████████████████████████████████████                                              | 25/50 [01:11<01:11,  2.87s/it]
 52%|███████████████████████████████████████████████▊                                            | 26/50 [01:14<01:08,  2.87s/it]
 54%|█████████████████████████████████████████████████▋                                          | 27/50 [01:17<01:06,  2.88s/it]
 56%|███████████████████████████████████████████████████▌                                        | 28/50 [01:20<01:04,  2.93s/it]
 58%|█████████████████████████████████████████████████████▎                                      | 29/50 [01:23<01:00,  2.90s/it]
 60%|███████████████████████████████████████████████████████▏                                    | 30/50 [01:26<00:57,  2.89s/it]
 62%|█████████████████████████████████████████████████████████                                   | 31/50 [01:28<00:54,  2.86s/it]
 64%|██████████████████████████████████████████████████████████▉                                 | 32/50 [01:31<00:51,  2.85s/it]
 66%|████████████████████████████████████████████████████████████▋                               | 33/50 [01:34<00:48,  2.85s/it]
 68%|██████████████████████████████████████████████████████████████▌                             | 34/50 [01:37<00:45,  2.84s/it]
 70%|████████████████████████████████████████████████████████████████▍                           | 35/50 [01:40<00:42,  2.83s/it]
 72%|██████████████████████████████████████████████████████████████████▏                         | 36/50 [01:42<00:39,  2.83s/it]
 74%|████████████████████████████████████████████████████████████████████                        | 37/50 [01:45<00:36,  2.83s/it]
 76%|█████████████████████████████████████████████████████████████████████▉                      | 38/50 [01:48<00:33,  2.81s/it]
 78%|███████████████████████████████████████████████████████████████████████▊                    | 39/50 [01:51<00:30,  2.82s/it]
 80%|█████████████████████████████████████████████████████████████████████████▌                  | 40/50 [01:54<00:28,  2.80s/it]
 82%|███████████████████████████████████████████████████████████████████████████▍                | 41/50 [01:56<00:25,  2.80s/it]
 84%|█████████████████████████████████████████████████████████████████████████████▎              | 42/50 [01:59<00:22,  2.80s/it]
 86%|███████████████████████████████████████████████████████████████████████████████             | 43/50 [02:02<00:19,  2.80s/it]
 88%|████████████████████████████████████████████████████████████████████████████████▉           | 44/50 [02:05<00:17,  2.86s/it]
 90%|██████████████████████████████████████████████████████████████████████████████████▊         | 45/50 [02:08<00:14,  2.85s/it]
 92%|████████████████████████████████████████████████████████████████████████████████████▋       | 46/50 [02:11<00:11,  2.85s/it]
 94%|██████████████████████████████████████████████████████████████████████████████████████▍     | 47/50 [02:14<00:08,  2.84s/it]
 96%|████████████████████████████████████████████████████████████████████████████████████████▎   | 48/50 [02:17<00:05,  2.89s/it]
 98%|██████████████████████████████████████████████████████████████████████████████████████████▏ | 49/50 [02:20<00:02,  2.94s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:23<00:00,  2.98s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:23<00:00,  2.86s/it]

../_images/db683c5f17455f6b06b3146b1e90b2b645af7d57f0dfa6daaf2c5f8c192aeeec.jpg

Add snow on the ground#

This prompt causes the diffusion model to add a light layer of snow on the ground

prompt = "add snow on the ground"

img3 = generate_perturbed_image(prompt, img_resized_rgb)
  0%|                                                                                                     | 0/50 [00:00<?, ?it/s]
  2%|█▊                                                                                           | 1/50 [00:04<03:20,  4.09s/it]
  4%|███▋                                                                                         | 2/50 [00:08<03:19,  4.15s/it]
  6%|█████▌                                                                                       | 3/50 [00:11<02:45,  3.53s/it]
  8%|███████▍                                                                                     | 4/50 [00:13<02:29,  3.25s/it]
 10%|█████████▎                                                                                   | 5/50 [00:16<02:19,  3.09s/it]
 12%|███████████▏                                                                                 | 6/50 [00:19<02:11,  2.99s/it]
 14%|█████████████                                                                                | 7/50 [00:22<02:06,  2.94s/it]
 16%|██████████████▉                                                                              | 8/50 [00:25<02:01,  2.89s/it]
 18%|████████████████▋                                                                            | 9/50 [00:27<01:57,  2.88s/it]
 20%|██████████████████▍                                                                         | 10/50 [00:30<01:54,  2.86s/it]
 22%|████████████████████▏                                                                       | 11/50 [00:33<01:50,  2.84s/it]
 24%|██████████████████████                                                                      | 12/50 [00:36<01:47,  2.84s/it]
 26%|███████████████████████▉                                                                    | 13/50 [00:39<01:44,  2.83s/it]
 28%|█████████████████████████▊                                                                  | 14/50 [00:42<01:42,  2.83s/it]
 30%|███████████████████████████▌                                                                | 15/50 [00:44<01:39,  2.83s/it]
 32%|█████████████████████████████▍                                                              | 16/50 [00:47<01:35,  2.82s/it]
 34%|███████████████████████████████▎                                                            | 17/50 [00:50<01:32,  2.81s/it]
 36%|█████████████████████████████████                                                           | 18/50 [00:53<01:30,  2.82s/it]
 38%|██████████████████████████████████▉                                                         | 19/50 [00:56<01:27,  2.82s/it]
 40%|████████████████████████████████████▊                                                       | 20/50 [00:58<01:24,  2.82s/it]
 42%|██████████████████████████████████████▋                                                     | 21/50 [01:01<01:22,  2.84s/it]
 44%|████████████████████████████████████████▍                                                   | 22/50 [01:04<01:19,  2.84s/it]
 46%|██████████████████████████████████████████▎                                                 | 23/50 [01:07<01:16,  2.84s/it]
 48%|████████████████████████████████████████████▏                                               | 24/50 [01:10<01:13,  2.84s/it]
 50%|██████████████████████████████████████████████                                              | 25/50 [01:13<01:10,  2.84s/it]
 52%|███████████████████████████████████████████████▊                                            | 26/50 [01:16<01:08,  2.84s/it]
 54%|█████████████████████████████████████████████████▋                                          | 27/50 [01:18<01:05,  2.83s/it]
 56%|███████████████████████████████████████████████████▌                                        | 28/50 [01:21<01:02,  2.82s/it]
 58%|█████████████████████████████████████████████████████▎                                      | 29/50 [01:24<00:59,  2.83s/it]
 60%|███████████████████████████████████████████████████████▏                                    | 30/50 [01:27<00:57,  2.85s/it]
 62%|█████████████████████████████████████████████████████████                                   | 31/50 [01:33<01:11,  3.78s/it]
 64%|██████████████████████████████████████████████████████████▉                                 | 32/50 [01:40<01:24,  4.68s/it]
 66%|████████████████████████████████████████████████████████████▋                               | 33/50 [01:44<01:20,  4.71s/it]
 68%|██████████████████████████████████████████████████████████████▌                             | 34/50 [01:47<01:06,  4.13s/it]
 70%|████████████████████████████████████████████████████████████████▍                           | 35/50 [01:50<00:55,  3.72s/it]
 72%|██████████████████████████████████████████████████████████████████▏                         | 36/50 [01:53<00:47,  3.43s/it]
 74%|████████████████████████████████████████████████████████████████████                        | 37/50 [01:55<00:41,  3.23s/it]
 76%|█████████████████████████████████████████████████████████████████████▉                      | 38/50 [01:58<00:37,  3.09s/it]
 78%|███████████████████████████████████████████████████████████████████████▊                    | 39/50 [02:01<00:33,  3.00s/it]
 80%|█████████████████████████████████████████████████████████████████████████▌                  | 40/50 [02:04<00:29,  2.95s/it]
 82%|███████████████████████████████████████████████████████████████████████████▍                | 41/50 [02:07<00:26,  2.91s/it]
 84%|█████████████████████████████████████████████████████████████████████████████▎              | 42/50 [02:09<00:23,  2.88s/it]
 86%|███████████████████████████████████████████████████████████████████████████████             | 43/50 [02:12<00:20,  2.86s/it]
 88%|████████████████████████████████████████████████████████████████████████████████▉           | 44/50 [02:15<00:17,  2.86s/it]
 90%|██████████████████████████████████████████████████████████████████████████████████▊         | 45/50 [02:18<00:14,  2.92s/it]
 92%|████████████████████████████████████████████████████████████████████████████████████▋       | 46/50 [02:21<00:11,  2.89s/it]
 94%|██████████████████████████████████████████████████████████████████████████████████████▍     | 47/50 [02:24<00:08,  2.86s/it]
 96%|████████████████████████████████████████████████████████████████████████████████████████▎   | 48/50 [02:27<00:05,  2.86s/it]
 98%|██████████████████████████████████████████████████████████████████████████████████████████▏ | 49/50 [02:30<00:02,  2.85s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:32<00:00,  2.84s/it]
100%|████████████████████████████████████████████████████████████████████████████████████████████| 50/50 [02:32<00:00,  3.06s/it]

../_images/3085f6c946b3863ae53cda5f6eaf0ff883460c1d308876fcf6872054e1edac98.jpg