繁体   English   中英

Python 高级 Numpy 切片和索引矢量化方法

[英]Python advanced Numpy slicing and indexing to vectorize method

我正在尝试对我在 ML 中用于图像增强的这种方法进行矢量化:

def random_erase_from_image(images, random_erasing, image_size):
#could probably be vectorized to speed up
to_return = images
for t in range(images.shape[0]):
    if np.random.randint(0, 2) == 0:#do random erasing
        x_erase_size = np.random.randint(0, random_erasing)
        y_erase_size = np.random.randint(0, random_erasing)

        x_erase_start = np.random.randint(0, image_size-x_erase_size)
        y_erase_start = np.random.randint(0, image_size-y_erase_size)

        shape = to_return[t, y_erase_start:y_erase_start+y_erase_size, x_erase_start:x_erase_start+x_erase_size, :].shape

        print(shape)

        to_return[t, y_erase_start:y_erase_start+y_erase_size, x_erase_start:x_erase_start+x_erase_size, :] = (np.random.random(shape) * 255).astype('uint8')

return images

这是据我所知,但不知道如何正确切片。

def random_erase_vec(images, random_erasing, image_size):
    #could probably be vectorized to speed up
    to_return = images
    mask = np.random.choice(a=[False, True], size=images.shape[0], p=[.5, .5])  
    x_erase_size = np.random.randint(0, random_erasing, size=images.shape[0])
    y_erase_size = np.random.randint(0, random_erasing, size=images.shape[0])

    x_erase_start = np.random.randint(0, image_size-x_erase_size, size=images.shape[0])
    y_erase_start = np.random.randint(0, image_size-y_erase_size, size=images.shape[0])

    random_values = (np.random.random((images.shape))* 255).astype('uint8')

    to_return[:, [y_erase_start[:]]:[y_erase_start[:]+y_erase_size[:]], [x_erase_start[:]]:[x_erase_start[:]+x_erase_size[:]], :] = random_values[:, [y_erase_start[:]]:[y_erase_start[:]+y_erase_size[:]], [x_erase_start[:]]:[x_erase_start[:]+x_erase_size[:]], :]

    return images

我试图避免重塑,但如果这是需要的,我想它会做到的。 让我知道您能想到的加快原始方法的任何方法。

我在切片线上收到此错误:“切片索引必须是整数或无或具有索引方法”

我也想遮盖,所以不是所有的图像都被随机删除,但我想在完成切片部分后这样做。

谢谢您的帮助。

编辑:示例输入:

图像:numpy 数组,尺寸为 [图像数量、高度 (32)、宽度 (32)、通道 (3)

random_erasing:名称不佳,但要擦除的任一维度中图像的最大大小。 目前设置为 20

image_size:现在我考虑一下可能已经从图像数组中获取了,但是清理还不是优先事项

我稍微清理了您的 function 并尝试对其进行部分矢量化,但是由于您想要更改随机补丁的大小,因此有点复杂。

import numpy as np

def random_erase(images, random_erasing):
    n, *image_size, n_channels = images.shape
    to_return = images.copy()
    
    for t in range(n):
        x_erase_size = np.random.randint(1, random_erasing)
        y_erase_size = np.random.randint(1, random_erasing)

        x_erase_start = np.random.randint(1, image_size[0]-x_erase_size)
        y_erase_start = np.random.randint(1, image_size[1]-y_erase_size)

        x_erase_end = x_erase_start + x_erase_size
        y_erase_end = y_erase_start + y_erase_size
        
        shape = (x_erase_size, y_erase_size, n_channels)
        random_image = np.random.randint(0, 255, size=shape, dtype=np.uint8)
        to_return[t, x_erase_start:x_erase_end, y_erase_start:y_erase_end, :] = random_image
        
    return to_return


def random_erase_vec(images, random_erasing):
    n, *image_size, n_channels = images.shape

    to_return = images.copy()
    x_erase_size = np.random.randint(1, random_erasing, size=n)
    y_erase_size = np.random.randint(1, random_erasing, size=n)

    x_erase_start = np.random.randint(1, image_size[0]-x_erase_size, size=n)
    y_erase_start = np.random.randint(1, image_size[1]-y_erase_size, size=n)

    x_erase_end = x_erase_start + x_erase_size
    y_erase_end = y_erase_start + y_erase_size

    shapes = np.vstack((x_erase_size, y_erase_size))
    sizes = np.prod(shapes, axis=0)
    sizes_cs = np.cumsum(np.concatenate([[0], sizes]))
    total_size = np.sum(sizes)

    idx = np.empty((total_size, 3), dtype=int)
    for i in range(n):
        idx_x, idx_y = np.meshgrid(np.arange(x_erase_start[i], x_erase_end[i]), 
                                   np.arange(y_erase_start[i], y_erase_end[i]))
        idx[sizes_cs[i]:sizes_cs[i+1], 0] = i
        idx[sizes_cs[i]:sizes_cs[i+1], 1] = idx_x.flatten()
        idx[sizes_cs[i]:sizes_cs[i+1], 2] = idx_y.flatten()

    random_values = np.random.randint(0, 255, size=(total_size, n_channels), dtype=np.uint8)
    to_return[idx[:, 0], idx[:, 1], idx[:, 2], :] = random_values

    return to_return
# images = np.random.random((1000, 100, 100, 1))
# random_erasing = 32
a = random_erase(images, random_erasing)
b = random_erase_vec(images, random_erasing)
# a: 0.059 s
# b: 0.049 s

速度提升并不惊人(大约 20%),因为这是用于 ML 中的预处理,您最好的选择是使用更多的工作人员来准备数据,这样您就可以充分利用您的 GPU。

编辑:是的,我使用 .copy() 来确保参数不会在例程之外发生突变。 因此,如果您愿意,可以忽略这一点。

我在[tensorflow文档]中使用术语工人:( https://www.tensorflow.org/api_docs/python/tf/keras/Model

worker仅用于生成器或 keras.utils.Sequence 输入。 使用基于进程的线程时要启动的最大进程数。 如果未指定,workers 将默认为 1。如果为 0,将在主线程上执行生成器。

use_multiprocessing仅用于生成器或 keras.utils.Sequence 输入。 如果为 True,则使用基于进程的线程。 如果未指定,use_multiprocessing 将默认为 False。 请注意,由于此实现依赖于多处理,因此您不应将不可提取的 arguments 传递给生成器,因为它们不能轻易传递给子进程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM