Я буду коротким.Предположим, у меня есть следующие 2 изображения размеров: N (number_of_images) xH (height_of_images) xW (width_of_images) xD (каналы), определенные в numpy как:
input_rgb = np.array(
[
[
[[.7], [.6], [.3]],
[[.2], [.0], [.0]],
[[.1], [.2], [.9]]
],
[
[[.7], [.6], [.3]],
[[.2], [.0], [.0]],
[[.1], [.2], [.9]]
]
])
и следующие 2 ядра размером: M (number_of_kernels) xH (height_of_kernel) xW (width_of_kernel) xD (каналы), определяемый как:
kernel = np.array(
[
[
[[.2], [.1]],
[[.1], [.7]]
],
[
[[.9], [.7]],
[[.1], [.5]]
]
])
Я хочу выполнить свертку двух вышеуказанных изображений с двумя вышеуказанными ядрами.Для этого я реализовал очень простое решение на основе einsum в numpy, которое прекрасно работает, пока у меня не будет единого изображения.Для одного изображения мой алгоритм выглядит следующим образом:
def convolve_1m(input_image, kernels, padding=0, stride=1):
image_height, image_width, image_channels = input_image.shape
number_of_kernels, kernel_height, kernel_width, kernel_depth = kernels.shape
assert (image_channels == kernel_depth)
input_image = np.pad(input_image, ((padding, padding), (padding, padding), (0, 0)),
mode='constant', constant_values=(0,))
kernels = np.rot90(kernels, k=2, axes=(1, 2))
fm_height = (image_height - kernel_height + 2*padding) // stride + 1
fm_width = (image_width - kernel_width + 2*padding) // stride + 1
feature_maps = np.zeros(shape=(fm_height, fm_width, number_of_kernels))
for i in range(fm_height):
for j in range(fm_width):
x = input_image[i * stride:i * stride + kernel_height, j * stride:j * stride + kernel_width, :]
feature_maps[i, j, :] = np.einsum('ijk,mijk', x, kernels)
return feature_maps
Если я позвоню выше, используя:
convolution = np.array([convolve_1m(input_rgb[0], kernel), convolve_1m(input_rgb[1], kernel)])
print(convolution.shape)
print(convolution)
Я получу результат, который выглядит следующим образом:
(2, 2, 2, 2)
[[[[0.57 0.55]
[0.45 0.33]]
[[0.19 0.35]
[0.2 0.95]]]
[[[0.57 0.55]
[0.45 0.33]]
[[0.19 0.35]
[0.2 0.95]]]]
Что выглядит идеально, ... по крайней мере, если мои собственные расчеты в порядке на бумаге.Теперь о проблемной части.Это выглядит не очень хорошо, потому что мне нужно восстановить массив np.array в области вызывающей стороны, чтобы я мог передать его следующему сверточному слою.Поэтому вместо того, чтобы иметь его, я попробовал следующий подход:
def convolve(input_images, kernels, padding=0, stride=1):
number_of_images, image_height, image_width, image_channels = input_images.shape
number_of_kernels, kernel_height, kernel_width, kernel_depth = kernels.shape
assert (image_channels == kernel_depth)
input_images = np.pad(input_images, ((0, 0), (padding, padding), (padding, padding), (0, 0)),
mode='constant', constant_values=(0,))
kernels = np.rot90(kernel, k=2, axes=(1, 2))
fm_height = (image_height - kernel_height + 2*padding) // stride + 1
fm_width = (image_width - kernel_width + 2*padding) // stride + 1
feature_maps = np.zeros(shape=(number_of_images, fm_height, fm_width, number_of_kernels))
for i in range(fm_height):
for j in range(fm_width):
x = input_images[:, i * stride:i * stride + kernel_height, j * stride:j * stride + kernel_width, :]
feature_maps[:, i, j, :] = np.einsum('nijk,mijk', x, kernels)
return feature_maps
convolution = convolve(input_rgb, kernel)
print(convolution.shape)
print(convolution)
Однако, несмотря на то, что результаты в порядке, размерность немного странная:
(2, 2, 2, 2)
[[[[0.57 0.57]
[0.45 0.45]]
[[0.19 0.19]
[0.2 0.2 ]]]
[[[0.55 0.55]
[0.33 0.33]]
[[0.35 0.35]
[0.95 0.95]]]]
Может кто-нибудь помочь мне разобратьсякак сделать так, чтобы описанный выше случай NM работал правильно, используя срезы массива, а не другой для цикла in range, например:
def convolve(input_images, kernels, padding=0, stride=1):
number_of_images, image_height, image_width, image_channels = input_images.shape
number_of_kernels, kernel_height, kernel_width, kernel_depth = kernels.shape
assert (image_channels == kernel_depth)
input_images = np.pad(input_images, ((0, 0), (padding, padding), (padding, padding), (0, 0)),
mode='constant', constant_values=(0,))
kernels = np.rot90(kernel, k=2, axes=(1, 2))
fm_height = (image_height - kernel_height + 2*padding) // stride + 1
fm_width = (image_width - kernel_width + 2*padding) // stride + 1
feature_maps = np.zeros(shape=(number_of_images, fm_height, fm_width, number_of_kernels))
for n in range(number_of_images):
for i in range(fm_height):
for j in range(fm_width):
x = input_images[n, i * stride:i * stride + kernel_height, j * stride:j * stride + kernel_width, :]
feature_maps[n, i, j, :] = np.einsum('ijk,mijk', x, kernels)
return feature_maps
Хотя это работает и дает правильный результат, я бы хотел получить его без внешнегодля- (п) -loop.