from __future__ import absolute_import from .. import backend as K from .. import initializations from .. import regularizers from .. import constraints from ..engine import Layer class Embedding(Layer): """Turn positive integers (indexes) into dense vectors of fixed size. eg. [[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]] This layer can only be used as the first layer in a model. # Example ```python model = Sequential() model.add(Embedding(1000, 64, input_length=10)) # the model will take as input an integer matrix of size (batch, input_length). # the largest integer (i.e. word index) in the input should be no larger than 999 (vocabulary size). # now model.output_shape == (None, 10, 64), where None is the batch dimension. input_array = np.random.randint(1000, size=(32, 10)) model.compile('rmsprop', 'mse') output_array = model.predict(input_array) assert output_array.shape == (32, 10, 64) ``` # Arguments input_dim: int > 0. Size of the vocabulary, ie. 1 + maximum integer index occurring in the input data. output_dim: int >= 0. Dimension of the dense embedding. init: name of initialization function for the weights of the layer (see: [initializations](../initializations.md)), or alternatively, Theano function to use for weights initialization. This parameter is only relevant if you don't pass a `weights` argument. weights: list of Numpy arrays to set as initial weights. The list should have 1 element, of shape `(input_dim, output_dim)`. W_regularizer: instance of the [regularizers](../regularizers.md) module (eg. L1 or L2 regularization), applied to the embedding matrix. W_constraint: instance of the [constraints](../constraints.md) module (eg. maxnorm, nonneg), applied to the embedding matrix. mask_zero: Whether or not the input value 0 is a special "padding" value that should be masked out. This is useful for [recurrent layers](recurrent.md) which may take variable length input. If this is `True` then all subsequent layers in the model need to support masking or an exception will be raised. If mask_zero is set to True, as a consequence, index 0 cannot be used in the vocabulary (input_dim should equal |vocabulary| + 2). input_length: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed). dropout: float between 0 and 1. Fraction of the embeddings to drop. # Input shape 2D tensor with shape: `(nb_samples, sequence_length)`. # Output shape 3D tensor with shape: `(nb_samples, sequence_length, output_dim)`. # References - [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287) """ def __init__(self, input_dim, output_dim, init='uniform', input_length=None, W_regularizer=None, activity_regularizer=None, W_constraint=None, mask_zero=False, weights=None, dropout=0., **kwargs): self.input_dim = input_dim self.output_dim = output_dim self.init = initializations.get(init) self.input_length = input_length self.mask_zero = mask_zero self.dropout = dropout self.W_constraint = constraints.get(W_constraint) self.W_regularizer = regularizers.get(W_regularizer) self.activity_regularizer = regularizers.get(activity_regularizer) if 0. < self.dropout < 1.: self.uses_learning_phase = True self.initial_weights = weights kwargs['input_shape'] = (self.input_length,) kwargs['input_dtype'] = 'int32' super(Embedding, self).__init__(**kwargs) def build(self, input_shape): self.W = self.add_weight((self.input_dim, self.output_dim), initializer=self.init, name='{}_W'.format(self.name), regularizer=self.W_regularizer, constraint=self.W_constraint) if self.initial_weights is not None: self.set_weights(self.initial_weights) self.built = True def compute_mask(self, x, mask=None): if not self.mask_zero: return None else: return K.not_equal(x, 0) def get_output_shape_for(self, input_shape): if not self.input_length: input_length = input_shape[1] else: input_length = self.input_length return (input_shape[0], input_length, self.output_dim) def call(self, x, mask=None): if K.dtype(x) != 'int32': x = K.cast(x, 'int32') if 0. < self.dropout < 1.: retain_p = 1. - self.dropout B = K.random_binomial((self.input_dim,), p=retain_p) * (1. / retain_p) B = K.expand_dims(B) W = K.in_train_phase(self.W * B, self.W) else: W = self.W out = K.gather(W, x) return out def get_config(self): config = {'input_dim': self.input_dim, 'output_dim': self.output_dim, 'init': self.init.__name__, 'input_length': self.input_length, 'mask_zero': self.mask_zero, 'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None, 'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None, 'W_constraint': self.W_constraint.get_config() if self.W_constraint else None, 'dropout': self.dropout} base_config = super(Embedding, self).get_config() return dict(list(base_config.items()) + list(config.items()))