CNN实现
带batch_size的多通道卷积计算
import numpy as np
def im2col(img, ksize, stride=1):
N, H, W, C = img.shape
out_h = (H - ksize) // stride + 1
out_w = (W - ksize) // stride + 1
col = np.empty((N * out_h * out_w, ksize * ksize * C))
outsize = out_w * out_h
for y in range(out_h):
y_min = y * stride
y_max = y_min + ksize
y_start = y * out_w
for x in range(out_w):
x_min = x * stride
x_max = x_min + ksize
col[y_start+x::outsize, :] = img[:, y_min:y_max, x_min:x_max, :].reshape(N, -1)
return col
def conv(X, W, stride=1, padding='valid'):
FN, ksize, ksize, C = W.shape
if padding == 'same':
p = ksize // 2
X = np.pad(X, ((0, 0), (p, p), (p, p), (0, 0)), 'constant')
N, H, w, C = X.shape
col = im2col(X, ksize, stride)
z = np.dot(col, W.reshape(W.shape[0], -1).transpose())
z = z.reshape(N, z.shape[0] // N, -1)
out_h = (H - ksize) // stride + 1
return z.reshape(N, out_h, -1 , FN)
A = np.random.randint(0, 9, (2*3*3*3)).reshape(2, 3, 3, 3)
ken = np.random.randint(0, 9, (6*2*2*3)).reshape(6,2,2,3)
print(conv(A, ken, 1).shape)
import numpy as np
from numpy.lib.stride_tricks import as_strided
def Conv2d_(X, kernel, stride, padding=0):
if padding:
X = np.pad(X, pad_width=((0, 0), (padding, padding), (padding, padding), (0, 0)), mode='constant', constant_values=0)
N, C, H, W = X.shape
kernel_n, kernel_c, kernel_size_h, kernel_size_w = kernel.shape
output_shape = (N, kernel_n, (H-kernel_size_h)//stride+1, (W-kernel_size_w)//stride+1)
kernel_size = (kernel_size_w, kernel_size_h)
img_W = as_strided(X, shape=kernel_size+(N, C, output_shape[-2], output_shape[-1]),
strides=(X.strides[0], X.strides[1], stride*X.strides[2], stride*X.strides[3])+X.strides[-2:])
img_W = img_W.reshape(-1, kernel_c*kernel_size_h*kernel_size_w)
Z = np.dot(img_W, kernel.reshape(kernel_n, -1).transpose())
return Z.reshape(output_shape)
A = np.random.randint(0, 9, (2*3*3*3)).reshape(2, 3, 3, 3)
ken = np.random.randint(0, 9, (6*2*2*3)).reshape(6,3,2,2)
print(Conv2d_(A, ken, 1).shape)
# 平面卷积计算
import numpy as np
from numpy.lib.stride_tricks import as_strided
def Conv2d(img, kernel, stride, padding=0):
if padding:
img = np.pad(img, pad_width=padding, mode='constant')
kernel_size_h, kernel_size_w = len(kernel[0]), len(kernel[1])
output_shape = ((img.shape[0]-kernel_size_h)//stride+1, (img.shape[1]-kernel_size_w)//stride+1)
kernel_size = (kernel_size_h, kernel_size_w)
img_W = as_strided(img, shape=kernel_size+output_shape,
strides=(stride*img.strides[0], stride*img.strides[1])+img.strides)
img_W = img_W.reshape(-1, *kernel_size)
return np.tensordot(img_W, kernel).reshape(output_shape)
A = np.array([[1, 1, 1, 1, 1], [1, 1, 3, 1, 1], [1, 2, 1, 1, 1], [1, 1, 1, 1, 1]]) # 4行5列
ken = np.array([[2, 4], [2, 1]])
print(Conv2d(A, ken, 2, 1))
pool实现
numpy实现
import numpy as np
from numpy.lib.stride_tricks import as_strided
def pool2d(A, kernel_size, stride, padding, pool_mode='max'):
if padding:
A = np.pad(A, padding, 'constant')
output_shape = ((A.shape[0]-kernel_size)//stride+1, (A.shape[1]-kernel_size)//stride+1)
kernel_size = (kernel_size, kernel_size)
A_w = as_strided(A, shape=output_shape+kernel_size,
strides=(stride*A.strides[0], stride*A.strides[1])+A.strides)
A_w = A_w.reshape(-1, *kernel_size)
if pool_mode == 'max':
return A_w.max(axis=(1,2)).reshape(output_shape)
if pool_mode == 'avg':
return A_w.mean(axis=(1,2)).reshape(output_shape)
A = np.array([[1, 1, 2, 4],
[5, 6, 7, 8],
[3, 2, 1, 0],
[1, 2, 3, 4]])
print(pool2d(A, kernel_size=2, stride=2, padding=0, pool_mode='avg'))
普通实现
from itertools import product
def max_pool(nums):
m, n = len(nums), len(nums[0])
ans = [[0]*(n//2) for _ in range(m//2)]
for i, j in product(range(0, m-1, 2), range(0, n-1, 2)):
maxN = float('-inf')
for k, l in product(range(i, min(m, i+2)), range(j, min(n, j+2))):
maxN = max(maxN, nums[k][l])
ans[i//2][j//2] = maxN
return ans
def avg_pool(nums):
m, n = len(nums), len(nums[0])
ans = [[0]*n for _ in range(m)]
for i, j in product(range(m), range(n)):
total = 0
cnt = 0
for k, l in product(range(max(0, i-1), min(m, i+2)), range(max(0, j-1), min(n, j+2))):
total += nums[k][l]
cnt += 1
ans[i][j] = total//cnt
return ans
def avg_pool_new(nums):
m, n = len(nums), len(nums[0])
ans = [[0]*n for _ in range(m)]
prefix = [[0]*(n+1) for _ in range(m+1)]
for i, j in product(range(1, m+1), range(1, n+1)):
prefix[i][j] = prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1] + nums[i-1][j-1]
for i, j in product(range(m), range(n)):
x1, y1 = max(0, i-1), max(0, j-1)
x2, y2 = min(m-1, i+1), min(n-1, j+1)
total = prefix[x2+1][y2+1] - prefix[x1][y2+1] - prefix[x2+1][y1] + prefix[x1][y1]
cnt = (x2-x1+1)*(y2-y1+1)
ans[i][j] = total // cnt
return ans
# nums = [[1,2,3], [4,5,6], [7,8,9]]
nums = [[1,2,3,4],[5,6,7,8], [9,10,11,12], [13,14,15,16]]
print(nums)
print(max_pool(nums))
print(avg_pool(nums))
print(avg_pool_new(nums))