def _fit(self, X, batch_name, Y=None, shuffle_mode=True): datagen = generator_from_index(X, batch_name=batch_name, k=self.k, batch_size=self.batch_size, search_k=self.search_k, precompute=True, verbose=1) loss_monitor = 'loss' try: triplet_loss_func = triplet_loss(distance=self.distance, margin=self.margin) except KeyError: raise ValueError('Loss function `{}` not implemented.'.format( self.distance)) if self.model_ is None: if type(self.model_def) is str: input_size = (X.obsm['X_pca'].shape[-1], ) self.model_, anchor_embedding, _, _ = \ triplet_network(base_network(input_size), embedding_dims=self.embedding_dims) else: self.model_, anchor_embedding, _, _ = \ triplet_network(self.model_def, embedding_dims=self.embedding_dims) self.model_.compile(optimizer='adam', loss=triplet_loss_func) self.encoder = self.model_.layers[3] if self.verbose > 0: print('Training neural network') hist = self.model_.fit( datagen, epochs=self.epochs, callbacks=[callback for callback in self.callbacks] + [ EarlyStopping(monitor=loss_monitor, patience=self.n_epochs_without_progress) ], shuffle=shuffle_mode, workers=10, verbose=self.verbose) self.loss_history_ += hist.history['loss']
def test_triplet_network(): X = np.zeros(shape=(10, 5)) embedding_dims = 3 base_model = Sequential() base_model.add(Dense(8, input_shape=(X.shape[-1], ))) model, _, _, _ = triplet_network(base_model, embedding_dims=embedding_dims, embedding_l2=0.1) encoder = model.layers[3] assert model.layers[3].output_shape == (None, 3) assert np.all(base_model.get_weights()[0] == encoder.get_weights()[0]) assert np.all([ isinstance(layer, keras.layers.InputLayer) for layer in model.layers[:3] ]) assert encoder.output_shape == (None, embedding_dims)
def _fit(self, X, batch_name, celltype_name=None, mask_batch=None, Y=None, shuffle_mode=True): datagen = generator_from_index(X, batch_name=batch_name, mask_batch=mask_batch, celltype_name=celltype_name, Y=Y, k_to_m_ratio=self.k_to_m_ratio, label_ratio=self.label_ratio, k=self.k, batch_size=self.batch_size, search_k=self.search_k, verbose=self.verbose, save_on_disk=self.save_on_disk, approx=self.approx) loss_monitor = 'loss' try: triplet_loss_func = triplet_loss(distance=self.distance, margin=self.margin) except KeyError: raise ValueError('Loss function `{}` not implemented.'.format( self.distance)) if self.model_ is None: if type(self.model_def) is str: input_size = (X.obsm['X_pca'].shape[-1], ) self.model_, anchor_embedding, _, _ = \ triplet_network(base_network(input_size), embedding_dims=self.embedding_dims) else: self.model_, anchor_embedding, _, _ = \ triplet_network(self.model_def, embedding_dims=self.embedding_dims) if Y is None: self.model_.compile(optimizer='adam', loss=triplet_loss_func) else: Y = le.fit_transform(Y) if is_categorical(self.supervision_metric): if not is_multiclass(self.supervision_metric): if not is_hinge(self.supervision_metric): # Binary logistic classifier if len(Y.shape) > 1: self.n_classes = Y.shape[-1] else: self.n_classes = 1 supervised_output = Dense( self.n_classes, activation='sigmoid', name='supervised')(anchor_embedding) else: # Binary Linear SVM output if len(Y.shape) > 1: self.n_classes = Y.shape[-1] else: self.n_classes = 1 supervised_output = Dense( self.n_classes, activation='linear', name='supervised', kernel_regularizer=regularizers.l1( l1=0.01))(anchor_embedding) else: if not is_hinge(self.supervision_metric): validate_sparse_labels(Y) self.n_classes = len( np.unique(Y[Y != np.array(-1)])) # Softmax classifier supervised_output = Dense( self.n_classes, activation='softmax', name='supervised')(anchor_embedding) else: self.n_classes = len(np.unique(Y, axis=0)) # Multiclass Linear SVM output supervised_output = Dense( self.n_classes, activation='linear', name='supervised', kernel_regularizer=regularizers.l1( l1=0.01))(anchor_embedding) else: # Regression if len(Y.shape) > 1: self.n_classes = Y.shape[-1] else: self.n_classes = 1 supervised_output = Dense( self.n_classes, activation='linear', name='supervised')(anchor_embedding) supervised_loss = keras.losses.get(self.supervision_metric) if self.supervision_metric == 'sparse_categorical_crossentropy': supervised_loss = semi_supervised_loss(supervised_loss) final_network = Model( inputs=self.model_.inputs, outputs=[self.model_.output, supervised_output]) self.model_ = final_network self.model_.compile(optimizer='adam', loss={ 'stacked_triplets': triplet_loss_func, 'supervised': supervised_loss }, loss_weights={ 'stacked_triplets': 1 - self.supervision_weight, 'supervised': self.supervision_weight }) # Store dedicated classification model supervised_model_input = Input( shape=(X.obsm['X_pca'].shape[-1], )) embedding = self.model_.layers[3](supervised_model_input) softmax_out = self.model_.layers[-1](embedding) self.supervised_model_ = Model(supervised_model_input, softmax_out) self.encoder = self.model_.layers[3] if self.verbose > 0: print('Training neural network') hist = self.model_.fit( datagen, epochs=self.epochs, callbacks=[callback for callback in self.callbacks] + [ EarlyStopping(monitor=loss_monitor, patience=self.n_epochs_without_progress) ], shuffle=shuffle_mode, workers=10, verbose=self.verbose) self.loss_history_ += hist.history['loss']