Skip to content

Commit

Permalink
Update benchmark (#1792)
Browse files Browse the repository at this point in the history
* Temp commit

* Refactoring

* Benchmark updated to give estimate for slow augmentations

* Refactoring

* Updated Gaussian Noise

* Speedups

* Added info about random to constributors guide

* Min albucore version boosted to 0.0.10

* Updated to work with latest albucore

* updated albucore version

* Updated benchmark

* Update CONTRIBUTING.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Update CONTRIBUTING.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
  • Loading branch information
ternaus and sourcery-ai[bot] committed Jun 17, 2024
1 parent d40477d commit 30ac95e
Show file tree
Hide file tree
Showing 18 changed files with 312 additions and 198 deletions.
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ Even if a parameter defined as `Tuple`, the transform should work correctly with

To maintain determinism and reproducibility, handle all probability calculations within the `get_params` or `get_params_dependent_on_targets` methods. These calculations should not occur in the `apply_xxx` or `__init__` methods, as it is crucial to separate configuration from execution in our codebase.

#### Using Random Number Generators

When you need to use random number generation in your contributions:

* Prefer `random` from the standard library: Use `random` whenever possible as it generally offers faster performance compared to `np.random`.
* Use `random_utils` for functions from `np.random`: When you need specific functionality provided by `np.random`, use the corresponding functions from `albumentations/random_utils.py` to ensure consistency and control over randomness.

By following this approach, we maintain the efficiency and consistency of random operations across the codebase.

### Specific Guidelines for Method Definitions

#### Handling `apply_xxx` Methods
Expand Down
55 changes: 28 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,39 +291,40 @@ The table shows how many images per second can be processed on a single core; hi
| Library | Version |
|---------|---------|
| Python | 3.10.13 (main, Sep 11 2023, 13:44:35) [GCC 11.2.0] |
| albumentations | 1.4.1 |
| albumentations | 1.4.8 |
| imgaug | 0.4.0 |
| torchvision | 0.17.1+rocm5.7 |
| torchvision | 0.18.1+rocm6.0 |
| numpy | 1.26.4 |
| opencv-python-headless | 4.9.0.80 |
| scikit-image | 0.22.0 |
| scipy | 1.12.0 |
| pillow | 10.2.0 |
| opencv-python-headless | 4.10.0.82 |
| scikit-image | 0.23.2 |
| scipy | 1.13.1 |
| pillow | 10.3.0 |
| kornia | 0.7.2 |
| augly | 1.0.0 |

| |albumentations<br><small>1.4.0</small>|torchvision<br><small>0.17.1+rocm5.7</small>|kornia<br><small>0.7.2</small>|augly<br><small>1.0.0</small>|imgaug<br><small>0.4.0</small>|
| |albumentations<br><small>1.4.8</small>|torchvision<br><small>0.18.1+rocm6.0</small>|kornia<br><small>0.7.2</small>|augly<br><small>1.0.0</small>|imgaug<br><small>0.4.0</small>|
|-----------------|--------------------------------------|--------------------------------------------|------------------------------|-----------------------------|------------------------------|
|HorizontalFlip |**9843 ± 2135** |2436 ± 29 |1014 ± 3 |3663 ± 18 |4884 ± 51 |
|VerticalFlip |**9898 ± 18** |2570 ± 37 |1024 ± 4 |5325 ± 13 |8683 ± 5 |
|Rotate |610 ± 4 |153 ± 2 |204 ± 1 |**626 ± 3** |499 ± 5 |
|Affine |**1705 ± 67** |159 ± 1 |200 ± 1 |- |663 ± 24 |
|Equalize |**1061 ± 14** |337 ± 1 |77 ± 1 |- |845 ± 33 |
|RandomCrop64 |**203197 ± 2105** |15931 ± 27 |837 ± 2 |21858 ± 362 |5681 ± 96 |
|RandomResizedCrop|**2998 ± 30** |1160 ± 4 |190 ± 1 |- |- |
|ShiftRGB |1400 ± 3 |- |435 ± 1 |- |**1528 ± 6** |
|Resize |**2581 ± 3** |1239 ± 1 |197 ± 1 |431 ± 1 |1728 ± 1 |
|RandomGamma |**4556 ± 3** |230 ± 1 |205 ± 1 |- |2282 ± 110 |
|Grayscale |**7234 ± 4** |1539 ± 7 |444 ± 3 |2606 ± 2 |918 ± 42 |
|ColorJitter |**452 ± 43** |51 ± 1 |50 ± 1 |221 ± 1 |- |
|RandomPerspective|**465 ± 1** |121 ± 1 |115 ± 1 |- |433 ± 16 |
|GaussianBlur |**2315 ± 9** |106 ± 2 |72 ± 1 |161 ± 1 |1213 ± 3 |
|MedianBlur |**3711 ± 2** |- |2 ± 1 |- |566 ± 3 |
|MotionBlur |**2763 ± 25** |- |101 ± 4 |- |508 ± 2 |
|Posterize |**4238 ± 51** |2581 ± 20 |284 ± 4 |- |1893 ± 9 |
|JpegCompression |208 ± 1 |- |- |**692 ± 4** |435 ± 1 |
|GaussianNoise |64 ± 9 |- |- |67 ± 1 |**212 ± 16** |
|Elastic |**129 ± 1** |3 ± 1 |1 ± 1 |- |128 ± 1 |
|HorizontalFlip |**8084 ± 30** |2422 ± 16 |940 ± 10 |3633 ± 7 |4869 ± 10 |
|VerticalFlip |7330 ± 11 |2541 ± 2 |945 ± 4 |4807 ± 4 |**8400 ± 11** |
|Rotate |535 ± 5 |144 ± 2 |202 ± 1 |**572 ± 2** |494 ± 1 |
|Affine |**1504 ± 46** |153 ± 1 |197 ± 1 |- |671 ± 2 |
|Equalize |1005 ± 1 |328 ± 2 |76 ± 1 |- |**1165 ± 1** |
|RandomCrop64 |20880 ± 170 |15792 ± 23 |833 ± 1 |**21313 ± 603** |5547 ± 2 |
|RandomResizedCrop|**2272 ± 6** |1113 ± 5 |189 ± 1 |- |- |
|ShiftRGB |**1708 ± 2** |- |425 ± 1 |- |1480 ± 11 |
|Resize |**2209 ± 1** |1285 ± 3 |200 ± 1 |430 ± 1 |1690 ± 1 |
|RandomGamma |**3638 ± 7** |229 ± 1 |213 ± 1 |- |2307 ± 3 |
|Grayscale |**7234 ± 4** |1628 ± 6 |447 ± 1 |2535 ± 1 |1052 ± 6 |
|ColorJitter |**438 ± 1** |50 ± 1 |47 ± 1 |214 ± 1 |- |
|RandomPerspective|457 ± 2 |122 ± 1 |115 ± 1 |- |**460 ± 2** |
|GaussianBlur |**2073 ± 1** |110 ± 2 |74 ± 2 |162 ± 1 |1271 ± 1 |
|MedianBlur |536 ± 1 |- |3 ± 0 |- |**564 ± 1** |
|MotionBlur |**2156 ± 8** |- |98 ± 1 |- |503 ± 1 |
|Posterize |**3435 ± 2** |2574 ± 2 |312 ± 9 |- |1894 ± 1 |
|JpegCompression |**805 ± 1** |- |- |679 ± 16 |427 ± 1 |
|GaussianNoise |**239 ± 1** |- |- |67 ± 1 |124 ± 1 |
|Elastic |126 ± 1 |4 ± 0 |1 ± 0 |- |**128 ± 1** |
|Normalize |**1056 ± 1** |429 ± 1 |398 ± 1 |- |- |

## Contributing

Expand Down
6 changes: 3 additions & 3 deletions albumentations/augmentations/blur/functional.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from itertools import product
from math import ceil
from typing import Sequence, Union
from typing import Literal, Sequence, Union

import cv2
import numpy as np
Expand Down Expand Up @@ -42,7 +42,7 @@ def glass_blur(
max_delta: int,
iterations: int,
dxy: np.ndarray,
mode: str,
mode: Literal["fast", "exact"],
) -> np.ndarray:
x = cv2.GaussianBlur(np.array(img), sigmaX=sigma, ksize=(0, 0))

Expand Down Expand Up @@ -104,4 +104,4 @@ def zoom_blur(img: np.ndarray, zoom_factors: Union[np.ndarray, Sequence[int]]) -
for zoom_factor in zoom_factors:
out += central_zoom(img, zoom_factor)

return ((img + out) / (len(zoom_factors) + 1)).astype(img.dtype)
return (img + out) / (len(zoom_factors) + 1)
8 changes: 4 additions & 4 deletions albumentations/augmentations/blur/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,8 @@ def apply(self, img: np.ndarray, kernel: np.ndarray, **params: Any) -> np.ndarra

def get_params(self) -> Dict[str, np.ndarray]:
ksize = random.randrange(self.blur_limit[0], self.blur_limit[1] + 1, 2)
sigma_x = random_utils.uniform(*self.sigma_x_limit)
sigma_y = random_utils.uniform(*self.sigma_y_limit)
sigma_x = random.uniform(*self.sigma_x_limit)
sigma_y = random.uniform(*self.sigma_y_limit)
angle = np.deg2rad(random.uniform(*self.rotate_limit))

# Split into 2 cases to avoid selection of narrow kernels (beta > 1) too often.
Expand Down Expand Up @@ -538,8 +538,8 @@ def apply(self, img: np.ndarray, radius: int, alias_blur: float, **params: Any)

def get_params(self) -> Dict[str, Any]:
return {
"radius": random_utils.randint(self.radius[0], self.radius[1] + 1),
"alias_blur": random_utils.uniform(self.alias_blur[0], self.alias_blur[1]),
"radius": random.randint(self.radius[0], self.radius[1]),
"alias_blur": random.uniform(self.alias_blur[0], self.alias_blur[1]),
}

def get_transform_init_args_names(self) -> Tuple[str, str]:
Expand Down
15 changes: 7 additions & 8 deletions albumentations/augmentations/crops/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from pydantic import AfterValidator, Field, field_validator, model_validator
from typing_extensions import Annotated, Self

from albumentations import random_utils
from albumentations.augmentations.geometric import functional as fgeometric
from albumentations.core.bbox_utils import union_of_bboxes
from albumentations.core.pydantic import (
Expand Down Expand Up @@ -492,7 +491,7 @@ def __init__(
self.w2h_ratio = w2h_ratio

def get_params(self) -> Dict[str, Union[int, float]]:
crop_height = random_utils.randint(self.min_max_height[0], self.min_max_height[1])
crop_height = random.randint(self.min_max_height[0], self.min_max_height[1])
return {
"h_start": random.random(),
"w_start": random.random(),
Expand Down Expand Up @@ -581,9 +580,9 @@ def get_params_dependent_on_targets(self, params: Dict[str, Any]) -> Dict[str, U
area = img_height * img_width

for _ in range(10):
target_area = random_utils.uniform(*self.scale) * area
target_area = random.uniform(*self.scale) * area
log_ratio = (math.log(self.ratio[0]), math.log(self.ratio[1]))
aspect_ratio = math.exp(random_utils.uniform(*log_ratio))
aspect_ratio = math.exp(random.uniform(*log_ratio))

width = int(round(math.sqrt(target_area * aspect_ratio)))
height = int(round(math.sqrt(target_area / aspect_ratio)))
Expand Down Expand Up @@ -1364,11 +1363,11 @@ def __init__(
def get_params_dependent_on_targets(self, params: Dict[str, Any]) -> Dict[str, int]:
height, width = params["image"].shape[:2]

x_min = random_utils.randint(0, int(self.crop_left * width) + 1)
x_max = random_utils.randint(max(x_min + 1, int((1 - self.crop_right) * width)), width + 1)
x_min = random.randint(0, int(self.crop_left * width))
x_max = random.randint(max(x_min + 1, int((1 - self.crop_right) * width)), width)

y_min = random_utils.randint(0, int(self.crop_top * height) + 1)
y_max = random_utils.randint(max(y_min + 1, int((1 - self.crop_bottom) * height)), height + 1)
y_min = random.randint(0, int(self.crop_top * height))
y_max = random.randint(max(y_min + 1, int((1 - self.crop_bottom) * height)), height)

return {"x_min": x_min, "x_max": x_max, "y_min": y_min, "y_max": y_max}

Expand Down
4 changes: 2 additions & 2 deletions albumentations/augmentations/domain_adaptation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import cv2
import numpy as np
from albucore.utils import is_grayscale_image, is_multispectral_image
from albucore.utils import clip, is_grayscale_image, is_multispectral_image
from pydantic import field_validator

from albumentations.augmentations.domain_adaptation_functional import (
Expand Down Expand Up @@ -299,7 +299,7 @@ def ensure_uint8(self, img: np.ndarray) -> Tuple[np.ndarray, bool]:
"Can not do it automatically when the image is out of [0..1] range."
)
raise TypeError(message)
return (img * 255).astype("uint8"), True
return clip(img * 255, np.uint8), True
return img, False

def apply(self, img: np.ndarray, reference_image: np.ndarray, blend_ratio: float, **params: Any) -> np.ndarray:
Expand Down
4 changes: 2 additions & 2 deletions albumentations/augmentations/domain_adaptation_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import cv2
import numpy as np
from albucore.functions import add_weighted
from albucore.utils import clipped, get_num_channels, preserve_channel_dim
from albucore.utils import clip, clipped, get_num_channels, preserve_channel_dim
from skimage.exposure import match_histograms
from sklearn.decomposition import PCA
from sklearn.preprocessing import MinMaxScaler, StandardScaler
Expand Down Expand Up @@ -52,7 +52,7 @@ def to_colorspace(self, img: np.ndarray) -> np.ndarray:
def from_colorspace(self, img: np.ndarray) -> np.ndarray:
if self.color_out is None:
return img
return cv2.cvtColor(img.astype("uint8"), self.color_out)
return cv2.cvtColor(clip(img, np.uint8), self.color_out)

def flatten(self, img: np.ndarray) -> np.ndarray:
img = self.to_colorspace(img)
Expand Down
3 changes: 1 addition & 2 deletions albumentations/augmentations/dropout/channel_dropout.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from pydantic import Field
from typing_extensions import Annotated

from albumentations import random_utils
from albumentations.core.pydantic import OnePlusIntRangeType
from albumentations.core.transforms_interface import BaseTransformInitSchema, ImageOnlyTransform
from albumentations.core.types import ColorType
Expand Down Expand Up @@ -65,7 +64,7 @@ def get_params_dependent_on_targets(self, params: Mapping[str, Any]) -> Dict[str
msg = "Can not drop all channels in ChannelDropout."
raise ValueError(msg)

num_drop_channels = random_utils.randint(self.channel_drop_range[0], self.channel_drop_range[1] + 1)
num_drop_channels = random.randint(self.channel_drop_range[0], self.channel_drop_range[1])

channels_to_drop = random.sample(range(num_channels), k=num_drop_channels)

Expand Down
16 changes: 8 additions & 8 deletions albumentations/augmentations/dropout/coarse_dropout.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import random
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union
from warnings import warn

import numpy as np
from pydantic import AfterValidator, Field, model_validator
from typing_extensions import Annotated, Literal, Self

from albumentations import random_utils
from albumentations.core.pydantic import check_1plus, nondecreasing
from albumentations.core.transforms_interface import BaseTransformInitSchema, DualTransform
from albumentations.core.types import ColorType, KeypointType, NumericType, ScalarType, Targets
Expand Down Expand Up @@ -210,20 +210,20 @@ def calculate_hole_dimensions(
max_width = width_range[1]
max_height = min(max_height, height)
max_width = min(max_width, width)
hole_height = random_utils.randint(min_height, max_height + 1)
hole_width = random_utils.randint(min_width, max_width + 1)
hole_height = random.randint(int(min_height), int(max_height))
hole_width = random.randint(int(min_width), int(max_width))

else: # Assume float
hole_height = int(height * random_utils.uniform(height_range[0], height_range[1]))
hole_width = int(width * random_utils.uniform(width_range[0], width_range[1]))
hole_height = int(height * random.uniform(height_range[0], height_range[1]))
hole_width = int(width * random.uniform(width_range[0], width_range[1]))
return hole_height, hole_width

def get_params_dependent_on_targets(self, params: Dict[str, Any]) -> Dict[str, Any]:
img = params["image"]
height, width = img.shape[:2]

holes = []
num_holes = random_utils.randint(self.num_holes_range[0], self.num_holes_range[1] + 1)
num_holes = random.randint(self.num_holes_range[0], self.num_holes_range[1])

for _ in range(num_holes):
hole_height, hole_width = self.calculate_hole_dimensions(
Expand All @@ -233,8 +233,8 @@ def get_params_dependent_on_targets(self, params: Dict[str, Any]) -> Dict[str, A
self.hole_width_range,
)

y1 = random_utils.randint(0, height - hole_height + 1)
x1 = random_utils.randint(0, width - hole_width + 1)
y1 = random.randint(0, height - hole_height)
x1 = random.randint(0, width - hole_width)
y2 = y1 + hole_height
x2 = x1 + hole_width
holes.append((x1, y1, x2, y2))
Expand Down
Loading

0 comments on commit 30ac95e

Please sign in to comment.