-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathneural_layers.py
176 lines (130 loc) · 5.03 KB
/
neural_layers.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import numpy as np
import chained_operations as op
class Layer(op.ChainedOperation):
def __init__(self, inputs=None):
inputs = inputs or []
super(Layer, self).__init__(inputs)
self.is_locked = False
self.firsts = [op.Placeholder() for _ in inputs]
self.input_shapes = []
for i in inputs:
if isinstance(i, Layer):
self.input_shapes.append(i.get_output_len())
else:
self.input_shapes.append(None)
self.last, self.variables = self.build_layer(self.firsts)
self.variables = self.variables or []
if not isinstance(self.variables, (list, tuple)):
self.variables = [self.variables]
def backwards(self, output_object=None):
if self.last is not None:
if output_object is not None:
self.last.grad = output_object.get_grad(self)
if self.last != self:
self.last.backwards()
super(Layer, self).backwards(output_object)
def calc_forwards(self, inputs):
for i, input_value in enumerate(inputs):
self.firsts[i].run(input_value)
if self.last is not None:
return self.last.output
def get_grad(self, input_object=None):
if input_object is None:
return self.grad
index = self.input_objects.index(input_object)
return self.firsts[index].grad
def calc_backwards(self, input_object):
pass
def get_variables(self):
if self.is_locked:
return []
return self.variables
def lock(self):
self.is_locked = True
def unlock(self):
self.is_locked = False
def set_inputs(self, new_inputs=None):
new_inputs = new_inputs or []
if not len(new_inputs) == len(self.input_objects):
raise ValueError('cannot change inputs number')
self.input_objects = new_inputs or []
self.inputs_ready = {}
for i in self.input_objects:
if isinstance(i, op.ChainedOperation):
if not isinstance(i, op.Variable):
self.inputs_ready[i] = False
i.add_output(self)
def get_output_len(self):
raise NotImplementedError()
def build_layer(self, inputs):
raise NotImplementedError()
class InputLayer(op.Placeholder, Layer):
def __init__(self, size=0, axis=1):
self.size = size
self.axis = axis
super(InputLayer, self).__init__()
def build_layer(self, inputs):
return None, None
def get_output_len(self):
return self.size
def run(self, value):
shape = np.shape(value)
if len(shape) < self.axis + 1 or shape[self.axis] != self.size:
raise ValueError('value shape not matching size %d in axis %d' % (self.size, self.axis))
super(InputLayer, self).run(value)
class VariableLayer(op.Variable, Layer):
def __init__(self, depth=0, size=0):
self.size = size
super(VariableLayer, self).__init__((depth, size))
def get_output_len(self):
return self.size
def build_layer(self, inputs):
return self, self
class UnaryLayer(Layer):
def __init__(self, x):
super(UnaryLayer, self).__init__([x])
def build_layer(self, inputs):
return self.build_unary_layer(inputs[0])
def build_unary_layer(self, x):
raise NotImplementedError()
def get_output_len(self):
return self.get_unary_len(self.input_shapes[0])
def get_unary_len(self, shape):
raise NotImplementedError()
def set_inputs(self, new_input=None):
super(UnaryLayer, self).set_inputs([new_input])
class BinaryLayer(Layer):
def __init__(self, a, b):
super(BinaryLayer, self).__init__([a, b])
def build_layer(self, inputs):
return self.build_binary_layer(inputs[0], inputs[1])
def build_binary_layer(self, a, b):
raise NotImplementedError()
def get_output_len(self):
return self.get_binary_len(self.input_shapes[0], self.input_shapes[1])
def get_binary_len(self, shape_a, shape_b):
raise NotImplementedError()
class Softmax(BinaryLayer):
def __init__(self, y, y_):
super(Softmax, self).__init__(y, y_)
def build_binary_layer(self, y, y_):
exp = op.Exp(y, axis=1)
top = op.Sum(op.Mul(y_, exp), axis=1)
reciprocal = op.Reciprocal(op.Sum(exp, axis=1))
naive = op.Mul(top, reciprocal)
return op.Mul(-1, op.Log(naive)), None
def get_binary_len(self, shape_a, shape_b):
return 1
class Dense(UnaryLayer):
def __init__(self, x=None, neurons=1):
self.neurons = neurons
super(Dense, self).__init__(x)
def build_unary_layer(self, x):
if self.input_shapes[0] is None:
raise ValueError('input has no defined shape')
w = op.Variable((self.input_shapes[0], self.neurons))
b = op.Variable((1, self.neurons))
y = op.Add(op.Dot(x, w), b, axis=0)
return y, [w, b]
def get_unary_len(self, shape):
return self.neurons