22
33import numpy as np
44import tensorflow as tf
5+ from tensorflow .python .ops import math_ops
56
67
78class PositionalEncoding (tf .keras .layers .Layer ):
@@ -67,6 +68,7 @@ def __init__(self,
6768 name : str = 'positional_encoding' ,
6869 ** kwargs ):
6970 """
71+
7072 :param max_sequence_length: Maximum sequence length of input
7173 :param embedding_dim: Dimensionality of the of the input's last dimension
7274 :param normalize_factor: Normalize factor
@@ -104,12 +106,13 @@ def compute_mask(self, inputs, mask=None):
104106 def call (self , inputs ,
105107 mask : Optional [tf .Tensor ] = None ,
106108 ** kwargs ) -> tf .Tensor :
107- output = inputs + self .positional_encoding
109+ output = inputs + self .positional_encoding # shape=(batch_size, time_steps, channels)
110+
108111 if mask is not None :
109112 output = tf .where (tf .tile (tf .expand_dims (mask , axis = - 1 ), multiples = [1 , 1 , inputs .shape [- 1 ]]), output ,
110- inputs )
113+ inputs ) # shape=(batch_size, time_steps, channels)
111114
112- return output # shape=(batch_size, time_steps, channels)
115+ return output
113116
114117 def get_config (self ):
115118 base_config = super ().get_config ()
@@ -132,8 +135,10 @@ class DynamicMetaEmbedding(tf.keras.layers.Layer):
132135 Arguments
133136 ---------
134137
135- - `embedding_matrices` (``List[tf.keras.layers.Embedding ]``): List of embedding layers
138+ - `embedding_matrices` (``List[np.ndarray ]``): List of embedding matrices
136139 - `output_dim` (``int``): Dimension of the output embedding
140+ - `mask_zero` (``bool``): Whether or not the input value 0 is a special "padding" value that should be masked out
141+ - `input_length` (``Optional[int]``): Parameter to be passed into internal ``tf.keras.layers.Embedding`` matrices
137142 - `name` (``str``): Layer name
138143
139144
@@ -160,27 +165,22 @@ class DynamicMetaEmbedding(tf.keras.layers.Layer):
160165 import tensorflow as tf
161166 import tavolo as tvl
162167
163- w2v_embedding = tf.keras.layers.Embedding(num_words,
164- EMBEDDING_DIM,
165- embeddings_initializer=tf.keras.initializers.Constant(w2v_matrix),
166- input_length=MAX_SEQUENCE_LENGTH,
167- trainable=False)
168+ w2v_embedding = np.array(...) # Pre-trained embedding matrix
168169
169- glove_embedding = tf.keras.layers.Embedding(num_words,
170- EMBEDDING_DIM,
171- embeddings_initializer=tf.keras.initializers.Constant(glove_matrix),
172- input_length=MAX_SEQUENCE_LENGTH,
173- trainable=False)
170+ glove_embedding = np.array(...) # Pre-trained embedding matrix
174171
175172 model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
176- tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding])]) # Use DME embeddings
173+ tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding],
174+ input_length=MAX_SEQUENCE_LENGTH)]) # Use DME embeddings
177175
178176 Using the same example as above, it is possible to define the output's channel size
179177
180178 .. code-block:: python3
181179
182180 model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
183- tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding], output_dim=200)])
181+ tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding],
182+ input_length=MAX_SEQUENCE_LENGTH,
183+ output_dim=200)])
184184
185185
186186 References
@@ -193,25 +193,41 @@ class DynamicMetaEmbedding(tf.keras.layers.Layer):
193193 """
194194
195195 def __init__ (self ,
196- embedding_matrices : List [tf . keras . layers . Embedding ],
196+ embedding_matrices : List [np . ndarray ],
197197 output_dim : Optional [int ] = None ,
198+ mask_zero : bool = False ,
199+ input_length : Optional [int ] = None ,
198200 name : str = 'dynamic_meta_embedding' ,
199201 ** kwargs ):
200202 """
201- :param embedding_matrices: List of embedding layers
203+
204+ :param embedding_matrices: List of embedding matrices
202205 :param output_dim: Dimension of the output embedding
206+ :param mask_zero: Whether or not the input value 0 is a special "padding" value that should be masked out
207+ :param input_length: Parameter to be passed into internal ``tf.keras.layers.Embedding`` matrices
203208 :param name: Layer name
204209 """
205210 super ().__init__ (name = name , ** kwargs )
206211
212+ self .mask_zero = mask_zero
213+ self .input_length = input_length
214+ self .base_matrices_shapes = [e .shape for e in embedding_matrices ]
215+
207216 # Validate all the embedding matrices have the same vocabulary size
208- if not len (set ((e .input_dim for e in embedding_matrices ))) == 1 :
217+ if not len (set ((e .shape [ 0 ] for e in embedding_matrices ))) == 1 :
209218 raise ValueError ('Vocabulary sizes (first dimension) of all embedding matrices must match' )
219+ if not set ((e .ndim for e in embedding_matrices )) == {2 }:
220+ raise ValueError ('All embedding matrices should have only 2 dimensions' )
210221
211222 # If no output_dim is supplied, use the maximum dimension from the given matrices
212- self .output_dim = output_dim or min ([e .output_dim for e in embedding_matrices ])
213-
214- self .embedding_matrices = embedding_matrices
223+ self .output_dim = output_dim or min ([e .shape [1 ] for e in embedding_matrices ])
224+
225+ self .embedding_matrices = [tf .keras .layers .Embedding (input_dim = e .shape [0 ],
226+ output_dim = e .shape [1 ],
227+ embeddings_initializer = tf .keras .initializers .Constant (e ),
228+ input_length = input_length ,
229+ name = 'embedding_matrix_{}' .format (i ))
230+ for i , e in enumerate (embedding_matrices )]
215231 self .n_embeddings = len (self .embedding_matrices )
216232
217233 self .projections = [tf .keras .layers .Dense (units = self .output_dim ,
@@ -225,11 +241,14 @@ def __init__(self,
225241 dtype = self .dtype )
226242
227243 def compute_mask (self , inputs , mask = None ):
228- return self .projections [0 ].compute_mask (
229- inputs , mask = self .embedding_matrices [0 ].compute_mask (inputs , mask = mask ))
244+ if not self .mask_zero :
245+ return None
246+
247+ return math_ops .not_equal (inputs , 0 )
230248
231249 def call (self , inputs ,
232250 ** kwargs ) -> tf .Tensor :
251+
233252 batch_size , time_steps = inputs .shape [:2 ]
234253
235254 # Embedding lookup
@@ -254,16 +273,17 @@ def call(self, inputs,
254273
255274 def get_config (self ):
256275 base_config = super ().get_config ()
257- base_config ['embedding_matrices ' ] = [ e . get_config () for e in self .embedding_matrices ]
276+ base_config ['base_matrices_shapes ' ] = self .base_matrices_shapes
258277 base_config ['output_dim' ] = self .output_dim
278+ base_config ['mask_zero' ] = self .mask_zero
279+ base_config ['input_length' ] = self .input_length
259280
260281 return base_config
261282
262283 @classmethod
263284 def from_config (cls , config : dict ):
264- embedding_matrices = [tf .keras .layers .Embedding .from_config (e_conf ) for e_conf in
265- config .pop ('embedding_matrices' )]
266- return cls (embedding_matrices = embedding_matrices , ** config )
285+ initial_matrices = [np .zeros (shape = s ) for s in config .pop ('base_matrices_shapes' )]
286+ return cls (embedding_matrices = initial_matrices , ** config )
267287
268288
269289class ContextualDynamicMetaEmbedding (tf .keras .layers .Layer ):
@@ -277,8 +297,10 @@ class ContextualDynamicMetaEmbedding(tf.keras.layers.Layer):
277297 Arguments
278298 ---------
279299
280- - `embedding_matrices` (``List[tf.keras.layers.Embedding ]``): List of embedding layers
300+ - `embedding_matrices` (``List[np.ndarray ]``): List of embedding matrices
281301 - `output_dim` (``int``): Dimension of the output embedding
302+ - `mask_zero` (``bool``): Whether or not the input value 0 is a special "padding" value that should be masked out
303+ - `input_length` (``Optional[int]``): Parameter to be passed into internal ``tf.keras.layers.Embedding`` matrices
282304 - `n_lstm_units` (``int``): Number of units in each LSTM, (notated as `m` in the original article)
283305 - `name` (``str``): Layer name
284306
@@ -306,27 +328,22 @@ class ContextualDynamicMetaEmbedding(tf.keras.layers.Layer):
306328 import tensorflow as tf
307329 import tavolo as tvl
308330
309- w2v_embedding = tf.keras.layers.Embedding(num_words,
310- EMBEDDING_DIM,
311- embeddings_initializer=tf.keras.initializers.Constant(w2v_matrix),
312- input_length=MAX_SEQUENCE_LENGTH,
313- trainable=False)
331+ w2v_embedding = np.array(...) # Pre-trained embedding matrix
314332
315- glove_embedding = tf.keras.layers.Embedding(num_words,
316- EMBEDDING_DIM,
317- embeddings_initializer=tf.keras.initializers.Constant(glove_matrix),
318- input_length=MAX_SEQUENCE_LENGTH,
319- trainable=False)
333+ glove_embedding = np.array(...) # Pre-trained embedding matrix
320334
321335 model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
322- tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding])]) # Use CDME embeddings
336+ tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding],
337+ input_length=MAX_SEQUENCE_LENGTH)]) # Use CDME embeddings
323338
324339 Using the same example as above, it is possible to define the output's channel size and number of units in each LSTM
325340
326341 .. code-block:: python3
327342
328343 model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
329- tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding], n_lstm_units=128, output_dim=200)])
344+ tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding],
345+ input_length=MAX_SEQUENCE_LENGTH,
346+ n_lstm_units=128, output_dim=200)])
330347
331348 References
332349 ----------
@@ -335,33 +352,47 @@ class ContextualDynamicMetaEmbedding(tf.keras.layers.Layer):
335352
336353 .. _`Dynamic Meta-Embeddings for Improved Sentence Representations`:
337354 https://arxiv.org/abs/1804.07983
338- add """
355+ """
339356
340357 def __init__ (self ,
341- embedding_matrices : List [tf . keras . layers . Embedding ],
358+ embedding_matrices : List [np . ndarray ],
342359 output_dim : Optional [int ] = None ,
360+ mask_zero : bool = False ,
361+ input_length : Optional [int ] = None ,
343362 n_lstm_units : int = 2 ,
344363 name : str = 'contextual_dynamic_meta_embedding' ,
345364 ** kwargs ):
346365 """
347- :param embedding_matrices: List of embedding layers
348- :param n_lstm_units: Number of units in each LSTM, (notated as `m` in the original article)
366+ :param embedding_matrices: List of embedding matrices
349367 :param output_dim: Dimension of the output embedding
368+ :param mask_zero: Whether or not the input value 0 is a special "padding" value that should be masked out
369+ :param input_length: Parameter to be passed into internal ``tf.keras.layers.Embedding`` matrices
370+ :param n_lstm_units: Number of units in each LSTM, (notated as `m` in the original article)
350371 :param name: Layer name
351372 """
352373
353374 super ().__init__ (name = name , ** kwargs )
354375
376+ self .mask_zero = mask_zero
377+ self .input_length = input_length
378+ self .n_lstm_units = n_lstm_units
379+ self .base_matrices_shapes = [e .shape for e in embedding_matrices ]
380+
355381 # Validate all the embedding matrices have the same vocabulary size
356- if not len (set ((e .input_dim for e in embedding_matrices ))) == 1 :
382+ if not len (set ((e .shape [ 0 ] for e in embedding_matrices ))) == 1 :
357383 raise ValueError ('Vocabulary sizes (first dimension) of all embedding matrices must match' )
384+ if not set ((e .ndim for e in embedding_matrices )) == {2 }:
385+ raise ValueError ('All embedding matrices should have only 2 dimensions' )
358386
359387 # If no output_dim is supplied, use the maximum dimension from the given matrices
360- self .output_dim = output_dim or min ([e .output_dim for e in embedding_matrices ])
361-
362- self .n_lstm_units = n_lstm_units
363-
364- self .embedding_matrices = embedding_matrices
388+ self .output_dim = output_dim or min ([e .shape [1 ] for e in embedding_matrices ])
389+
390+ self .embedding_matrices = [tf .keras .layers .Embedding (input_dim = e .shape [0 ],
391+ output_dim = e .shape [1 ],
392+ embeddings_initializer = tf .keras .initializers .Constant (e ),
393+ input_length = input_length ,
394+ name = 'embedding_matrix_{}' .format (i ))
395+ for i , e in enumerate (embedding_matrices )]
365396 self .n_embeddings = len (self .embedding_matrices )
366397
367398 self .projections = [tf .keras .layers .Dense (units = self .output_dim ,
@@ -380,8 +411,10 @@ def __init__(self,
380411 dtype = self .dtype )
381412
382413 def compute_mask (self , inputs , mask = None ):
383- return self .projections [0 ].compute_mask (
384- inputs , mask = self .embedding_matrices [0 ].compute_mask (inputs , mask = mask ))
414+ if not self .mask_zero :
415+ return None
416+
417+ return math_ops .not_equal (inputs , 0 )
385418
386419 def call (self , inputs ,
387420 ** kwargs ) -> tf .Tensor :
@@ -416,14 +449,15 @@ def call(self, inputs,
416449
417450 def get_config (self ):
418451 base_config = super ().get_config ()
419- base_config ['embedding_matrices ' ] = [ e . get_config () for e in self .embedding_matrices ]
452+ base_config ['base_matrices_shapes ' ] = self .base_matrices_shapes
420453 base_config ['output_dim' ] = self .output_dim
454+ base_config ['mask_zero' ] = self .mask_zero
455+ base_config ['input_length' ] = self .input_length
421456 base_config ['n_lstm_units' ] = self .n_lstm_units
422457
423458 return base_config
424459
425460 @classmethod
426461 def from_config (cls , config : dict ):
427- embedding_matrices = [tf .keras .layers .Embedding .from_config (e_conf ) for e_conf in
428- config .pop ('embedding_matrices' )]
429- return cls (embedding_matrices = embedding_matrices , ** config )
462+ initial_matrices = [np .zeros (shape = s ) for s in config .pop ('base_matrices_shapes' )]
463+ return cls (embedding_matrices = initial_matrices , ** config )
0 commit comments