def call(self, inputs): if len(inputs) == 3: X, A, I = inputs self.data_mode = 'graph' else: X, A = inputs I = tf.zeros(tf.shape(X)[:1], dtype=tf.int32) self.data_mode = 'single' if K.ndim(I) == 2: I = I[:, 0] A_is_sparse = K.is_sparse(A) # Get mask y = K.dot(X, K.l2_normalize(self.kernel)) N = K.shape(X)[-2] indices = ops.top_k(y[:, 0], I, self.ratio, self.top_k_var) mask = tf.scatter_nd(tf.expand_dims(indices, 1), tf.ones_like(indices), (N, )) # Multiply X and y to make layer differentiable features = X * self.gating_op(y) axis = 0 if len(K.int_shape( A)) == 2 else 1 # Cannot use negative axis in tf.boolean_mask # Reduce X X_pooled = tf.boolean_mask(features, mask, axis=axis) # Compute A^2 if A_is_sparse: A_dense = tf.sparse.to_dense(A) else: A_dense = A A_squared = K.dot(A, A_dense) # Reduce A A_pooled = tf.boolean_mask(A_squared, mask, axis=axis) A_pooled = tf.boolean_mask(A_pooled, mask, axis=axis + 1) if A_is_sparse: A_pooled = tf.contrib.layers.dense_to_sparse(A_pooled) output = [X_pooled, A_pooled] # Reduce I if self.data_mode == 'graph': I_pooled = tf.boolean_mask(I[:, None], mask)[:, 0] output.append(I_pooled) if self.return_mask: output.append(mask) return output
def bernoulliSample_ST(op, grad): return [grad, tf.zeros(tf.shape(op.inputs[1]))]
def call(self, inputs): # Note that I is useless, because thee layer cannot be used in graph # batch mode. if len(inputs) == 3: X, A, I = inputs else: X, A = inputs I = None # Check if the layer is operating in batch mode (X and A have rank 3) batch_mode = K.ndim(A) == 3 # Optionally compute hidden layer if self.h is None: Hid = X else: Hid = K.dot(X, self.kernel_in) if self.use_bias: Hid = K.bias_add(Hid, self.bias_in) if self.activation is not None: Hid = self.activation(Hid) # Compute cluster assignment matrix S = K.dot(Hid, self.kernel_out) if self.use_bias: S = K.bias_add(S, self.bias_out) S = activations.softmax( S, axis=-1) # Apply softmax to get cluster assignments # MinCut regularization A_pooled = ops.matmul_AT_B_A(S, A) num = tf.trace(A_pooled) D = ops.degree_matrix(A) den = tf.trace(ops.matmul_AT_B_A(S, D)) cut_loss = -(num / den) if batch_mode: cut_loss = K.mean(cut_loss) self.add_loss(cut_loss) # Orthogonality regularization SS = ops.matmul_AT_B(S, S) I_S = tf.eye(self.k) ortho_loss = tf.norm(SS / tf.norm(SS, axis=(-1, -2)) - I_S / tf.norm(I_S), axis=(-1, -2)) if batch_mode: ortho_loss = K.mean(cut_loss) self.add_loss(ortho_loss) # Pooling X_pooled = ops.matmul_AT_B(S, X) A_pooled = tf.linalg.set_diag(A_pooled, tf.zeros( K.shape(A_pooled)[:-1])) # Remove diagonal A_pooled = ops.normalize_A(A_pooled) output = [X_pooled, A_pooled] if I is not None: I_mean = tf.segment_mean(I, I) I_pooled = ops.tf_repeat_1d(I_mean, tf.ones_like(I_mean) * self.k) output.append(I_pooled) if self.return_mask: output.append(S) return output
def false_fn(): x_padded = tf.concat([x, tf.zeros((1, 1))], axis=0) return x_padded