comfi-fast-grnn-tensorflow 0.0.1__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.
- comfi_fast_grnn_tensorflow/ComfiFastGRNN.py +360 -0
- comfi_fast_grnn_tensorflow/__init__.py +0 -0
- comfi_fast_grnn_tensorflow-0.0.1.dist-info/METADATA +44 -0
- comfi_fast_grnn_tensorflow-0.0.1.dist-info/RECORD +6 -0
- comfi_fast_grnn_tensorflow-0.0.1.dist-info/WHEEL +5 -0
- comfi_fast_grnn_tensorflow-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import tensorflow as tf
|
|
2
|
+
from tensorflow.keras.layers import AbstractRNNCell
|
|
3
|
+
from tensorflow.keras import backend
|
|
4
|
+
from tensorflow.keras.initializers import RandomNormal, Constant, Ones
|
|
5
|
+
from tensorflow.keras.constraints import MinMaxNorm
|
|
6
|
+
from tensorflow.keras.layers import RNN
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def gen_non_linearity(A, non_linearity):
|
|
10
|
+
'''
|
|
11
|
+
Returns required activation for a tensor based on the inputs
|
|
12
|
+
non_linearity is either a callable or a value in
|
|
13
|
+
['tanh', 'sigmoid', 'relu', 'quantTanh', 'quantSigm', 'quantSigm4']
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
if non_linearity == "tanh":
|
|
17
|
+
return backend.tanh(A)
|
|
18
|
+
elif non_linearity == "sigmoid":
|
|
19
|
+
return backend.sigmoid(A)
|
|
20
|
+
elif non_linearity == "relu":
|
|
21
|
+
return backend.maximum(A, 0.0)
|
|
22
|
+
elif non_linearity == "quantTanh":
|
|
23
|
+
return backend.maximum(backend.minimum(A, 1.0), -1.0)
|
|
24
|
+
elif non_linearity == "quantSigm":
|
|
25
|
+
A = (A + 1.0) / 2.0
|
|
26
|
+
return backend.maximum(backend.minimum(A, 1.0), 0.0)
|
|
27
|
+
elif non_linearity == "quantSigm4":
|
|
28
|
+
A = (A + 2.0) / 4.0
|
|
29
|
+
return backend.maximum(backend.minimum(A, 1.0), 0.0)
|
|
30
|
+
else:
|
|
31
|
+
# non_linearity is a user specified function
|
|
32
|
+
if not callable(non_linearity):
|
|
33
|
+
raise ValueError("non_linearity is either a callable or a value: ['tanh', 'sigmoid', 'relu', 'quantTanh', 'quantSigm', 'quantSigm4']")
|
|
34
|
+
return non_linearity(A)
|
|
35
|
+
|
|
36
|
+
# -------------------------------
|
|
37
|
+
# Comfi-FastGRNN cell
|
|
38
|
+
# -------------------------------
|
|
39
|
+
class ComfiFastGRNNCell(AbstractRNNCell):
|
|
40
|
+
|
|
41
|
+
'''
|
|
42
|
+
Comfi-FastGRNN Cell
|
|
43
|
+
|
|
44
|
+
This class is upgraded from the official FastGRNN cell code to Tensorflow 2.0 syntax, and
|
|
45
|
+
it is extended with the trainable complementary filter aproach suggested in our paper.
|
|
46
|
+
|
|
47
|
+
Original FastGRNN cell code available in: https://github.com/microsoft/EdgeML/tree/master
|
|
48
|
+
|
|
49
|
+
The cell has both Full Rank and Low Rank Formulations and
|
|
50
|
+
multiple activation functions for the gates.
|
|
51
|
+
|
|
52
|
+
hidden_size = # hidden units
|
|
53
|
+
|
|
54
|
+
gate_non_linearity = nonlinearity for the gate can be chosen from
|
|
55
|
+
[tanh, sigmoid, relu, quantTanh, quantSigm]
|
|
56
|
+
|
|
57
|
+
update_non_linearity = nonlinearity for final rnn update
|
|
58
|
+
can be chosen from [tanh, sigmoid, relu, quantTanh, quantSigm]
|
|
59
|
+
|
|
60
|
+
w_rank = rank of W matrix (creates two matrices if not None)
|
|
61
|
+
u_rank = rank of U matrix (creates two matrices if not None)
|
|
62
|
+
zeta_init = init for zeta, the scale param
|
|
63
|
+
nu_init = init for nu, the translation param
|
|
64
|
+
lambda_init = init value for lambda, the CF drift modulation parameter
|
|
65
|
+
gamma_init = init value for gamma, the CF hidden state contribution parameter
|
|
66
|
+
|
|
67
|
+
Equations of the RNN state update:
|
|
68
|
+
|
|
69
|
+
z_t = gate_nl(W + Uh_{t-1} + B_g)
|
|
70
|
+
h_t^ = update_nl(W + Uh_{t-1} + B_h)
|
|
71
|
+
h_t = z_t*h_{t-1} + (sigmoid(zeta)(1-z_t) + sigmoid(nu))*h_t^
|
|
72
|
+
h_t_comfi = gamma*h_t + (1-gamma)*lambda
|
|
73
|
+
|
|
74
|
+
W and U can further parameterised into low rank version by
|
|
75
|
+
W = matmul(W_1, W_2) and U = matmul(U_1, U_2)
|
|
76
|
+
'''
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
hidden_size,
|
|
81
|
+
gate_non_linearity="sigmoid",
|
|
82
|
+
update_non_linearity="tanh",
|
|
83
|
+
w_rank=None,
|
|
84
|
+
u_rank=None,
|
|
85
|
+
zeta_init=1.0,
|
|
86
|
+
nu_init=-4.0,
|
|
87
|
+
lambda_init=0.0,
|
|
88
|
+
gamma_init=0.999,
|
|
89
|
+
name="FastGRNN",
|
|
90
|
+
**kwargs):
|
|
91
|
+
|
|
92
|
+
super(ComfiFastGRNNCell, self).__init__(**kwargs)
|
|
93
|
+
self._hidden_size = hidden_size
|
|
94
|
+
self._gate_non_linearity = gate_non_linearity
|
|
95
|
+
self._update_non_linearity = update_non_linearity
|
|
96
|
+
self._num_weight_matrices = [1, 1]
|
|
97
|
+
self._w_rank = w_rank
|
|
98
|
+
self._u_rank = u_rank
|
|
99
|
+
self._zeta_init = zeta_init
|
|
100
|
+
self._nu_init = nu_init
|
|
101
|
+
self._lambda_init = lambda_init
|
|
102
|
+
self._gamma_init = gamma_init
|
|
103
|
+
|
|
104
|
+
if w_rank is not None:
|
|
105
|
+
self._num_weight_matrices[0] += 1
|
|
106
|
+
if u_rank is not None:
|
|
107
|
+
self._num_weight_matrices[1] += 1
|
|
108
|
+
self._name = name
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def state_size(self):
|
|
112
|
+
return self._hidden_size
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def output_size(self):
|
|
116
|
+
return self._hidden_size
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def gate_non_linearity(self):
|
|
120
|
+
return self._gate_non_linearity
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def update_non_linearity(self):
|
|
124
|
+
return self._update_non_linearity
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def w_rank(self):
|
|
128
|
+
return self._w_rank
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def u_rank(self):
|
|
132
|
+
return self._u_rank
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def num_weight_matrices(self):
|
|
136
|
+
return self._num_weight_matrices
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def name(self):
|
|
140
|
+
return self._name
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def cellType(self):
|
|
144
|
+
return "Comfi-FastGRNN"
|
|
145
|
+
|
|
146
|
+
def build(self, input_shape):
|
|
147
|
+
input_dim = input_shape[-1]
|
|
148
|
+
if self._w_rank is None:
|
|
149
|
+
w_init = RandomNormal(mean=0.0, stddev=0.1)
|
|
150
|
+
self.w_matrix = self.add_weight(
|
|
151
|
+
shape=(input_dim, self._hidden_size),
|
|
152
|
+
name="w_matrix",
|
|
153
|
+
initializer=w_init
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
w_init_1 = RandomNormal(mean=0.0, stddev=0.1)
|
|
157
|
+
w_init_2 = RandomNormal(mean=0.0, stddev=0.1)
|
|
158
|
+
self.w_matrix_1 = self.add_weight(
|
|
159
|
+
shape=(input_dim, self._w_rank),
|
|
160
|
+
name="w_matrix_1",
|
|
161
|
+
initializer=w_init_1
|
|
162
|
+
)
|
|
163
|
+
self.w_matrix_2 = self.add_weight(
|
|
164
|
+
shape=(self._w_rank, self._hidden_size),
|
|
165
|
+
name="w_matrix_2",
|
|
166
|
+
initializer=w_init_2
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if self._u_rank is None:
|
|
170
|
+
u_init = RandomNormal(mean=0.0, stddev=0.1)
|
|
171
|
+
self.u_matrix = self.add_weight(
|
|
172
|
+
shape=(self._hidden_size, self._hidden_size),
|
|
173
|
+
name="u_matrix",
|
|
174
|
+
initializer=u_init
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
u_init_1 = RandomNormal(mean=0.0, stddev=0.1)
|
|
178
|
+
u_init_2 = RandomNormal(mean=0.0, stddev=0.1)
|
|
179
|
+
self.u_matrix_1 = self.add_weight(
|
|
180
|
+
shape=(self._hidden_size, self._u_rank),
|
|
181
|
+
name="u_matrix_1",
|
|
182
|
+
initializer=u_init_1
|
|
183
|
+
)
|
|
184
|
+
self.u_matrix_2 = self.add_weight(
|
|
185
|
+
shape=(self._u_rank, self._hidden_size),
|
|
186
|
+
name="u_matrix_2",
|
|
187
|
+
initializer=u_init_2
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
zeta_init = Constant(self._zeta_init)
|
|
191
|
+
nu_init = Constant(self._nu_init)
|
|
192
|
+
lambda_init = Constant(self._lambda_init)
|
|
193
|
+
gamma_init = Constant(self._gamma_init)
|
|
194
|
+
bias_gate_initializer = Ones()
|
|
195
|
+
bias_update_initializer = Ones()
|
|
196
|
+
|
|
197
|
+
self.zeta = self.add_weight(
|
|
198
|
+
shape=(1,1),
|
|
199
|
+
name="zeta",
|
|
200
|
+
initializer=zeta_init
|
|
201
|
+
)
|
|
202
|
+
self.nu = self.add_weight(
|
|
203
|
+
shape=(1,1),
|
|
204
|
+
name="nu",
|
|
205
|
+
initializer=nu_init
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
self.bias_gate = self.add_weight(
|
|
209
|
+
shape=(1, self._hidden_size),
|
|
210
|
+
name="bias_gate",
|
|
211
|
+
initializer=bias_gate_initializer
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
self.bias_update_gate = self.add_weight(
|
|
215
|
+
shape=(1, self._hidden_size),
|
|
216
|
+
name="bias_update",
|
|
217
|
+
initializer=bias_update_initializer
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
self.lambd = self.add_weight(
|
|
221
|
+
shape=(1,),
|
|
222
|
+
name="lambd",
|
|
223
|
+
initializer=lambda_init,
|
|
224
|
+
trainable=True,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
self.gamma= self.add_weight(
|
|
228
|
+
shape=(1,),
|
|
229
|
+
name="gamma",
|
|
230
|
+
trainable=True,
|
|
231
|
+
initializer=gamma_init,
|
|
232
|
+
constraint=MinMaxNorm(min_value=0.0, max_value=1.0) # Note: We can either limit its value range here or use a sigmoid function later on.
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
self.built = True
|
|
236
|
+
|
|
237
|
+
def call(self, inputs, states):
|
|
238
|
+
h_tm1 = states[0]
|
|
239
|
+
if self._w_rank is None:
|
|
240
|
+
W = backend.dot(inputs, self.w_matrix)
|
|
241
|
+
else:
|
|
242
|
+
w_tmp = backend.dot(inputs, self.w_matrix_1)
|
|
243
|
+
W = backend.dot(w_tmp, self.w_matrix_2)
|
|
244
|
+
|
|
245
|
+
if self._u_rank is None:
|
|
246
|
+
U = backend.dot(h_tm1, self.u_matrix)
|
|
247
|
+
else:
|
|
248
|
+
u_tmp = backend.dot(h_tm1, self.u_matrix_1)
|
|
249
|
+
U = backend.dot(u_tmp, self.u_matrix_2)
|
|
250
|
+
|
|
251
|
+
z = gen_non_linearity( (W + U + self.bias_gate), self._gate_non_linearity )
|
|
252
|
+
|
|
253
|
+
h_hat = gen_non_linearity( (W + U + self.bias_update_gate), self._update_non_linearity )
|
|
254
|
+
|
|
255
|
+
h = ((z * h_tm1) + (backend.sigmoid(self.zeta) * (1.0 - z) + backend.sigmoid(self.nu)) * h_hat)
|
|
256
|
+
|
|
257
|
+
# Comfi-FastGRNN state update
|
|
258
|
+
h_t_comfi = h*self.gamma + (1-self.gamma)*self.lambd
|
|
259
|
+
|
|
260
|
+
return h_t_comfi, h_t_comfi
|
|
261
|
+
|
|
262
|
+
def get_config(self):
|
|
263
|
+
config = {
|
|
264
|
+
"hidden_size": self._hidden_size,
|
|
265
|
+
"gate_non_linearity": self._gate_non_linearity,
|
|
266
|
+
"update_non_linearity":self._update_non_linearity,
|
|
267
|
+
"w_rank": self._w_rank,
|
|
268
|
+
"u_rank":self._u_rank,
|
|
269
|
+
"zeta_init":self._zeta_init,
|
|
270
|
+
"nu_init":self._nu_init,
|
|
271
|
+
"lambda_init":self._lambda_init,
|
|
272
|
+
"gamma_init":self._gamma_init,
|
|
273
|
+
"name":self._name
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
base_config = super(ComfiFastGRNNCell, self).get_config()
|
|
277
|
+
return dict(list(base_config.items()) + list(config.items()))
|
|
278
|
+
|
|
279
|
+
@classmethod
|
|
280
|
+
def from_config(cls, config):
|
|
281
|
+
return cls(**config)
|
|
282
|
+
|
|
283
|
+
# -------------------------------
|
|
284
|
+
# Comfi-FastGRNN layer
|
|
285
|
+
# -------------------------------
|
|
286
|
+
class ComfiFastGRNN(tf.keras.layers.RNN):
|
|
287
|
+
|
|
288
|
+
def __init__(
|
|
289
|
+
self,
|
|
290
|
+
units,
|
|
291
|
+
gate_non_linearity="sigmoid",
|
|
292
|
+
update_non_linearity="tanh",
|
|
293
|
+
w_rank=None,
|
|
294
|
+
u_rank=None,
|
|
295
|
+
zeta_init=1.0,
|
|
296
|
+
nu_init=-4.0,
|
|
297
|
+
lambda_init=0.0,
|
|
298
|
+
gamma_init=0.999,
|
|
299
|
+
return_sequences=False,
|
|
300
|
+
return_state=False,
|
|
301
|
+
go_backwards=False,
|
|
302
|
+
stateful=False,
|
|
303
|
+
unroll=False,
|
|
304
|
+
**kwargs,
|
|
305
|
+
):
|
|
306
|
+
|
|
307
|
+
self.hidden_size = units
|
|
308
|
+
self.gate_non_linearity = gate_non_linearity
|
|
309
|
+
self.update_non_linearity = update_non_linearity
|
|
310
|
+
self.w_rank = w_rank
|
|
311
|
+
self.u_rank = u_rank
|
|
312
|
+
self.zeta_init = zeta_init
|
|
313
|
+
self.nu_init = nu_init
|
|
314
|
+
self.lambda_init = lambda_init
|
|
315
|
+
self.gamma_init = gamma_init
|
|
316
|
+
|
|
317
|
+
cell = ComfiFastGRNNCell(
|
|
318
|
+
hidden_size=units,
|
|
319
|
+
gate_non_linearity=gate_non_linearity,
|
|
320
|
+
update_non_linearity=update_non_linearity,
|
|
321
|
+
w_rank=w_rank,
|
|
322
|
+
u_rank=u_rank,
|
|
323
|
+
zeta_init=zeta_init,
|
|
324
|
+
nu_init=nu_init,
|
|
325
|
+
lambda_init=lambda_init,
|
|
326
|
+
gamma_init=gamma_init,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
super().__init__(
|
|
330
|
+
cell=cell,
|
|
331
|
+
return_sequences=return_sequences,
|
|
332
|
+
return_state=return_state,
|
|
333
|
+
go_backwards=go_backwards,
|
|
334
|
+
stateful=stateful,
|
|
335
|
+
unroll=unroll,
|
|
336
|
+
**kwargs,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def get_config(self):
|
|
340
|
+
config = super().get_config()
|
|
341
|
+
|
|
342
|
+
# Remove serialized cell
|
|
343
|
+
config.pop("cell", None)
|
|
344
|
+
|
|
345
|
+
config.update({
|
|
346
|
+
"units": self.hidden_size,
|
|
347
|
+
"gate_non_linearity": self.gate_non_linearity,
|
|
348
|
+
"update_non_linearity": self.update_non_linearity,
|
|
349
|
+
"w_rank": self.w_rank,
|
|
350
|
+
"u_rank": self.u_rank,
|
|
351
|
+
"zeta_init": self.zeta_init,
|
|
352
|
+
"nu_init": self.nu_init,
|
|
353
|
+
"lambda_init": self.lambda_init,
|
|
354
|
+
"gamma_init": self.gamma_init,
|
|
355
|
+
})
|
|
356
|
+
return config
|
|
357
|
+
|
|
358
|
+
@classmethod
|
|
359
|
+
def from_config(cls, config):
|
|
360
|
+
return cls(**config)
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: comfi_fast_grnn_tensorflow
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A PyTorch implementation of Fast ULCNet
|
|
5
|
+
Author-email: Nicolas Arrieta Larraza <NIAL@bang-olufsen.dk>, Niels de Koeijer <NEMK@bang-olufsen.dk>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/narrietal/Fast-ULCNet
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: tensorflow>=2.14.0
|
|
11
|
+
Requires-Dist: tensorflow-estimator>=2.14.0
|
|
12
|
+
Requires-Dist: libsegmenter==1.0.4
|
|
13
|
+
Requires-Dist: CRM_tensorflow==0.1.6
|
|
14
|
+
|
|
15
|
+
# fast-ulcnet-tensorflow
|
|
16
|
+
Implements Comfi-FastGRNN in tensorflow.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
You can use the `ComfiFastGRNN` layer just like any standard Keras RNN layer (e.g., `LSTM`, `GRU`). It supports the Sequential and Functional APIs.
|
|
21
|
+
|
|
22
|
+
### Basic Implementation
|
|
23
|
+
The simplest way to use the layer with default settings:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import tensorflow as tf
|
|
27
|
+
from comfi_fast_grnn_tensorflow import ComfiFastGRNN
|
|
28
|
+
|
|
29
|
+
# Define a Sequential model
|
|
30
|
+
model = tf.keras.Sequential([
|
|
31
|
+
# Input shape: (Timesteps, Features)
|
|
32
|
+
tf.keras.layers.Input(shape=(100, 32)),
|
|
33
|
+
|
|
34
|
+
# Comfi-FastGRNN layer
|
|
35
|
+
ComfiFastGRNN(
|
|
36
|
+
units=64,
|
|
37
|
+
return_sequences=False
|
|
38
|
+
),
|
|
39
|
+
|
|
40
|
+
tf.keras.layers.Dense(10, activation='softmax')
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
model.summary()
|
|
44
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
comfi_fast_grnn_tensorflow/ComfiFastGRNN.py,sha256=neLMlEBBLgPmwwLqtPhmzhfO6QQNa4RNTq3xwKjurSE,11278
|
|
2
|
+
comfi_fast_grnn_tensorflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
comfi_fast_grnn_tensorflow-0.0.1.dist-info/METADATA,sha256=0SSKxGnXNjnUk3EGCfaHsacQeWCiKHJ3qg903P_vPXU,1245
|
|
4
|
+
comfi_fast_grnn_tensorflow-0.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
5
|
+
comfi_fast_grnn_tensorflow-0.0.1.dist-info/top_level.txt,sha256=ihF3p9lpg_PVArJ30NTV3nmFpvA4NM4PZAiw8TzHikk,27
|
|
6
|
+
comfi_fast_grnn_tensorflow-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
comfi_fast_grnn_tensorflow
|