Давайте попробуем визуализировать, что делает im2col
. Он принимает в качестве входных данных стек цветных изображений, стек имеет размеры изображения id, цветовой канал, вертикальное положение, горизонтальное положение. Давайте для простоты предположим, что у нас есть только одно изображение:

Первое, что он делает, это заполнение:

Затем он разрезает его на окна. Размер окон контролируется filter_h/w
, перекрытие strides
.

Вот откуда берутся шесть измерений: идентификатор изображения (отсутствует в примере, потому что у нас только одно изображение), высота / ширина сетки, цветовой канал. высота / ширина окна.

Алгоритм в его нынешнем виде немного неуклюж, он собирает выходные данные в неправильном порядке измерений и затем должен исправить это, используя transpose
.
Лучше понять все правильно:
def im2col_better(input_data, filter_h, filter_w, stride=1, pad=0):
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
N, C, H, W = img.shape
out_h = (H - filter_h)//stride + 1
out_w = (W - filter_w)//stride + 1
col = np.zeros((N, out_h, out_w, C, filter_h, filter_w))
for y in range(out_h):
for x in range(out_w):
col[:, y, x] = img[
..., y*stride:y*stride+filter_h, x*stride:x*stride+filter_w]
return col.reshape(np.multiply.reduceat(col.shape, (0, 3)))
Как примечание: мы можем сделать еще лучше, используя stride_tricks
и избегая вложенного цикла for
:
def im2col_best(input_data, filter_h, filter_w, stride=1, pad=0):
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
N, C, H, W = img.shape
NN, CC, HH, WW = img.strides
out_h = (H - filter_h)//stride + 1
out_w = (W - filter_w)//stride + 1
col = np.lib.stride_tricks.as_strided(img, (N, out_h, out_w, C, filter_h, filter_w), (NN, stride * HH, stride * WW, CC, HH, WW)).astype(float)
return col.reshape(np.multiply.reduceat(col.shape, (0, 3)))
Последнее, что делает алгоритм, это изменение формы, объединяя первые три измерения (опять только два в нашем примере, потому что только одно изображение). Красные стрелки показывают, как отдельные окна выстроены в первое новое измерение:

Последние три измерения цветовой канал, координата y в окне, координата x в окне объединяются во второе выходное измерение. Отдельные пиксели выровнены, как показано желтыми стрелками:
