batch process of graph_cnn in tensorflow - tensorflow
I want to use the graph_cnn (Defferrard et al. 2016) for inputs with variation of number of nodes. The author provided the example code (see graph_cnn). Below is the what I think the critical part of the code
def chebyshev5(self, x, L, Fout, K):
N, M, Fin = x.get_shape()
N, M, Fin = int(N), int(M), int(Fin)
# Rescale Laplacian and store as a TF sparse tensor. Copy to not modify the shared L.
L = scipy.sparse.csr_matrix(L)
L = graph.rescale_L(L, lmax=2)
L = L.tocoo()
indices = np.column_stack((L.row, L.col))
L = tf.SparseTensor(indices, L.data, L.shape)
L = tf.sparse_reorder(L)
# Transform to Chebyshev basis
x0 = tf.transpose(x, perm=[1, 2, 0]) # M x Fin x N
x0 = tf.reshape(x0, [M, Fin*N]) # M x Fin*N
x = tf.expand_dims(x0, 0) # 1 x M x Fin*N
def concat(x, x_):
x_ = tf.expand_dims(x_, 0) # 1 x M x Fin*N
return tf.concat([x, x_], axis=0) # K x M x Fin*N
if K > 1:
x1 = tf.sparse_tensor_dense_matmul(L, x0)
x = concat(x, x1)
for k in range(2, K):
x2 = 2 * tf.sparse_tensor_dense_matmul(L, x1) - x0 # M x Fin*N
x = concat(x, x2)
x0, x1 = x1, x2
x = tf.reshape(x, [K, M, Fin, N]) # K x M x Fin x N
x = tf.transpose(x, perm=[3,1,2,0]) # N x M x Fin x K
x = tf.reshape(x, [N*M, Fin*K]) # N*M x Fin*K
# Filter: Fin*Fout filters of order K, i.e. one filterbank per feature pair.
W = self._weight_variable([Fin*K, Fout], regularization=False)
x = tf.matmul(x, W) # N*M x Fout
return tf.reshape(x, [N, M, Fout]) # N x M x Fout
Essentially, I think what this does can be simplified as something like
return = concat{(L*x)^k for (k=0 to K-1)} * W
x is the input of N x M x Fin (size variable in any batch):
L is an array of operators on x each with the size of M x M matching the corresponding sample (size variable in any batch).
W is the neural network parameters to be optimized, its size is Fin x K x Fout
N: number of samples in a batch (size fixed for any batch);
M: the number of nodes in the graph (size variable in any batch);
Fin: the number of input features (size fixed for any batch)].
Fout is the number of output features (size fixed for any batch).
K is a constant representing the number of steps (hops) in the graph
For single example, the above code works. But since both x and L have variable length for each sample in a batch, I don't know how to make it work for a batch of samples.
The tf.matmul currently (v1.4) only supports batch matrix multiplication on the lowest 2 dims for dense tensors. If either of the input tensor is sparse, it will prompt dimension mismatch error. tf.sparse_tensor_dense_matmul cannot be applied to batch inputs either.
Therefore, my current solution is to move all L preparation steps before calling the function, pass the L as a dense tensor (shape: [N, M, M]), and use the tf.matmul to perform the batch matrix multiplication.
Here is my revised code:
'''
chebyshev5_batch
Purpose:
perform the graph filtering on the given layer
Args:
x: the batch of inputs for the given layer,
dense tensor, size: [N, M, Fin],
L: the batch of sorted Laplacian of the given layer (tf.Tensor)
if in dense format, size of [N, M, M]
Fout: the number of output features on the given layer
K: the filter size or number of hopes on the given layer.
lyr_num: the idx of the original Laplacian lyr (start form 0)
Output:
y: the filtered output from the given layer
'''
def chebyshev5_batch(x, L, Fout, K, lyr_num):
N, M, Fin = x.get_shape()
#N, M, Fin = int(N), int(M), int(Fin)
# # Rescale Laplacian and store as a TF sparse tensor. Copy to not modify the shared L.
# L = scipy.sparse.csr_matrix(L)
# L = graph.rescale_L(L, lmax=2)
# L = L.tocoo()
# indices = np.column_stack((L.row, L.col))
# L = tf.SparseTensor(indices, L.data, L.shape)
# L = tf.sparse_reorder(L)
# # Transform to Chebyshev basis
# x0 = tf.transpose(x, perm=[1, 2, 0]) # M x Fin x N
# x0 = tf.reshape(x0, [M, Fin*N]) # M x Fin*N
def expand_concat(orig, new):
new = tf.expand_dims(new, 0) # 1 x N x M x Fin
return tf.concat([orig, new], axis=0) # (shape(x)[0] + 1) x N x M x Fin
# L: # N x M x M
# x0: # N x M x Fin
# L*x0: # N x M x Fin
x0 = x # N x M x Fin
stk_x = tf.expand_dims(x0, axis=0) # 1 x N x M x Fin (eventually K x N x M x Fin, if K>1)
if K > 1:
x1 = tf.matmul(L, x0) # N x M x Fin
stk_x = expand_concat(stk_x, x1)
for kk in range(2, K):
x2 = tf.matmul(L, x1) - x0 # N x M x Fin
stk_x = expand_concat(stk_x, x2)
x0 = x1
x1 = x2
# now stk_x has the shape of K x N x M x Fin
# transpose to the shape of N x M x Fin x K
## source positions 1 2 3 0
stk_x_transp = tf.transpose(stk_x, perm=[1,2,3,0])
stk_x_forMul = tf.reshape(stk_x_transp, [N*M, Fin*K])
#W = self._weight_variable([Fin*K, Fout], regularization=False)
W_initial = tf.truncated_normal_initializer(0, 0.1)
W = tf.get_variable('weights_L_'+str(lyr_num), [Fin*K, Fout], tf.float32, initializer=W_initial)
tf.summary.histogram(W.op.name, W)
y = tf.matmul(stk_x_forMul, W)
y = tf.reshape(y, [N, M, Fout])
return y
Related
Why the numpy pinv did not give the correct result
I have a pseudoinverse problem as follows: Y = W.T # X Where Y.shape = (2, 800) W.shape = (9, 2) X.shape = (9, 800) I have Y and X and I am looking for W. I used numpy.linalg.pinv. W = Y # numpy.linalg.pinv(X) But the results did not match: I found this W.T # X != Y What did I miss here? Here is my code: X = np.random.random(size=(9, 800)) Y = np.random.randint(low=0, high=2, size=(2, 800)) Xinv = np.linalg.pinv(X) W = Y # Xinv W # X # != Y ???
Mask values inside given path (triangle, square etc) for a contourf plot
I am trying to mask specific locations (triangles, squares) for a contourf plot. I can do the mask based on the Z values but finding it difficult to get it work based on x and y values. For the MWE below, I want to create a mask between given X,Y values (triangle or square). Lets say for the example below, I want to mask values inside triangle formed between points (0,0),(2,0),(0,2). I want to basically be able to provide an enclosed path and mask everything in between those values. I have tried the approach here but I have to provide the logic for individual X and Y values which becomes cumbersome for a complicated path. import numpy as np import matplotlib.pyplot as plt origin = 'lower' delta = 0.025 x = y = np.arange(-3.0, 3.01, delta) X, Y = np.meshgrid(x, y) Z1 = np.exp(-X**2 - Y**2) Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) Z = (Z1 - Z2) * 2 fig1, ax2 = plt.subplots(constrained_layout=True) CS = ax2.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin=origin,extend='both') ax2.set_title('Random Plot') ax2.set_xlabel('X Axis') ax2.set_ylabel('Y Axis') cbar = fig1.colorbar(CS)
A convex shape such as a triangle can be defined by the equations of the lines going through their vertices. In this case the equations are quite simple: X >= 0 is the zone right of the line through 0,0 and 0,2. Similar Y >= 0 and X + Y <= 2 are the two other zones. The triangle is the intersection of these 3 zones. Setting the corresponding Z values to NaN will create the empty triangle in the contour plot. import numpy as np import matplotlib.pyplot as plt delta = 0.025 x = y = np.arange(-3.0, 3.01, delta) X, Y = np.meshgrid(x, y) Z1 = np.exp(-X ** 2 - Y ** 2) Z2 = np.exp(-(X - 1) ** 2 - (Y - 1) ** 2) Z = (Z1 - Z2) * 2 Z[(X >= 0) & (Y >= 0) & (X + Y <= 2)] = np.nan fig1, ax2 = plt.subplots() CS = ax2.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin='lower', extend='both') ax2.set_title('Random Plot missing a triangle') ax2.set_xlabel('X Axis') ax2.set_ylabel('Y Axis') cbar = fig1.colorbar(CS) plt.show() PS: The equation of a line through two points x1,y1 and x2,y2 is (X - x1) * (y2 - y1) - (Y - y1) * (x2 - x1) == 0 So, a more general code could look like: def line_eq(X, Y, p1, p2): x1, y1 = p1 x2, y2 = p2 return (X - x1) * (y2 - y1) - (Y - y1) * (x2 - x1) >= 0 p = [(0, 0), (0, 2), (2, 0)] # clockwise ordering Z[line_eq(X, Y, p[0], p[1]) & line_eq(X, Y, p[1], p[2]) & line_eq(X, Y, p[2], p[0])] = np.nan Note that when the vertices are ordered counterclockwise, the equation should be <= 0 to grab the interior convex shape. Concave shapes can be created by taking the union (logical or) of several convex shapes: def line_eq(X, Y, p1, p2): x1, y1 = p1 x2, y2 = p2 return (X - x1) * (y2 - y1) - (Y - y1) * (x2 - x1) >= 0 def convex_eq(X, Y, p): mask = line_eq(X, Y, p[-1], p[0]) for p1, p2 in zip(p[:-1], p[1:]): mask &= line_eq(X, Y, p1, p2) return mask def multiple_convex_eq(X, Y, c): mask = convex_eq(X, Y, c[0]) for ci in c: mask |= convex_eq(X, Y, ci) return mask p = [(0, 2.5), (1.5, 1), (1, -2), (-1, -2), (-1.5, 1)] # pentagon, clockwise ordering five_trianggles = [[(0, 0), p1, p2] for p1, p2 in zip(p, (p + p)[2:])] Z[multiple_convex_eq(X, Y, five_trianggles)] = np.nan
Multiplying multidimensional array in python
I have two arrays: L, M, N = 6, 31, 500 A = np.random.random((L, M, N)) B = np.random.random((L, L)) I am trying to get an array C such that: C = B * A C has dimension [L, M, N] I tried answer posted at this link but it hasn't given me the desired output. A for loop version of above code is: L, M, N = 6, 31, 500 A = np.random.random((L, M, N)) B = np.random.random((L, L)) z1 = [] for j in range(M): a = np.squeeze(A[:, j, :]) z1.append(np.dot(B, a)) z2 = np.stack(z1)
I think you are looking for numpy.tensordot() where you can specify along which axes to sum: np.tensordot(B,A,axes=(1,0))
Pick random tensors from another one in Tensorflow
I have a Tensor X whith shape [B, L, E] (let's say, B batches of L vectors of length E). From this Tensor X, I want to randomly pick N vectors in each batch, and so create Y with shape [B, N, E]. I tried to combine tf.random_uniform and tf.gather but I really struggle with the dimension and can't get Y.
You can use something like this: import tensorflow as tf import numpy as np B = 3 L = 5 E = 2 N = 3 input = np.array(range(B * L * E)).reshape([B, L, E]) print(input) print("#################################") X = tf.constant(input) batch_range = tf.tile(tf.reshape(tf.range(B, dtype=tf.int32), shape=[B, 1, 1]), [1, N, 1]) random = tf.random_uniform([B, N, 1], minval = 0, maxval = L - 1, dtype = tf.int32) indices = tf.concat([batch_range, random], axis = 2) output = tf.gather_nd(X, indices) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(indices)) print("#################################") print(sess.run(output))
Flatten out y-matrix and repeat x-vector
So I have a vector x and a matrix y where y[i] = [f(x[i]),f(x[i]),f(x[i])...] is a row of experimental values of f at x. I need to flatten out y so that I have two vectors with y[i] = f(x[i]). Here's what I'm using now: x = np.ravel([[xx]*y.shape[1] for xx in x]); y = np.ravel(y) Is there a cleaner/faster way?
You could just use np.repeat - x = x.repeat(y.shape[1])