Сверточный слой в Python с использованием Numpy - PullRequest
0 голосов
/ 11 мая 2019

Я пытаюсь реализовать сверточный слой в Python, используя Numpy.В качестве входных данных используется четырехмерный массив формы [N, H, W, C], где:

  • N: размер партии
  • H: высота изображения
  • W: ширина изображения
  • C: количество каналов

Сверточный фильтр также представляет собой 4-мерный массив формы [F, F, Cin, Cout], где

  • F: высота и ширина квадратного фильтра
  • Cin: количество входных каналов (Cin = C)
  • Cout: количество выходных каналов

При условии шага по одному по всем осям и без заполнения, вывод должен быть 4-мерным массивом формы [N, H - F + 1, W - F + 1, Cout].

Мой код выглядит следующим образом:

import numpy as np

def conv2d(image, filter):
  # Height and width of output image
  Hout = image.shape[1] - filter.shape[0] + 1
  Wout = image.shape[2] - filter.shape[1] + 1

  output = np.zeros([image.shape[0], Hout, Wout, filter.shape[3]])

  for n in range(output.shape[0]):
    for i in range(output.shape[1]):
      for j in range(output.shape[2]):
        for cout in range(output.shape[3]):
          output[n,i,j,cout] = np.multiply(image[n, i:i+filter.shape[0], j:j+filter.shape[1], :], filter[:,:,:,cout]).sum()

  return output

Это отлично работает, но использует четыре для циклов и очень медленно.Есть ли лучший способ реализации сверточного слоя, который принимает 4-мерный ввод и фильтр и возвращает 4-мерный вывод, используя Numpy?

1 Ответ

1 голос
/ 13 мая 2019

Это прямая реализация такого рода keras -подобной (?) Свертки.Это может быть трудно понять новичкам, потому что он использует множество приемов вещания и быстрого продвижения.

from numpy.lib.stride_tricks import as_strided
def conv2d(a, b):
    a = as_strided(a,(len(a),a.shape[1]-len(b)+1,a.shape[2]-b.shape[1]+1,len(b),b.shape[1],a.shape[3]),a.strides[:3]+a.strides[1:])
    return np.einsum('abcijk,ijkd', a, b[::-1,::-1])

Кстати: если вы делаете свертку с очень большим ядром, используйте вместо этого алгоритм на основе Фурье.

РЕДАКТИРОВАТЬ: [::-1,::-1] следует удалить в случае, если свертка не включает в себя сначала перевернуть ядро ​​(как в tensorflow).

РЕДАКТИРОВАТЬ: np.tensordot(a, b, axes=3) работает намного лучше, чем np.einsum("abcijk,ijkd", a, b), и настоятельно рекомендуется.Итак, функция становится:

from numpy.lib.stride_tricks import as_strided

def conv2d(a, b):
  Hout = a.shape[1] - b.shape[0] + 1
  Wout = a.shape[2] - b.shape[1] + 1

  a = as_strided(a, (a.shape[0], Hout, Wout, b.shape[0], b.shape[1], a.shape[3]), a.strides[:3] + a.strides[1:])

  return np.tensordot(a, b, axes=3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...