[英]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.