nodev 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- __init__.py +0 -0
- nodev/__init__.py +18 -0
- nodev/core.py +297 -0
- nodev/cuda.py +27 -0
- nodev/dataloaders.py +65 -0
- nodev/dataset.py +186 -0
- nodev/layers.py +179 -0
- nodev/model.py +119 -0
- nodev/operations.py +389 -0
- nodev/operations_conv.py +474 -0
- nodev/optimizer.py +72 -0
- nodev/transforms.py +65 -0
- nodev/utils.py +172 -0
- nodev-1.0.0.dist-info/METADATA +14 -0
- nodev-1.0.0.dist-info/RECORD +17 -0
- nodev-1.0.0.dist-info/WHEEL +5 -0
- nodev-1.0.0.dist-info/top_level.txt +2 -0
nodev/operations_conv.py
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
|
|
2
|
+
from nodev.utils import get_conv_outsize,pair
|
|
3
|
+
from nodev import cuda, as_datafield
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from nodev.core import Operation
|
|
7
|
+
from nodev.operations import broadcast_to
|
|
8
|
+
|
|
9
|
+
def im2col(x, kernel_h, kernel_w, stride=1, pad=0,to_matrix=False): #x 输入 kenrnel_size 卷积核大小 stride 步幅 pad 填充 to_matrix 能否变形为矩阵
|
|
10
|
+
xp = cuda.get_array_module(x)
|
|
11
|
+
N, C, H, W = x.shape
|
|
12
|
+
|
|
13
|
+
out_h = get_conv_outsize(H, kernel_h, stride, pad)
|
|
14
|
+
out_w = get_conv_outsize(W, kernel_w, stride, pad)
|
|
15
|
+
|
|
16
|
+
img = xp.pad(x,
|
|
17
|
+
[(0,0),(0,0),(pad,pad),(pad,pad)],
|
|
18
|
+
'constant')
|
|
19
|
+
|
|
20
|
+
col = xp.zeros((N, C, kernel_h, kernel_w, out_h, out_w))
|
|
21
|
+
|
|
22
|
+
for y in range(kernel_h):
|
|
23
|
+
y_max = y + stride*out_h
|
|
24
|
+
for x in range(kernel_w):
|
|
25
|
+
x_max = x + stride*out_w
|
|
26
|
+
|
|
27
|
+
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
|
|
28
|
+
|
|
29
|
+
col = col.transpose(0,4,5,1,2,3).reshape(N*out_h*out_w, -1)
|
|
30
|
+
|
|
31
|
+
return col
|
|
32
|
+
"""def conv2d_simple(x,W,b=None,stride=1,pad=0):
|
|
33
|
+
x,W=as_variable(x),as_variable(W)
|
|
34
|
+
weight=W
|
|
35
|
+
N,C,H,W=x.shape
|
|
36
|
+
OC,C,KH,KW=weight.shape
|
|
37
|
+
SH,SW=pair(stride)
|
|
38
|
+
PH,PW=pair(pad)
|
|
39
|
+
OH=get_conv_outsize(H,KH,SH,PH)
|
|
40
|
+
OW=get_conv_outsize(W,KW,SW,PW)
|
|
41
|
+
col=im2col(x,(KH,KW),stride,pad,to_matrix=True)
|
|
42
|
+
weight=weight.reshape(OC,-1).transpose()
|
|
43
|
+
t=linear(col,weight,b)
|
|
44
|
+
y=t.reshape(N,OH,OW,OC).transpose(0,3,1,2)
|
|
45
|
+
return y"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Conv2d(Operation):
|
|
49
|
+
def __init__(self, stride=1, pad=0):
|
|
50
|
+
super().__init__()
|
|
51
|
+
self.stride = pair(stride)
|
|
52
|
+
self.pad = pair(pad)
|
|
53
|
+
|
|
54
|
+
def forward(self, x, W, b):
|
|
55
|
+
xp = cuda.get_array_module(x)
|
|
56
|
+
|
|
57
|
+
KH, KW = W.shape[2:]
|
|
58
|
+
col = im2col_array(x, (KH, KW), self.stride, self.pad, to_matrix=False)
|
|
59
|
+
#col = im2col_array(x, (KH, KW), self.stride, self.pad)
|
|
60
|
+
y = xp.tensordot(col, W, ((1, 2, 3), (1, 2, 3)))
|
|
61
|
+
if b is not None:
|
|
62
|
+
y += b
|
|
63
|
+
y = xp.rollaxis(y, 3, 1)
|
|
64
|
+
# y = np.transpose(y, (0, 3, 1, 2))
|
|
65
|
+
return y
|
|
66
|
+
|
|
67
|
+
def backward(self, gy):
|
|
68
|
+
x, W, b = self.inputs
|
|
69
|
+
# ==== gx ====
|
|
70
|
+
gx = deconv2d(gy, W, b=None, stride=self.stride, pad=self.pad,
|
|
71
|
+
outsize=(x.shape[2], x.shape[3]))
|
|
72
|
+
# ==== gW ====
|
|
73
|
+
gW = Conv2DGradW(self)(x, gy)
|
|
74
|
+
# ==== gb ====
|
|
75
|
+
gb = None
|
|
76
|
+
if b.data is not None:
|
|
77
|
+
gb = gy.sum(axis=(0, 2, 3))
|
|
78
|
+
return gx, gW, gb
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def conv2d(x, W, b=None, stride=1, pad=0):
|
|
82
|
+
return Conv2d(stride, pad)(x, W, b)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class Deconv2d(Operation):
|
|
86
|
+
def __init__(self, stride=1, pad=0, outsize=None):
|
|
87
|
+
super().__init__()
|
|
88
|
+
self.stride = pair(stride)
|
|
89
|
+
self.pad = pair(pad)
|
|
90
|
+
self.outsize = outsize
|
|
91
|
+
|
|
92
|
+
def forward(self, x, W, b):
|
|
93
|
+
xp = cuda.get_array_module(x)
|
|
94
|
+
|
|
95
|
+
Weight = W
|
|
96
|
+
SH, SW = self.stride
|
|
97
|
+
PH, PW = self.pad
|
|
98
|
+
C, OC, KH, KW = Weight.shape
|
|
99
|
+
N, C, H, W = x.shape
|
|
100
|
+
if self.outsize is None:
|
|
101
|
+
out_h = get_deconv_outsize(H, KH, SH, PH)
|
|
102
|
+
out_w = get_deconv_outsize(W, KW, SW, PW)
|
|
103
|
+
else:
|
|
104
|
+
out_h, out_w = pair(self.outsize)
|
|
105
|
+
img_shape = (N, OC, out_h, out_w)
|
|
106
|
+
|
|
107
|
+
gcol = xp.tensordot(Weight, x, (0, 1))
|
|
108
|
+
gcol = xp.rollaxis(gcol, 3)
|
|
109
|
+
y = col2im_array(gcol, img_shape, (KH, KW), self.stride, self.pad,
|
|
110
|
+
to_matrix=False)
|
|
111
|
+
# b, k, h, w
|
|
112
|
+
if b is not None:
|
|
113
|
+
self.no_bias = True
|
|
114
|
+
y += b.reshape((1, b.size, 1, 1))
|
|
115
|
+
return y
|
|
116
|
+
|
|
117
|
+
def backward(self, gy):
|
|
118
|
+
x, W, b = self.inputs
|
|
119
|
+
|
|
120
|
+
# ==== gx ====
|
|
121
|
+
gx = conv2d(gy, W, b=None, stride=self.stride, pad=self.pad)
|
|
122
|
+
# ==== gW ====
|
|
123
|
+
f = Conv2DGradW(self)
|
|
124
|
+
gW = f(gy, x)
|
|
125
|
+
# ==== gb ====
|
|
126
|
+
gb = None
|
|
127
|
+
if b.data is not None:
|
|
128
|
+
gb = gy.sum(axis=(0, 2, 3))
|
|
129
|
+
return gx, gW, gb
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def deconv2d(x, W, b=None, stride=1, pad=0, outsize=None):
|
|
133
|
+
return Deconv2d(stride, pad, outsize)(x, W, b)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class Conv2DGradW(Operation):
|
|
137
|
+
def __init__(self, conv2d):
|
|
138
|
+
W = conv2d.inputs[1]
|
|
139
|
+
kh, kw = W.shape[2:]
|
|
140
|
+
self.kernel_size = (kh, kw)
|
|
141
|
+
self.stride = conv2d.stride
|
|
142
|
+
self.pad = conv2d.pad
|
|
143
|
+
|
|
144
|
+
def forward(self, x, gy):
|
|
145
|
+
xp = cuda.get_array_module(x)
|
|
146
|
+
|
|
147
|
+
col = im2col_array(x, self.kernel_size, self.stride, self.pad,
|
|
148
|
+
to_matrix=False)
|
|
149
|
+
gW = xp.tensordot(gy, col, ((0, 2, 3), (0, 4, 5)))
|
|
150
|
+
return gW
|
|
151
|
+
|
|
152
|
+
def backward(self, gys):
|
|
153
|
+
x, gy = self.inputs
|
|
154
|
+
gW, = self.outputs
|
|
155
|
+
|
|
156
|
+
xh, xw = x.shape[2:]
|
|
157
|
+
gx = deconv2d(gy, gW, stride=self.stride, pad=self.pad,
|
|
158
|
+
outsize=(xh, xw))
|
|
159
|
+
ggy = conv2d(x, gW, stride=self.stride, pad=self.pad)
|
|
160
|
+
return gx, ggy
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# =============================================================================
|
|
164
|
+
# pooling(max-pooling) / average_pooling
|
|
165
|
+
# =============================================================================
|
|
166
|
+
class Pooling(Operation):
|
|
167
|
+
def __init__(self, kernel_size, stride=1, pad=0):
|
|
168
|
+
super().__init__()
|
|
169
|
+
self.kernel_size = kernel_size
|
|
170
|
+
self.stride = stride
|
|
171
|
+
self.pad = pad
|
|
172
|
+
|
|
173
|
+
def forward(self, x):
|
|
174
|
+
col = im2col_array(x, self.kernel_size, self.stride, self.pad,
|
|
175
|
+
to_matrix=False)
|
|
176
|
+
|
|
177
|
+
N, C, KH, KW, OH, OW = col.shape
|
|
178
|
+
col = col.reshape(N, C, KH * KW, OH, OW)
|
|
179
|
+
self.indexes = col.argmax(axis=2)
|
|
180
|
+
y = col.max(axis=2)
|
|
181
|
+
return y
|
|
182
|
+
|
|
183
|
+
def backward(self, gy):
|
|
184
|
+
return Pooling2DGrad(self)(gy)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class Pooling2DGrad(Operation):
|
|
188
|
+
def __init__(self, mpool2d):
|
|
189
|
+
self.mpool2d = mpool2d
|
|
190
|
+
self.kernel_size = mpool2d.kernel_size
|
|
191
|
+
self.stride = mpool2d.stride
|
|
192
|
+
self.pad = mpool2d.pad
|
|
193
|
+
self.input_shape = mpool2d.inputs[0].shape
|
|
194
|
+
self.dtype = mpool2d.inputs[0].dtype
|
|
195
|
+
self.indexes = mpool2d.indexes
|
|
196
|
+
|
|
197
|
+
def forward(self, gy):
|
|
198
|
+
xp = cuda.get_array_module(gy)
|
|
199
|
+
|
|
200
|
+
N, C, OH, OW = gy.shape
|
|
201
|
+
N, C, H, W = self.input_shape
|
|
202
|
+
KH, KW = pair(self.kernel_size)
|
|
203
|
+
|
|
204
|
+
gcol = xp.zeros((N * C * OH * OW * KH * KW), dtype=self.dtype)
|
|
205
|
+
|
|
206
|
+
indexes = (self.indexes.ravel()
|
|
207
|
+
+ xp.arange(0, self.indexes.size * KH * KW, KH * KW))
|
|
208
|
+
|
|
209
|
+
gcol[indexes] = gy.ravel()
|
|
210
|
+
gcol = gcol.reshape(N, C, OH, OW, KH, KW)
|
|
211
|
+
gcol = xp.swapaxes(gcol, 2, 4)
|
|
212
|
+
gcol = xp.swapaxes(gcol, 3, 5)
|
|
213
|
+
|
|
214
|
+
gx = col2im_array(gcol, (N, C, H, W), self.kernel_size, self.stride,
|
|
215
|
+
self.pad, to_matrix=False)
|
|
216
|
+
return gx
|
|
217
|
+
|
|
218
|
+
def backward(self, ggx):
|
|
219
|
+
f = Pooling2DWithIndexes(self.mpool2d)
|
|
220
|
+
return f(ggx)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class Pooling2DWithIndexes(Operation):
|
|
224
|
+
def __init__(self, mpool2d):
|
|
225
|
+
self.kernel_size = mpool2d.kernel_size
|
|
226
|
+
self.stride = mpool2d.stride
|
|
227
|
+
self.pad = mpool2d.pad
|
|
228
|
+
self.input_shpae = mpool2d.inputs[0].shape
|
|
229
|
+
self.dtype = mpool2d.inputs[0].dtype
|
|
230
|
+
self.indexes = mpool2d.indexes
|
|
231
|
+
|
|
232
|
+
def forward(self, x):
|
|
233
|
+
col = im2col_array(x, self.kernel_size, self.stride, self.pad,
|
|
234
|
+
to_matrix=False)
|
|
235
|
+
N, C, KH, KW, OH, OW = col.shape
|
|
236
|
+
col = col.reshape(N, C, KH * KW, OH, OW)
|
|
237
|
+
col = col.transpose(0, 1, 3, 4, 2).reshape(-1, KH * KW)
|
|
238
|
+
indexes = self.indexes.ravel()
|
|
239
|
+
col = col[np.arange(len(indexes)), indexes]
|
|
240
|
+
return col.reshape(N, C, OH, OW)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def pooling(x, kernel_size, stride=1, pad=0):
|
|
244
|
+
return Pooling(kernel_size, stride, pad)(x)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class AveragePooling(Operation):
|
|
248
|
+
def __init__(self, kernel_size, stride=1, pad=0):
|
|
249
|
+
super().__init__()
|
|
250
|
+
self.kernel_size = kernel_size
|
|
251
|
+
self.stride = stride
|
|
252
|
+
self.pad = pad
|
|
253
|
+
self.input_shape = None
|
|
254
|
+
|
|
255
|
+
def forward(self, x):
|
|
256
|
+
self.input_shape = x.shape
|
|
257
|
+
col = im2col_array(x, self.kernel_size, self.stride, self.pad,
|
|
258
|
+
to_matrix=False)
|
|
259
|
+
y = col.mean(axis=(2, 3))
|
|
260
|
+
return y
|
|
261
|
+
|
|
262
|
+
def backward(self, gy):
|
|
263
|
+
# TODO(Koki): This is simple implementation
|
|
264
|
+
N, C, OH, OW = gy.shape
|
|
265
|
+
KW, KH = pair(self.kernel_size)
|
|
266
|
+
gy /= (KW * KH)
|
|
267
|
+
gcol = broadcast_to(gy.reshape(-1), (KH, KW, N * C * OH * OW))
|
|
268
|
+
gcol = gcol.reshape(KH, KW, N, C, OH, OW).transpose(2, 3, 0, 1, 4, 5)
|
|
269
|
+
gx = col2im(gcol, self.input_shape, self.kernel_size, self.stride,
|
|
270
|
+
self.pad, to_matrix=False)
|
|
271
|
+
return gx
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def average_pooling(x, kernel_size, stride=1, pad=0):
|
|
275
|
+
return AveragePooling(kernel_size, stride, pad)(x)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# =============================================================================
|
|
279
|
+
# im2col / col2im
|
|
280
|
+
# =============================================================================
|
|
281
|
+
class Im2col(Operation):
|
|
282
|
+
def __init__(self, kernel_size, stride, pad, to_matrix):
|
|
283
|
+
super().__init__()
|
|
284
|
+
self.input_shape = None
|
|
285
|
+
self.kernel_size = kernel_size
|
|
286
|
+
self.stride = stride
|
|
287
|
+
self.pad = pad
|
|
288
|
+
self.to_matrix = to_matrix
|
|
289
|
+
|
|
290
|
+
def forward(self, x):
|
|
291
|
+
self.input_shape = x.shape
|
|
292
|
+
y = im2col_array(x, self.kernel_size, self.stride, self.pad,
|
|
293
|
+
self.to_matrix)
|
|
294
|
+
return y
|
|
295
|
+
|
|
296
|
+
def backward(self, gy):
|
|
297
|
+
gx = col2im(gy, self.input_shape, self.kernel_size, self.stride,
|
|
298
|
+
self.pad, self.to_matrix)
|
|
299
|
+
return gx
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class Col2im(Operation):
|
|
304
|
+
def __init__(self, input_shape, kernel_size, stride, pad, to_matrix):
|
|
305
|
+
super().__init__()
|
|
306
|
+
self.input_shape = input_shape
|
|
307
|
+
self.kernel_size = kernel_size
|
|
308
|
+
self.stride = stride
|
|
309
|
+
self.pad = pad
|
|
310
|
+
self.to_matrix = to_matrix
|
|
311
|
+
|
|
312
|
+
def forward(self, x):
|
|
313
|
+
y = col2im_array(x, self.input_shape, self.kernel_size, self.stride,
|
|
314
|
+
self.pad, self.to_matrix)
|
|
315
|
+
return y
|
|
316
|
+
|
|
317
|
+
def backward(self, gy):
|
|
318
|
+
gx = im2col(gy, self.kernel_size, self.stride, self.pad,
|
|
319
|
+
self.to_matrix)
|
|
320
|
+
return gx
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def col2im(x, input_shape, kernel_size, stride=1, pad=0, to_matrix=True):
|
|
324
|
+
return Col2im(input_shape, kernel_size, stride, pad, to_matrix)(x)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
# =============================================================================
|
|
328
|
+
# numpy im2col
|
|
329
|
+
# =============================================================================
|
|
330
|
+
def im2col_array(img, kernel_size, stride, pad, to_matrix=True):
|
|
331
|
+
N, C, H, W = img.shape
|
|
332
|
+
KH, KW = pair(kernel_size)
|
|
333
|
+
SH, SW = pair(stride)
|
|
334
|
+
PH, PW = pair(pad)
|
|
335
|
+
OH = get_conv_outsize(H, KH, SH, PH)
|
|
336
|
+
OW = get_conv_outsize(W, KW, SW, PW)
|
|
337
|
+
|
|
338
|
+
xp = cuda.get_array_module(img)
|
|
339
|
+
if xp != np:
|
|
340
|
+
col = _im2col_gpu(img, kernel_size, stride, pad)
|
|
341
|
+
else:
|
|
342
|
+
img = np.pad(img,
|
|
343
|
+
((0, 0), (0, 0), (PH, PH + SH - 1), (PW, PW + SW - 1)),
|
|
344
|
+
mode='constant', constant_values=(0,))
|
|
345
|
+
col = np.ndarray((N, C, KH, KW, OH, OW), dtype=img.dtype)
|
|
346
|
+
|
|
347
|
+
for j in range(KH):
|
|
348
|
+
j_lim = j + SH * OH
|
|
349
|
+
for i in range(KW):
|
|
350
|
+
i_lim = i + SW * OW
|
|
351
|
+
col[:, :, j, i, :, :] = img[:, :, j:j_lim:SH, i:i_lim:SW]
|
|
352
|
+
|
|
353
|
+
if to_matrix:
|
|
354
|
+
col = col.transpose((0, 4, 5, 1, 2, 3)).reshape((N * OH * OW, -1))
|
|
355
|
+
|
|
356
|
+
return col
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def col2im_array(col, img_shape, kernel_size, stride, pad, to_matrix=True):
|
|
360
|
+
N, C, H, W = img_shape
|
|
361
|
+
KH, KW = pair(kernel_size)
|
|
362
|
+
SH, SW = pair(stride)
|
|
363
|
+
PH, PW = pair(pad)
|
|
364
|
+
OH = get_conv_outsize(H, KH, SH, PH)
|
|
365
|
+
OW = get_conv_outsize(W, KW, SW, PW)
|
|
366
|
+
|
|
367
|
+
if to_matrix:
|
|
368
|
+
col = col.reshape(N, OH, OW, C, KH, KW).transpose(0, 3, 4, 5, 1, 2)
|
|
369
|
+
|
|
370
|
+
xp = cuda.get_array_module(col)
|
|
371
|
+
if xp != np:
|
|
372
|
+
img = _col2im_gpu(col, SH, SW, PH, PW, H, W)
|
|
373
|
+
return img
|
|
374
|
+
else:
|
|
375
|
+
img = np.zeros((N, C, H + 2 * PH + SH - 1, W + 2 * PW + SW - 1),
|
|
376
|
+
dtype=col.dtype)
|
|
377
|
+
for j in range(KH):
|
|
378
|
+
j_lim = j + SH * OH
|
|
379
|
+
for i in range(KW):
|
|
380
|
+
i_lim = i + SW * OW
|
|
381
|
+
img[:, :, j:j_lim:SH, i:i_lim:SW] += col[:, :, j, i, :, :]
|
|
382
|
+
return img[:, :, PH:H + PH, PW:W + PW]
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _im2col_gpu(img, kernel_size, stride, pad):
|
|
386
|
+
"""im2col function for GPU.
|
|
387
|
+
This code is ported from Chainer:
|
|
388
|
+
https://github.com/chainer/chainer/blob/v6.4.0/chainer/utils/conv.py
|
|
389
|
+
"""
|
|
390
|
+
n, c, h, w = img.shape
|
|
391
|
+
kh, kw = pair(kernel_size)
|
|
392
|
+
sy, sx = pair(stride)
|
|
393
|
+
ph, pw = pair(pad)
|
|
394
|
+
out_h = get_conv_outsize(h, kh, sy, ph)
|
|
395
|
+
out_w = get_conv_outsize(w, kw, sx, pw)
|
|
396
|
+
dy, dx = 1, 1
|
|
397
|
+
col = cuda.cupy.empty((n, c, kh, kw, out_h, out_w), dtype=img.dtype)
|
|
398
|
+
|
|
399
|
+
cuda.cupy.ElementwiseKernel(
|
|
400
|
+
'raw T img, int32 h, int32 w, int32 out_h, int32 out_w,'
|
|
401
|
+
'int32 kh, int32 kw, int32 sy, int32 sx, int32 ph, int32 pw,'
|
|
402
|
+
'int32 dy, int32 dx',
|
|
403
|
+
'T col',
|
|
404
|
+
'''
|
|
405
|
+
int c0 = i / (kh * kw * out_h * out_w);
|
|
406
|
+
int ky = i / (kw * out_h * out_w) % kh;
|
|
407
|
+
int kx = i / (out_h * out_w) % kw;
|
|
408
|
+
int out_y = i / out_w % out_h;
|
|
409
|
+
int out_x = i % out_w;
|
|
410
|
+
int in_y = ky * dy + out_y * sy - ph;
|
|
411
|
+
int in_x = kx * dx + out_x * sx - pw;
|
|
412
|
+
if (in_y >= 0 && in_y < h && in_x >= 0 && in_x < w) {
|
|
413
|
+
col = img[in_x + w * (in_y + h * c0)];
|
|
414
|
+
} else {
|
|
415
|
+
col = 0;
|
|
416
|
+
}
|
|
417
|
+
''',
|
|
418
|
+
'im2col')(img.reduced_view(),
|
|
419
|
+
h, w, out_h, out_w, kh, kw, sy, sx, ph, pw, dy, dx, col)
|
|
420
|
+
|
|
421
|
+
return col
|
|
422
|
+
def get_deconv_outsize(size, k, stride, pad):
|
|
423
|
+
return stride * (size - 1) + k - 2 * pad
|
|
424
|
+
def _col2im_gpu(col, sy, sx, ph, pw, h, w):
|
|
425
|
+
"""col2im function for GPU.
|
|
426
|
+
This code is ported from Chainer:
|
|
427
|
+
https://github.com/chainer/chainer/blob/v6.4.0/chainer/utils/conv.py
|
|
428
|
+
"""
|
|
429
|
+
n, c, kh, kw, out_h, out_w = col.shape
|
|
430
|
+
dx, dy = 1, 1
|
|
431
|
+
img = cuda.cupy.empty((n, c, h, w), dtype=col.dtype)
|
|
432
|
+
|
|
433
|
+
cuda.cupy.ElementwiseKernel(
|
|
434
|
+
'raw T col, int32 h, int32 w, int32 out_h, int32 out_w,'
|
|
435
|
+
'int32 kh, int32 kw, int32 sy, int32 sx, int32 ph, int32 pw,'
|
|
436
|
+
'int32 dx, int32 dy',
|
|
437
|
+
'T img',
|
|
438
|
+
'''
|
|
439
|
+
int c0 = i / (h * w);
|
|
440
|
+
int y = i / w % h;
|
|
441
|
+
int x = i % w;
|
|
442
|
+
T val = 0;
|
|
443
|
+
for (int ky = 0; ky < kh; ++ky) {
|
|
444
|
+
int out_y = (y + ph - ky * dy);
|
|
445
|
+
if (0 > out_y || out_y >= out_h * sy) continue;
|
|
446
|
+
if (out_y % sy != 0) continue;
|
|
447
|
+
out_y /= sy;
|
|
448
|
+
for (int kx = 0; kx < kw; ++kx) {
|
|
449
|
+
int out_x = (x + pw - kx * dx);
|
|
450
|
+
if (0 > out_x || out_x >= out_w * sx) continue;
|
|
451
|
+
if (out_x % sx != 0) continue;
|
|
452
|
+
out_x /= sx;
|
|
453
|
+
int k = out_y + out_h * (kx + kw * (ky + kh * c0));
|
|
454
|
+
val = val + col[out_x + out_w * k];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
img = val;
|
|
458
|
+
''',
|
|
459
|
+
'col2im')(col.reduced_view(),
|
|
460
|
+
h, w, out_h, out_w, kh, kw, sy, sx, ph, pw, dx, dy, img)
|
|
461
|
+
return img
|
|
462
|
+
def pooling_simple(x,kernel_size,stride=1,pad=0):
|
|
463
|
+
x=as_datafield(x)
|
|
464
|
+
N,C,H,W=x.shape
|
|
465
|
+
KH,KW=pair(kernel_size)
|
|
466
|
+
PH,PW=pair(pad)
|
|
467
|
+
SH,SW=pair(stride)
|
|
468
|
+
OH=get_conv_outsize(H,KH,SH,PH)
|
|
469
|
+
OW=get_conv_outsize(W,KW,SW,PW)
|
|
470
|
+
col=im2col(x,kernel_size,stride,pad,to_matrix=True)
|
|
471
|
+
col=col.reshape(-1,KH*KW)
|
|
472
|
+
y=col.max(axis=1)
|
|
473
|
+
y=y.reshape((N,OH,OW,C)).transpose(0,3,1,2)
|
|
474
|
+
return y
|
nodev/optimizer.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
import math
|
|
3
|
+
from nodev import cuda
|
|
4
|
+
from nodev.cuda import get_array_module
|
|
5
|
+
|
|
6
|
+
class Optimizer:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.target=None
|
|
9
|
+
self.hooks=[]
|
|
10
|
+
def setup(self,target):
|
|
11
|
+
self.target=target
|
|
12
|
+
return self
|
|
13
|
+
def update(self):
|
|
14
|
+
params=[p for p in self.target.params() if p.grad is not None]
|
|
15
|
+
#预处理
|
|
16
|
+
for f in self.hooks:
|
|
17
|
+
f(params)
|
|
18
|
+
#更新参数
|
|
19
|
+
for param in params:
|
|
20
|
+
self.update_one(param)
|
|
21
|
+
def update_one(self,param):
|
|
22
|
+
raise NotImplementedError
|
|
23
|
+
def add_hook(self,f):
|
|
24
|
+
self.hooks.append(f)
|
|
25
|
+
|
|
26
|
+
class SGD(Optimizer):
|
|
27
|
+
def __init__(self,lr=0.01):
|
|
28
|
+
super().__init__()
|
|
29
|
+
self.lr=lr
|
|
30
|
+
|
|
31
|
+
def update_one(self,param):
|
|
32
|
+
param.data-=self.lr*param.grad.data
|
|
33
|
+
|
|
34
|
+
class MomentumSGD(Optimizer):
|
|
35
|
+
def __init__(self,lr=0.01,momentum=0.9):
|
|
36
|
+
super().__init__()
|
|
37
|
+
self.lr=lr
|
|
38
|
+
self.momentum=momentum
|
|
39
|
+
self.vs={}
|
|
40
|
+
def update_one(self,param):
|
|
41
|
+
v_key=id(param)
|
|
42
|
+
if v_key not in self.vs:
|
|
43
|
+
xp = get_array_module(param.data)
|
|
44
|
+
self.vs[v_key] = xp.zeros_like(param.data)
|
|
45
|
+
|
|
46
|
+
v=self.vs[v_key]
|
|
47
|
+
v*=self.momentum
|
|
48
|
+
v-=self.lr*param.grad.data
|
|
49
|
+
param.data += v
|
|
50
|
+
|
|
51
|
+
class AdaGrad(Optimizer):
|
|
52
|
+
def __init__(self, lr=0.001, eps=1e-8):
|
|
53
|
+
super().__init__()
|
|
54
|
+
self.lr = lr
|
|
55
|
+
self.eps = eps
|
|
56
|
+
self.hs = {}
|
|
57
|
+
|
|
58
|
+
def update_one(self, param):
|
|
59
|
+
xp = cuda.get_array_module(param.data)
|
|
60
|
+
|
|
61
|
+
h_key = id(param)
|
|
62
|
+
if h_key not in self.hs:
|
|
63
|
+
self.hs[h_key] = xp.zeros_like(param.data)
|
|
64
|
+
|
|
65
|
+
lr = self.lr
|
|
66
|
+
eps = self.eps
|
|
67
|
+
grad = param.grad.data
|
|
68
|
+
h = self.hs[h_key]
|
|
69
|
+
|
|
70
|
+
h += grad * grad
|
|
71
|
+
param.data -= lr * grad / (xp.sqrt(h) + eps)
|
|
72
|
+
|
nodev/transforms.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Compose:
|
|
5
|
+
"""Compose multiple transforms."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, transforms=[]):
|
|
8
|
+
self.transforms = transforms
|
|
9
|
+
|
|
10
|
+
def __call__(self, x):
|
|
11
|
+
if not self.transforms:
|
|
12
|
+
return x
|
|
13
|
+
for t in self.transforms:
|
|
14
|
+
x = t(x)
|
|
15
|
+
return x
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Flatten:
|
|
19
|
+
"""Flatten ndarray."""
|
|
20
|
+
|
|
21
|
+
def __call__(self, x):
|
|
22
|
+
return x.reshape(-1)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ToFloat:
|
|
26
|
+
"""Convert ndarray dtype to float32."""
|
|
27
|
+
|
|
28
|
+
def __call__(self, x):
|
|
29
|
+
return x.astype(np.float32)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Normalize:
|
|
33
|
+
"""Normalize ndarray."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, mean=0., std=1.):
|
|
36
|
+
self.mean = mean
|
|
37
|
+
self.std = std
|
|
38
|
+
|
|
39
|
+
def __call__(self, x):
|
|
40
|
+
mean = self.mean
|
|
41
|
+
std = self.std
|
|
42
|
+
|
|
43
|
+
if not np.isscalar(mean):
|
|
44
|
+
mean = np.array(mean, dtype=x.dtype)
|
|
45
|
+
if not np.isscalar(std):
|
|
46
|
+
std = np.array(std, dtype=x.dtype)
|
|
47
|
+
|
|
48
|
+
return (x - mean) / std
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AsType:
|
|
52
|
+
"""Convert ndarray dtype."""
|
|
53
|
+
|
|
54
|
+
def __init__(self, dtype=np.float32):
|
|
55
|
+
self.dtype = dtype
|
|
56
|
+
|
|
57
|
+
def __call__(self, x):
|
|
58
|
+
return x.astype(self.dtype)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ToInt:
|
|
62
|
+
"""Convert ndarray dtype to int."""
|
|
63
|
+
|
|
64
|
+
def __call__(self, x):
|
|
65
|
+
return x.astype(np.int32)
|