Suppose I got a 3 dimension tensor input with shape(batch_size, dim_a, dim_b).
If I have a weight vector with shape (batch_size, dim_a), and want to get weighted sum of input, weighted_sum of shape (batch_size, dim_b). What should I do?
You could reshape your weight vector and make use of tf.reduce_sum:
import numpy as np
import tensorflow as tf
a = np.random.rand(5, 3, 2)
b = np.random.rand(5, 3)
input = tf.constant(a)
weight = tf.constant(b)
C = input * weight.reshape((5, 3, 1)) # Reshape and multiply weights and input
weighted_sum = tf.reduce_sum(C, axis=1) # Sum along dim_a
weighted_sum.shape
Out[9]: TensorShape([Dimension(5), Dimension(2)])
Related
How to concatenate tensors of shapes [None, 128] with tensor of [1,128]. Here the first tensor will some data of unknown length and the second tensor is fixed tensor not dependant on data size. The final output should be of shape[None, 328]. This is a part of a neural network concatenation.
I tried
> c = Concatenate(axis = -1, name = 'DQN_Input')([ a, b])
Here a.shape = (None, 192) and b.shape = (1,128)
But this does not work.
The error is
ValueError: A Concatenate layer requires inputs with matching
shapes except for the concat axis. Got inputs shapes: [(None, 192),
(1, 128)]
What you can do is use tf.repeat on b based on the first dimension of a to generate the same shape tensor. Here is a simple working example:
import tensorflow as tf
a = tf.keras.layers.Input((192, ), name = 'a')
alpha = tf.keras.layers.Input((1,),name = 'Alpha')
b = tf.matmul(alpha, a, transpose_a=True)
b = tf.repeat(b, repeats=tf.shape(a)[0], axis=0)
c = tf.keras.layers.Concatenate(axis = -1, name = 'DQN_Input')([ a, b])
model = tf.keras.Model([a, alpha], c)
tf.print(model((tf.random.normal((5, 192)), tf.random.normal((5, 1)))).shape)
TensorShape([5, 384])
I would like to initialize the weights for a (5,5) convolutional layer with four channels to be a numpy array. The input to this layer is of shape (128,128,1). In particular, I would like the following:
def custom_weights(shape, dtype=None):
matrix = np.zeros((1,5,5,4))
matrix[0,2,2,0,0] = 1
matrix[0,2,1,0,0] = -1
matrix[0,2,2,0,1] = 1
matrix[0,3,2,0,1] = -1
matrix[0,2,2,0,2] = 2
matrix[0,2,1,0,2] = -1
matrix[0,2,3,0,2] = -1
matrix[0,2,2,0,3] = 2
matrix[0,1,2,0,3] = -1
matrix[0,3,2,0,3] = -1
weights = K.variable(matrix)
return weights
input_shape = (128, 128, 1)
images = Input(input_shape, name='phi_input')
conv1 = Conv2D(4,[5, 5], use_bias = False, kernel_initializer=custom_weights, padding='valid', name='Conv2D_1', strides=1)(images)
However, when I try to do this, I get an error of
Depth of input (1) is not a multiple of input depth of filter (5) for 'Conv2D_1_19/convolution' (op: 'Conv2D') with input shapes: [?,128,128,1], [1,5,5,4].
Is my error in the shape of the weight matrix?
There are many inconsistencies (which led to errors) in your code, the error you're getting is not from the given code as it doesn't even index the matrix properly.
matrix = np.zeros((1,5,5,4))
matrix[0,2,2,0,0] = 1
You are initializing a numpy array with 4 dimensions but using 5 indices to change value.
Your dimensions for kernel weights are wrong. Here's the fixed code.
from tensorflow.keras.layers import *
from tensorflow.keras import backend as K
import numpy as np
def custom_weights(shape, dtype=None):
kernel = np.zeros((5,5,1,4))
# change value here
kernel = K.variable(kernel)
return kernel
input_shape = (128, 128, 1)
images = Input(input_shape, name='phi_input')
conv1 = Conv2D(4,[5, 5], use_bias = False, kernel_initializer=custom_weights, padding='valid', name='Conv2D_1', strides=1)(images)
I am trying to filter a TensorFlow tensor of shape (N_batch, N_data), where N_batch is the batch size (e.g. 32), and N_data is the size of the (noisy) timeseries array. I have a Gaussian kernel (taken from here), which is one-dimensional. I then want to use tensorflow.nn.conv1d to convolve this kernel with my signal.
I have been trying for most of the morning to get the dimensions of the input signal and the kernel right, but obviously with no success. From what I gathered from the interwebs, the dimensions of both the input signal and the kernel need to be aligned in some finicky way, and I just can't figure out which way that is. The TensorFlow error messages aren't particularly meaningful either (Shape must be rank 4 but is rank 3 for 'conv1d/Conv2D' (op: 'Conv2D') with input shapes: [?,1,1000], [1,81]). Below I've included a little piece of code to reproduce the situation:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# Based on: https://stackoverflow.com/a/52012658/1510542
# Credits to #zephyrus
def gaussian_kernel(size, mean, std):
d = tf.distributions.Normal(tf.cast(mean, tf.float32), tf.cast(std, tf.float32))
vals = d.prob(tf.range(start=-size, limit=size+1, dtype=tf.float32))
kernel = vals # Some reshaping is required here
return kernel / tf.reduce_sum(kernel)
def gaussian_filter(input, sigma):
size = int(4*sigma + 0.5)
x = input # Some reshaping is required here
kernel = gaussian_kernel(size=size, mean=0.0, std=sigma)
conv = tf.nn.conv1d(x, kernel, stride=1, padding="SAME")
return conv
def run_filter():
tf.reset_default_graph()
# Define size of data, batch sizes
N_batch = 32
N_data = 1000
noise = 0.2 * (np.random.rand(N_batch, N_data) - 0.5)
x = np.linspace(0, 2*np.pi, N_data)
y = np.tile(np.sin(x), N_batch).reshape(N_batch, N_data)
y_noisy = y + noise
input = tf.placeholder(tf.float32, shape=[None, N_data])
smooth_input = gaussian_filter(input, sigma=10)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
y_smooth = smooth_input.eval(feed_dict={input: y_noisy})
plt.plot(y_noisy[0])
plt.plot(y_smooth[0])
plt.show()
if __name__ == "__main__":
run_filter()
Any ideas?
You need to add channel dimensions to your input/kernel, since TF convolutions are generally used for multi-channel inputs/outputs. As you are working with simple 1-channel input/output this amounts to just adding some size-1 "dummy" axes.
Since by default convolution expects channels to come last, your placeholder should have shape [None, N_data, 1] and your input be modified like
y_noisy = y + noise
y_noisy = y_noisy[:, :, np.newaxis]
Similarly, you need to add input and output channel dimensions to your filter:
kernel = gaussian_kernel(size=size, mean=0.0, std=sigma)
kernel = kernel[:, tf.newaxis, tf.newaxis]
That is, the filter is expected to have shape [width, in_channels, out_cannels].
I have an input layer of size 32x32. Then I apply a 2d convolution with stride (4,4) and with 16 filters each having kernel size 4x4. Hence, the resulting shape will be 8 x 8 x 16. Now I want to reshape the result back to the input shape so that the channel dimension will turn back into 4x4 squares in the corresponding places, i.e. if we define the result of the convolution as T and the desired result as D, then I want D[i * 4 + k, j * 4 + l] = T [i , j , k * 8 + l], with i,j = 0,..,7 and k,l = 0,..,3. Is there a way to do this?
import numpy as np
from keras.layers import Input, Conv2D
from keras.initializers import Constant
input = Input(( 32, 32), dtype = 'float32')
filters = np.ndarray((4, 4, 16), dtype=np.float32)
# Initialization of the filter
filter_layer = Conv2D(16, 4, strides =(4,4), kernel_initialzer=Constant(filters), trainable = False)(input)
# no idea how to reshape the filter back
I have two vectors, weighted: shape (None, 3) and D: shape (None, 3, 5). Then I want to multiply weighted to D like weighted * D: shape(None, 3, 5).
I attached my image below. So each scalar value is multiplied to each row element.
So I tried multiply([weighted, D]), but I got an error ValueError: Operands could not be broadcast together with shapes (3, 5) (3,). I assume this is caused of different shape of inputs. Then, how do I fix this?
Update
multiply([weighted, Permute((2, 1))(D)]) worked. I am not sure but last element of shape must be same..
You can reshape weighted and use broadcasting to accomplish that. Like this:
weighted = weighted.reshape(-1, 3, 1)
result = weighted * D
Update 1: The same concept (broadcasting) can be used for instance in tensorflow with tf.expand_dims(weights, dim=2). My POC:
import tensorflow as tf
import numpy as np
tf.reset_default_graph()
anp = np.array([[1, 2, 10], [2, 1, 10]])
bnp = np.random.random((2, 3, 5))
with tf.Session() as sess:
weighted = tf.placeholder(tf.float32, shape=(None, 3))
D = tf.placeholder(tf.float32, shape=(None, 3, 5))
rweighted = tf.expand_dims(weighted, dim=2)
result = rweighted * D
r = sess.run(result, feed_dict={weighted: anp, D: bnp})
print(bnp)
print("--")
print(r)
For keras use the backend API:
from keras import backend as K
...
K.expand_dims(weighted, 2)