Skip to content

Commit 3e279cd

Browse files
committed
fast maxpool
1 parent a7addae commit 3e279cd

5 files changed

Lines changed: 155 additions & 36 deletions

File tree

infCNN/LayerLib.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
from .Core import Layer
2-
from .conv import img2col
2+
from .conv import conv
33
import numpy as np
44

55
class Dense(Layer):
66

77
def __init__(self, n_in, n_out):
88
super().__init__('dense_{}_{}'.format(n_in, n_out))
9-
self.n_in = n_in
10-
self.n_out = n_out
11-
self.K = np.zeros((n_out, n_in), dtype='float32')
12-
self.bias = np.zeros(n_out, dtype='float32')
9+
self.n_in, self.n_out = n_in, n_out
10+
self.K = np.zeros((n_out, n_in), dtype=np.float32)
11+
self.bias = np.zeros(n_out, dtype=np.float32)
1312

1413
def forward(self, x):
1514
self.x = x
16-
w = self.K
17-
# the dense layer math: y = x*w
18-
y = w.dot(x.T)
19-
return y.T + self.bias.reshape((1, -1))
15+
y = x.dot(self.K.T)
16+
y += self.bias.reshape((1,-1))
17+
return y
2018

2119
def load_from_torch(self, weights, bias):
2220
self.K = weights.copy()
@@ -39,15 +37,10 @@ def __init__(self, C_in, C_out, K_s, Stride):
3937
self.K = np.zeros((C_out, C_in, K_s, K_s), dtype='float32')
4038
self.bias = np.zeros(C_out, dtype='float32')
4139

42-
# def forward(self, X):
43-
# out = conv_forward(X, self.K, self.bias, stride=self.stride, padding=self.pad_size)
44-
# return out
45-
4640
def forward(self, X):
47-
out = img2col(X, self.K)
48-
out = out.transpose(0, 2, 3, 1)
49-
out = out + self.bias
50-
return out.transpose(0, 3, 1, 2)
41+
out = conv(X, self.K)
42+
out += self.bias.reshape((1,-1,1,1))
43+
return out
5144

5245
def load_from_torch(self, weights, bias):
5346
self.K = weights.copy()

infCNN/OpLib.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .Core import Op
22
import numpy as np
33
from .im2col import im2col_indices
4+
from .maxpool import maxpool
45

56

67
class ReLU(Op):
@@ -86,4 +87,4 @@ def forward(self, x):
8687
flatten = Flatten()
8788
sigmoid = Sigmoid()
8889
softmax = Softmax()
89-
maxpool = MaxPool()
90+
maxpool = maxpool

infCNN/conv.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ def fill_col(pdimg, idx, colimg):
2222
s += 1
2323
return colimg
2424

25-
def img2col(img, core, buf=[np.zeros(1, dtype=np.int32)]):
25+
def conv(img, core, stride=(1,1), buf=[np.zeros(1, dtype=np.int32)]):
2626
# new the col_img, if needed
27+
strh, strw = stride
2728
cimg_w = np.cumprod(core.shape[1:])[-1]
28-
cimg_h = img.size//img.shape[1]
29+
n,c,h,w = img.shape
30+
cimg_h = n*(h//strh)*(w//strw)
31+
2932
if len(buf[0])<cimg_h*cimg_w:
3033
buf[0] = col_img = np.zeros(cimg_h*cimg_w, dtype=np.int32)
3134
else:
@@ -34,9 +37,8 @@ def img2col(img, core, buf=[np.zeros(1, dtype=np.int32)]):
3437

3538
# mark where need
3639
iimg = img.view(dtype=np.int32)
37-
# iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
3840
iimg &= 0xfffffffe
39-
iimg[:,0,:,:] |= 1
41+
iimg[:,0,::strh,::strw] |= 1
4042

4143
# ravel the image
4244
n,c,h,w = np.array(core.shape)
@@ -51,27 +53,22 @@ def img2col(img, core, buf=[np.zeros(1, dtype=np.int32)]):
5153
col_core = core.reshape((core.shape[0],-1))
5254
rst = col_core.dot(col_img.T)
5355
ni, ci, hi, wi = img.shape
54-
return rst.reshape((ni, n, hi, wi))
56+
return rst.reshape((ni, n, hi//strh, wi//strw))
5557

5658
if __name__ == '__main__':
5759
from skimage.data import camera
5860
import matplotlib.pyplot as plt
5961
from scipy.ndimage import convolve
6062
img = np.zeros((1, 3, 512, 512), dtype=np.float32)
61-
img.ravel()[:] = np.arange(3*512*512)
62-
63-
iimg = img.view(dtype=np.int32)
64-
# iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
65-
iimg &= 0xfffffffe
66-
iimg[:,0,:,:] |= 1
67-
63+
#img.ravel()[:] = np.arange(3*512*512)
6864
core = np.zeros((32, 3, 3, 3), dtype=np.float32)
69-
core.ravel()[:] = np.arange(3*3*3*32)
70-
65+
#core.ravel()[:] = np.arange(3*3*3*32)
66+
67+
rst1 = conv(img, core, (1,1))
7168
start = time()
72-
rst1 = img2col(img, core)
73-
print(time()-start)
69+
rst1 = conv(img, core, (1,1))
70+
print('jit cost:', time()-start)
7471

7572
start = time()
76-
rst = img2col(img, core)
77-
print('jit cost: x10', time()-start)
73+
rst2 = conv(img, core, (1,1))
74+
print('jit cost:', time()-start)

infCNN/conv_s.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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, stride=(1,1), buf=[np.zeros(1, dtype=np.int32)]):
26+
# new the col_img, if needed
27+
strh, strw = stride
28+
cimg_w = np.cumprod(core.shape[1:])[-1]
29+
print(img.shape)
30+
n,c,h,w = img.shape
31+
cimg_h = n*(h//strh)*(w//strw)
32+
33+
if len(buf[0])<cimg_h*cimg_w:
34+
buf[0] = col_img = np.zeros(cimg_h*cimg_w, dtype=np.int32)
35+
else:
36+
col_img = buf[0][:cimg_h*cimg_w]
37+
col_img[:] = 0
38+
39+
# mark where need
40+
iimg = img.view(dtype=np.int32)
41+
#iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
42+
iimg &= 0xfffffffe
43+
iimg[:,0,::strh,::strw] |= 1
44+
45+
# ravel the image
46+
n,c,h,w = np.array(core.shape)
47+
shp = ((0,0),(0,0),(h//2,h//2),(w//2,w//2))
48+
pdimg = np.pad(iimg, shp, 'constant', constant_values=0)
49+
nbs = neighbors(pdimg.shape[1:], core.shape[1:])
50+
fill_col(pdimg.ravel(), nbs, col_img)
51+
col_img = col_img.view(np.float32)
52+
col_img = col_img.reshape((cimg_h, cimg_w))
53+
54+
# dot
55+
col_core = core.reshape((core.shape[0],-1))
56+
rst = col_core.dot(col_img.T)
57+
ni, ci, hi, wi = img.shape
58+
return rst.reshape((ni, n, hi//strh, wi//strw))
59+
60+
if __name__ == '__main__':
61+
from skimage.data import camera
62+
import matplotlib.pyplot as plt
63+
from scipy.ndimage import convolve
64+
img = np.zeros((1, 3, 512, 512), dtype=np.float32)
65+
img.ravel()[:] = np.arange(3*512*512)
66+
67+
iimg = img.view(dtype=np.int32)
68+
iimg.view(dtype=np.uint8).ravel()[::4]&=0xfe
69+
iimg[:,0,:,:] |= 1
70+
71+
core = np.zeros((32, 3, 3, 3), dtype=np.float32)
72+
core.ravel()[:] = np.arange(3*3*3*32)
73+
74+
start = time()
75+
rst1 = img2col(img, core, (1,1))
76+
print(time()-start)
77+
78+
start = time()
79+
rst2 = img2col(img, core, (2,2))
80+
print('jit cost: x10', time()-start)

infCNN/maxpool.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
acc = np.cumprod((1,)+shape[::-1][:-1])
11+
return np.dot(idx.T, acc[::-1])
12+
13+
@njit
14+
def fill_col(pdimg, idx, colimg):
15+
s = 0
16+
for i in range(len(pdimg)):
17+
if pdimg[i]&1==0: continue
18+
for j in idx:
19+
colimg[s] = max(colimg[s], pdimg[i+j])
20+
s += 1
21+
return colimg
22+
23+
def maxpool(img, stride=(2,2)):
24+
strh, strw = stride
25+
n,c,h,w = img.shape
26+
cimg_h = n*c*(h//strh)*(w//strw)
27+
28+
iimg = img.view(dtype=np.int32)
29+
iimg &= 0xfffffffe
30+
iimg[:,:,::strh,::strw] |= 1
31+
32+
nbs = neighbors(img.shape[1:], (1,)+stride)
33+
shp = (n, c, h//strh, w//strw)
34+
colimg = np.zeros(shp, dtype=np.int32)
35+
fill_col(iimg.ravel(), nbs, colimg.ravel())
36+
return colimg.view(np.float32)
37+
38+
if __name__ == '__main__':
39+
img = np.zeros((1, 3, 512, 512), dtype=np.float32)
40+
41+
42+
start = time()
43+
rst1 = maxpool(img)
44+
print(time()-start)
45+
46+
start = time()
47+
rst = maxpool(img)
48+
print('jit cost: x10', time()-start)

0 commit comments

Comments
 (0)