스트라이드 컨볼루션
- 기존 컨볼루션 연산은 필터를 1칸씩 이동시키며 연산을 했는데, 스트라이드 컨볼루션은 여러칸씩 점프하며 연산하는 것
def conv2d(data: np.ndarray, filters: np.ndarray, stride: int = 1) -> np.ndarray:
data_len, _ = data.shape
filter_len, _ = filters.shape
output_len = ((data_len - filter_len) // stride) + 1
output = np.zeros((output_len, output_len))
for i in range(output_len):
for j in range(output_len):
for k in range(filter_len):
for l in range(filter_len):
output[i, j] += data[i * stride + k, j * stride + l] * filters[k, l]
return output
data = np.array([
[2, 3, 7, 4, 6, 2, 9],
[6, 6, 9, 8, 7, 4, 3],
[3, 4, 8, 3, 8, 9, 7],
[7, 8, 3, 6, 6, 3, 4],
[4, 2, 1, 8, 3, 4, 6],
[3, 2, 4, 1, 9, 8, 3],
[0, 1, 3, 9, 2, 1, 4]
])
kernel = np.array([
[3, 4, 4],
[1, 0, 2],
[-1, 0, 3]
])
result = conv2d(data, kernel, stride=2)
print(result)
[[ 91. 100. 88.]
[ 69. 91. 117.]
[ 44. 72. 74.]]
- stride 는 s 로 표기한다.
- 출력 행렬의 크기는 반올림 하여 [sn+2p−f+1]×[sn+2p−f+1] 가 된다.
수학 교과서의 컨볼루션
- 요소별 곱셈과 합을 하기 전에 필터를 좌/우로 뒤집는다.
kernel = np.array([
[3, 4, 4],
[1, 0, 2],
[-1, 0, 3]
])
flip_kernel = np.flipud(np.fliplr(kernel))
print(flip_kernel)
[[ 3 0 -1]
[ 2 0 1]
[ 4 4 3]]
- 원래 이런 미러링까지 도입 해야 진짜 컨볼루션 연산이라고 할 수 있지만 딥러닝에서 관례 상 그냥 컨볼루션 연산이라고 얘기를 한다.