2-D свертка как матрично-матричное умножение

Я знаю, что в одномерном случае свертка между двумя векторами,a а такжеb, может быть вычислено какconv(a, b), но также как продукт междуT_a а такжеb, гдеT_a соответствующая матрица Теплица для.a

Можно ли распространить эту идею на 2D?

Даноa = [5 1 3; 1 1 2; 2 1 3] а такжеb=[4 3; 1 2], можно ли конвертироватьa в матрице Теплица и вычислить матрично-матричное произведение междуT_a а такжеb как в 1-м случае?

Ответы на вопрос(4)

Код, показанный выше, неt создать развернутую матрицу нужных размеров. Размерность должна быть (n-k + 1) * (m-k + 1), (k) (k). k: размер фильтра, n: количество строк во входной матрице, m: количество столбцов.

def unfold_matrix(X, k):
    n, m = X.shape[0:2]
    xx = zeros(((n - k + 1) * (m - k + 1), k**2))
    row_num = 0
    def make_row(x):
        return x.flatten()

    for i in range(n- k+ 1):
        for j in range(m - k + 1):
            #collect block of m*m elements and convert to row
            xx[row_num,:] = make_row(X[i:i+k, j:j+k])
            row_num = row_num + 1

    return xx

Для более подробной информации, смотрите мой пост в блоге:

http://www.telesens.co/2018/04/09/initializing-weights-for-the-convolutional-and-fully-connected-layers/

Да, это возможно, и вы также должны использовать циркулянтную матрицу с двойным блоком (что является частным случаемТеплица матрица). Я приведу пример с небольшим размером ядра и входными данными, но можно построить матрицу Тёплица для любого ядра. Итак, у вас есть 2d входx и 2d ядроk и вы хотите рассчитать сверткуx * k, Также позвольтеПредположим, чтоk уже перевернуто. Позволять'Также предположим, чтоx имеет размерn×n а такжеk является .m×m

Так вы развернетеk в разреженную матрицу размера(n-m+1)^2 × n^2и развернутьx в длинный векторn^2 × 1, Вы вычисляете умножение этой разреженной матрицы на вектор и конвертируете полученный вектор (который будет иметь размер(n-m+1)^2 × 1) вn-m+1 квадратная матрица

Я почти уверен, что это трудно понять только по чтению. Итак, вот пример для 2 ×2 ядра и 3 ×3 входа. *

Вот построенная матрица с вектором:

что равно.

И это тот же результат, который вы получили бы, сделав скользящее окноk над .x

 Daniel Arnett27 апр. 2019 г., 16:11
@mrgloom Да, приведенная выше операция является корреляцией, поэтому он сначала переворачивает фильтр (вверх ногами), чтобы потом он стал эквивалентен свертке. Numpy этоflip(m, 0), что эквивалентно.flipud(m)
 Salvador Dali12 июн. 2017 г., 20:14
@jvans да, в конце концов, вы должны изменить свой вектор. Здесь написано:преобразовать полученный вектор (который будет иметь размер (n-m + 1) ^ 2 X 1) в квадратную матрицу n-m + 1
 jvans12 июн. 2017 г., 19:11
Там должно быть какое-то изменение формы в конце правильно? Этот последний вектор равен 4 x 1, но результат свертки будет 2 x 2
 user268287714 мар. 2018 г., 18:18
В вашем примере это не матрица Теплица. Таким образом, вы отвечаете только частично правильно, не так ли?
 mrgloom09 сент. 2018 г., 18:47
Что вы подразумеваете подAlso let's assume that k is already flipped? Это потому, что мы хотим выполнить корреляцию вместо свертки? Что такоеflipped с точки зрения NumPy операций?

Если вы развернете k к вектору m ^ 2 и развернете X, вы получите: a

m**2 vectorak((n-m)**2, m**2) матрица дляunrolled_X

гдеunrolled_X может быть получен с помощью следующего кода Python:

from numpy import zeros


def unroll_matrix(X, m):
  flat_X = X.flatten()
  n = X.shape[0]
  unrolled_X = zeros(((n - m) ** 2, m**2))
  skipped = 0
  for i in range(n ** 2):
      if (i % n) < n - m and ((i / n) % n) < n - m:
          for j in range(m):
              for l in range(m):
                  unrolled_X[i - skipped, j * m + l] = flat_X[i + j * n + l]
      else:
          skipped += 1
  return unrolled_X

Развертывание X и не k позволяет более компактное представление (меньшие матрицы), чем наоборот для каждого X - но вам нужно развернуть каждый X. Вы можете предпочесть развертывание k в зависимости от того, что вы хотите сделать.

Здесьunrolled_X не редкость, тогда какunrolled_k будет редким, но размером((n-m+1)^2,n^2) как упомянул Сальвадор Дали.

Развернувk можно сделать так:

from scipy.sparse import lil_matrix
from numpy import zeros
import scipy 


def unroll_kernel(kernel, n, sparse=True):

    m = kernel.shape[0]
    if sparse:
         unrolled_K = lil_matrix(((n - m)**2, n**2))
    else:
         unrolled_K = zeros(((n - m)**2, n**2))

    skipped = 0
    for i in range(n ** 2):
         if (i % n) < n - m and((i / n) % n) < n - m:
             for j in range(m):
                 for l in range(m):
                    unrolled_K[i - skipped, i + j * n + l] = kernel[j, l]
         else:
             skipped += 1
    return unrolled_K
1- Определить ввод и фильтр

Могу я быть входным сигналом и F быть фильтром или ядром.

2- Рассчитать окончательный размер вывода

Если яm1 x n1 и F - m2 x n2, размер вывода будет:

3- Zero-pad матрица фильтра

Обнулите фильтр, чтобы он соответствовал размеру вывода.

4- Создайте матрицу Теплица для каждой строки фильтра с добавлением нуля

5- Создать дважды блокированную матрицу Теплица

Теперь все эти маленькие матрицы Теплица должны быть расположены в большой дважды блокированной теплицевой матрице.

6- преобразовать входную матрицу в вектор-столбец

7 - Умножьте дважды блокированную матрицу теплица с векторизованным входным сигналом

Это умножение дает результат свертки.

8- Последний шаг: преобразовать результат в матричную форму

Для получения более подробной информации и кода Python, посмотрите мой репозиторий Github:

Пошаговое объяснение двумерной свертки, реализованной в виде умножения матриц с использованием теплицевых матриц в Python

Ваш ответ на вопрос