Я ставлю это на первое место, я не использую никаких фреймворков, и я начал изучать сверточные слои, как на прошлой неделе.Я понимаю основы прямого распространения, даже не коснулся, но это выходит за рамки.Вот моя путаница:
Предположим, у меня есть 4 изображения с 3 каналами размером 4x4: 4x3x4x4 И у меня есть ядра с 3 каналами размера 3x3: K * 3x3x3
Я пытаюсь вычислитьсвертки на всех 4 изображениях, но я всегда теряюсь в размерности.Вот что я попробовал:
import numpy as np
w = np.array(
[
# Img: 1, 4x4 image with 3 channels
[
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
],
[
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
],
[
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]
]
],
# Img: 2, 4x4 image with 3 channels
[
[
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
],
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
],
[
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]
]
],
# Img: 3, 4x4 image with 3 channels
[
[
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]
],
[
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
],
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
]
],
# Img: 4, 4x4 image with 3 channels
[
[
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]
],
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
],
[
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
]
]
)
f = np.array(
[
# Filter: 1, 3x3 filter for 3 channels -> All 1s
[
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
],
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
],
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
]
],
# Filter: 2, 3x3 filter for 3 channels -> All 2s
[
[
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]
],
[
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]
],
[
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]
]
]
]
)
hori_dimension = (w.shape[3] - f.shape[3]) // 1 + 1
vert_dimension = (w.shape[2] - f.shape[2]) // 1 + 1
r = np.zeros(shape=(w.shape[0], f.shape[0], vert_dimension, hori_dimension))
for i in range(vert_dimension):
for j in range(hori_dimension):
r[:, :, i, j] += np.sum(w[:, :, i:i+3, j:j+3] * f, axis=(1, 2, 3))
print(r)
Это не работает, и у меня есть проблемы с этой частью, когда у меня есть число ядер K для числа N изображений.
Если яоднако у меня есть одно ядро, и я могу определить свою операцию следующим образом: (Это работает безупречно):
hori_dimension = (w.shape[3] - f.shape[3]) // 1 + 1
vert_dimension = (w.shape[2] - f.shape[2]) // 1 + 1
r = np.zeros(shape=(w.shape[0], vert_dimension, hori_dimension))
for i in range(vert_dimension):
for j in range(hori_dimension):
r[:, i, j] += np.sum(w[:, :, i:i+3, j:j+3] * f, axis=(1, 2, 3))
print(r)
, что приводит к возможности 2x2 для каждого изображения:
[[[27. 27.]
[27. 27.]]
[[27. 27.]
[27. 27.]]
[[27. 27.]
[27. 27.]]
[[27. 27.]
[27. 27.]]]
Это кажется правильным,У меня есть 1 ядро, поэтому у меня будет 1 карта объектов для каждого изображения, что дает 4 карты объектов в 2 измерениях.В вышесказанном я бы ожидал, другое измерение.Имея 4 карты характеристик для каждого ядра, но я не могу понять это.
@ Обновление:
Это похоже на выполнение работы:
p = 0
s = 1
number_of_input_images, number_of_image_channels, height_of_image, width_of_image = w.shape
number_of_kernels, number_of_kernel_channels, height_of_kernel, width_of_kernel = f.shape
assert(number_of_image_channels == number_of_kernel_channels)
width_of_features = (width_of_image - width_of_kernel + 2*p) // s + 1
height_of_features = (height_of_image - height_of_kernel + 2*p) // s + 1
feature_maps = np.zeros(shape=(number_of_input_images, number_of_kernels, height_of_features, width_of_features))
for k in range(f.shape[0]):
for i in range(height_of_features):
for j in range(width_of_features):
feature_maps[:, k, i, j] += np.sum(w[:, :, i:i+3, j:j+3] * f[k], axis=(1, 2, 3))
print(feature_maps)
Этоприводит к следующим картам функций:
[
# pic1
[
# kernel1
[
[27. 27.]
[27. 27.]
]
# kernel2
[
[54. 54.]
[54. 54.]
]
]
# pic2
[
#kernel1
[
[27. 27.]
[27. 27.]
]
#kernel2
[
[54. 54.]
[54. 54.]
]
]
#pic3
[
#kernel1
[
[27. 27.]
[27. 27.]
]
#kernel2
[
[54. 54.]
[54. 54.]
]
]
#pic4
[
#kernel1
[
[27. 27.]
[27. 27.]
]
#kerbel2
[
[54. 54.]
[54. 54.]
]
]
]
Есть ли лучший способ сделать это?Это даже правильно?Мне кажется, это нормально.Имея изображение и несколько ядер, результатом свертки будет карта характеристик каждого ядра, поставленная «после» другого права?Таким образом, при количестве ядер K, в котором карты объектов имеют N N измерений, вывод сверточного слоя становится K N * N.Таким образом, вышесказанное кажется правильным, я думаю?Как я уже сказал, я действительно испортил эти N измерений ...
@ Обновление:
Я получил следующий код для действительных (прямая) / полная (обратная) сверток:
def convolve(sources: np.ndarray,
kernels: np.ndarray,
mode: str = 'valid',
padding: typing.Tuple[int] = (0, 0),
stride: int = 1):
number_of_input_images, number_of_image_channels, height_of_image, width_of_image = sources.shape
number_of_kernels, number_of_kernel_channels, height_of_kernel, width_of_kernel = kernels.shape
assert(number_of_image_channels == number_of_kernel_channels)
if mode == 'full':
padding = (height_of_kernel, width_of_kernel)
if padding:
sources = np.pad(sources,
((0, 0), (0, 0), (padding[0], padding[0]), (padding[1], padding[1])),
mode='constant', constant_values=0)
kernels = np.rot90(kernels, k=2, axes=(2, 3))
width_of_features = (width_of_image - width_of_kernel + 2*padding[1]) // stride + 1
height_of_features = (height_of_image - height_of_kernel + 2*padding[0]) // stride + 1
feature_maps = np.zeros(shape=(number_of_input_images, number_of_kernels, height_of_features, width_of_features))
for k in range(f.shape[0]):
for i in range(height_of_features):
for j in range(width_of_features):
feature_maps[:, k, i, j] = np.einsum('ncij,cij', sources[:, :, i:i+3, j:j+3], kernels[k])
return feature_maps
Любые отзывы будут оценены.Я читал, что ядра должны быть повернуты при выполнении свертки, поэтому я поворачиваюсь дважды на 90 градусов, также есть возможность использовать пользовательское заполнение, и для полной сверточности я дополняю до размера ядра -1, чтобы всеокружающие элементы равны нулю, и я не получаю ошибок индекса.