Skip to content

Commit 86fbd42

Browse files
committed
faster cpu conv
1 parent df05cbc commit 86fbd42

4 files changed

Lines changed: 95 additions & 85 deletions

File tree

infCNN/LayerLib.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .Core import Layer
2-
from .im2col import im2col_indices
2+
from .conv import img2col
33
import numpy as np
44

55
class Dense(Layer):
@@ -8,8 +8,8 @@ def __init__(self, n_in, n_out):
88
super().__init__('dense_{}_{}'.format(n_in, n_out))
99
self.n_in = n_in
1010
self.n_out = n_out
11-
self.K = np.random.randn(n_out, n_in)
12-
self.bias = np.zeros(n_out)
11+
self.K = np.zeros((n_out, n_in), dtype='float32')
12+
self.bias = np.zeros(n_out, dtype='float32')
1313

1414
def forward(self, x):
1515
self.x = x
@@ -30,50 +30,28 @@ def __init__(self, C_in, C_out, K_s, Stride):
3030
Params:
3131
in channels, out channles, kernel size, stride
3232
"""
33-
super().__init__("conv_{}_{}x{}x{}".format(C_out, C_in, K_s, K_s))
33+
super().__init__("conv_{}_{}x{}x{}".format(C_in, C_out, K_s, K_s))
3434
self.c_in = C_in
3535
self.c_out = C_out
3636
self.k_s = K_s
3737
self.stride = Stride
3838
self.pad_size = int((K_s -1)/2)
39-
self.K = np.zeros((C_out, C_in, K_s, K_s))
40-
self.bias = np.zeros(C_out)
39+
self.K = np.zeros((C_out, C_in, K_s, K_s), dtype='float32')
40+
self.bias = np.zeros(C_out, dtype='float32')
4141

42-
def forward(self, X):
43-
out = conv_forward(X, self.K, self.bias, stride=self.stride, padding=self.pad_size)
44-
return out
42+
# def forward(self, X):
43+
# out = conv_forward(X, self.K, self.bias, stride=self.stride, padding=self.pad_size)
44+
# return out
4545

46+
def forward(self, X):
47+
out = img2col(X, self.K)
48+
print(out.shape)
4649

4750
def load_from_torch(self, weights, bias):
4851
self.K = weights
4952
self.bias = bias
5053

5154

52-
def conv_forward(X, W, b, stride=1, padding=1):
53-
cache = W, b, stride, padding
54-
n_filters, d_filter, h_filter, w_filter = W.shape
55-
n_x, d_x, h_x, w_x = X.shape
56-
h_out = (h_x - h_filter + 2 * padding) / stride + 1
57-
w_out = (w_x - w_filter + 2 * padding) / stride + 1
58-
59-
if not h_out.is_integer() or not w_out.is_integer():
60-
raise Exception('Invalid output dimension!')
61-
62-
h_out, w_out = int(h_out), int(w_out)
63-
64-
X_col = im2col_indices(X, h_filter, w_filter, padding=padding, stride=stride)
65-
W_col = W.reshape(n_filters, -1)
66-
67-
out = W_col @ X_col
68-
out = (out.T + b[:]).T
69-
out = out.reshape(n_filters, h_out, w_out, n_x)
70-
out = out.transpose(3, 0, 1, 2)
71-
72-
cache = (X, W, b, stride, padding, X_col)
73-
74-
return out# , cache
75-
76-
7755

7856

7957
if __name__ == "__main__":

infCNN/conv.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import numpy as np
2+
from time import time
3+
from numba import njit
4+
5+
def neighbors(shape, core):
6+
shp = [slice(0,i) for i in core]
7+
idx = np.mgrid[tuple(shp)]
8+
idx = idx.reshape((len(core),-1))
9+
offset = np.array(core)//2
10+
offset[0] = 0
11+
idx -= offset.reshape((-1,1))
12+
acc = np.cumprod((1,)+shape[::-1][:-1])
13+
return np.dot(idx.T, acc[::-1])
14+
15+
@njit
16+
def fill_col(pdimg, idx, colimg):
17+
s = 0
18+
for i in range(len(pdimg)):
19+
if pdimg[i]&1==0: continue
20+
for j in idx:
21+
colimg[s] = pdimg[i+j]
22+
s += 1
23+
return colimg
24+
25+
def img2col(img, core, buf=[np.zeros(1, dtype=np.int32)]):
26+
# new the col_img, if needed
27+
cimg_w = np.cumprod(core.shape[1:])[-1]
28+
cimg_h = img.size//img.shape[1]
29+
if len(buf[0])<cimg_h*cimg_w:
30+
buf[0] = col_img = np.zeros(cimg_h*cimg_w, dtype=np.int32)
31+
else:
32+
col_img = buf[0][:cimg_h*cimg_w]
33+
col_img[:] = 0
34+
35+
# mark where need
36+
iimg = img.view(dtype=np.int32)
37+
iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
38+
iimg[:,0,:,:] |= 1
39+
40+
# ravel the image
41+
n,c,h,w = np.array(core.shape)
42+
shp = ((0,0),(0,0),(h//2,h//2),(w//2,w//2))
43+
pdimg = np.pad(iimg, shp, 'constant', constant_values=0)
44+
nbs = neighbors(pdimg.shape[1:], core.shape[1:])
45+
fill_col(pdimg.ravel(), nbs, col_img)
46+
col_img = col_img.view(np.float32)
47+
col_img = col_img.reshape((cimg_h, cimg_w))
48+
49+
# dot
50+
col_core = core.reshape((core.shape[0],-1))
51+
rst = col_core.dot(col_img.T)
52+
ni, ci, hi, wi = img.shape
53+
return rst.reshape((ni, n, hi, wi))
54+
55+
if __name__ == '__main__':
56+
from skimage.data import camera
57+
import matplotlib.pyplot as plt
58+
from scipy.ndimage import convolve
59+
img = np.zeros((1, 3, 512, 512), dtype=np.float32)
60+
img.ravel()[:] = np.arange(3*512*512)
61+
62+
iimg = img.view(dtype=np.int32)
63+
iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
64+
iimg[:,0,:,:] |= 1
65+
66+
core = np.zeros((32, 3, 3, 3), dtype=np.float32)
67+
core.ravel()[:] = np.arange(3*3*3*32)
68+
69+
start = time()
70+
rst1 = img2col(img, core)
71+
print(time()-start)
72+
73+
start = time()
74+
rst = img2col(img, core)
75+
print('jit cost: x10', time()-start)

infCNN/im2col.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

infCNN/numpy_extend.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ def up4x(fm):
1818
fm4x = up2x(up2x(fm))
1919
return fm4x
2020

21+
def up8x(fm):
22+
fm8x = up4x(up2x(fm))
23+
return fm8x
24+
25+
def up16x(fm):
26+
fm16x = up8x(up2x(fm))
27+
return fm16x
28+
2129
if __name__ == "__main__":
2230
img = np.random.randn(2, 3, 100, 100)
2331
img2x = up4x(img)

0 commit comments

Comments
 (0)