forked from benanne/kaggle-ndsb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtmp_dnn.py
157 lines (130 loc) · 6.02 KB
/
tmp_dnn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""
cuDNN based layers
"""
import theano
import theano.tensor as T
from lasagne import init
from lasagne import nonlinearities
from lasagne.layers.base import Layer
dnn_available = False
if theano.config.device.startswith("gpu"):
from theano.sandbox.cuda import dnn
if dnn.dnn_available():
dnn_available = True
__all__ = [
"Pool2DDNNLayer",
"MaxPool2DDNNLayer",
"Conv2DDNNLayer",
]
class DNNLayer(Layer):
pass
class Pool2DDNNLayer(DNNLayer):
def __init__(self, input_layer, ds, strides=None, mode='max'):
super(Pool2DDNNLayer, self).__init__(input_layer)
self.ds = ds # a tuple
self.mode = mode
self.strides = strides if strides is not None else ds
def get_output_shape_for(self, input_shape):
output_shape = list(input_shape) # copy / convert to mutable list
output_shape[2] = (output_shape[2] - self.ds[0]) // self.strides[0] + 1
output_shape[3] = (output_shape[3] - self.ds[1]) // self.strides[1] + 1
return tuple(output_shape)
def get_output_for(self, input, *args, **kwargs):
if not dnn_available:
raise RuntimeError("cudnn is not available.")
return dnn.dnn_pool(input, self.ds, self.strides, self.mode)
class MaxPool2DDNNLayer(Pool2DDNNLayer): # for consistency
def __init__(self, input_layer, ds, strides=None):
super(MaxPool2DDNNLayer, self).__init__(input_layer, ds, strides, mode='max')
class RMSPool2DDNNLayer(Pool2DDNNLayer):
def __init__(self, input_layer, ds, strides=None, epsilon=1e-12):
super(RMSPool2DDNNLayer, self).__init__(input_layer, ds, strides)
self.epsilon = epsilon
del self.mode
def get_output_for(self, input, *args, **kwargs):
if not dnn_available:
raise RuntimeError("cudnn is not available.")
out = dnn.dnn_pool(T.sqr(input), self.ds, self.strides, 'average')
return T.sqrt(out + self.epsilon)
class Conv2DDNNLayer(DNNLayer):
def __init__(self, input_layer, num_filters, filter_size, strides=(1, 1), border_mode=None, untie_biases=False,
W=init.Uniform(), b=init.Constant(0.), nonlinearity=nonlinearities.rectify, pad=None,
flip_filters=False):
super(Conv2DDNNLayer, self).__init__(input_layer)
if nonlinearity is None:
self.nonlinearity = nonlinearities.identity
else:
self.nonlinearity = nonlinearity
self.num_filters = num_filters
self.filter_size = filter_size
if isinstance(strides, int):
strides = (strides, strides)
self.strides = strides
self.untie_biases = untie_biases
self.flip_filters = flip_filters
if border_mode is not None and pad is not None:
raise RuntimeError("You cannot specify both 'border_mode' and 'pad'. To avoid ambiguity, please specify only one of them.")
elif border_mode is None and pad is None:
# no option specified, default to valid mode
self.pad = (0, 0)
self.border_mode = 'valid'
elif border_mode is not None:
if border_mode == 'valid':
self.pad = (0, 0)
self.border_mode = 'valid'
elif border_mode == 'full':
self.pad = (self.filter_size[0] - 1, self.filter_size[1] - 1)
self.border_mode = 'full'
elif border_mode == 'same':
# dnn_conv does not support same, so we just specify padding directly.
# only works for odd filter size, but the even filter size case is probably not worth supporting.
self.pad = ((self.filter_size[0] - 1) // 2, (self.filter_size[1] - 1) // 2)
self.border_mode = None
else:
raise RuntimeError("Unsupported border_mode for Conv2DDNNLayer: %s" % border_mode)
else:
if isinstance(pad, int):
pad = (pad, pad)
self.pad = pad
self.W = self.create_param(W, self.get_W_shape())
if b is None:
self.b = None
elif self.untie_biases:
output_shape = self.get_output_shape()
self.b = self.create_param(b, (num_filters, output_shape[2], output_shape[3]))
else:
self.b = self.create_param(b, (num_filters,))
def get_W_shape(self):
num_input_channels = self.input_layer.get_output_shape()[1]
return (self.num_filters, num_input_channels, self.filter_size[0], self.filter_size[1])
def get_params(self):
return [self.W] + self.get_bias_params()
def get_bias_params(self):
return [self.b] if self.b is not None else []
def get_output_shape_for(self, input_shape):
batch_size = input_shape[0]
input_rows, input_columns = input_shape[2:4]
output_rows = (input_rows + 2*self.pad[0] - self.filter_size[0]) // self.strides[0] + 1
output_columns = (input_columns + 2*self.pad[1] - self.filter_size[1]) // self.strides[1] + 1
return (batch_size, self.num_filters, output_rows, output_columns)
def get_output_for(self, input, *args, **kwargs):
if not dnn_available:
raise RuntimeError("cudnn is not available.")
# by default we assume 'cross', consistent with earlier versions of conv2d.
conv_mode = 'conv' if self.flip_filters else 'cross'
# if 'border_mode' is one of 'valid' or 'full' use that.
# else use pad directly.
border_mode = self.border_mode if (self.border_mode is not None) else self.pad
conved = dnn.dnn_conv(img=input,
kerns=self.W,
subsample=self.strides,
border_mode=border_mode,
conv_mode=conv_mode
)
if self.b is None:
activation = conved
elif self.untie_biases:
activation = conved + self.b.dimshuffle('x', 0, 1, 2)
else:
activation = conved + self.b.dimshuffle('x', 0, 'x', 'x')
return self.nonlinearity(activation)