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.
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ comfi_fast_grnn_tensorflow