How to make a checkerboard matrix in tensorflow? - tensorflow

I need to initialize a checkerboard matrix to merge two feature maps in my tensorflow graph, I was able to do it for a known shape using numpy beside TF like this
def checkerboard_concat(x1, x2):
mask1 = np.ones((10,10,3))
mask1[1::2,::2] = 0
mask1[::2,1::2] = 0
mask2 = np.zeros((10,10,3))
mask2[1::2,::2] = 1
mask2[::2,1::2] = 1
return x1 * mask1 + x2 * mask2
But I was not able to do it with a dynamic shape, I used tf.shape() that returns an output of shape (N,) but I don't how to evaluate it dynamically.
Also, I tried using tf.ones_like(x1) but couldn't use subscripts to change it like a numpy array

Here is a solution based on modulo and XOR operations:
import tensorflow as tf
def make_checkerboard(N):
"""
Return a NxN checkerboard matrix M, i.e. with M(i,j) == True if (i+j) mod 2 == 1
:param N: Length of the checkerboard (can be dynamic)
:return: Boolean tensor of shape NxN
"""
range_n = tf.range(N)
odd_ind = tf.cast(tf.mod(range_n, 2), dtype=tf.bool)
odd_rows = tf.tile(tf.expand_dims(odd_ind , -1), [1, N])
odd_cols = tf.tile(tf.expand_dims(odd_ind , 0), [N, 1])
checker = tf.logical_xor(odd_rows, odd_cols)
return checker
def checkerboard_concat(x1, x2, is_batch=True):
dynamic_n = tf.shape(x1)[1 if is_batch else 0]
mask2 = make_checkerboard(dynamic_n)
mask2 = tf.expand_dims(mask2, -1) # Expand masks to cover channels
mask1 = tf.logical_not(mask2)
return x1 * tf.cast(mask1, dtype=x1.dtype) + x2 * tf.cast(mask2, dtype=x2.dtype)
# Example:
tf.reset_default_graph()
sess = tf.InteractiveSession()
x1 = tf.ones((4,4,3), dtype=tf.int32)
x2 = tf.ones((4,4,3), dtype=tf.int32) * 2
x = checkerboard_concat(x1, x2, is_batch=False)
res = sess.run(x)
print(res[...,0])
# [[1 2 1 2]
# [2 1 2 1]
# [1 2 1 2]
# [2 1 2 1]]

Related

How to create compilable tf.keras model with multiple tensor inputs?

This is with tf 2.1.0
The following works up until you try to call a compiled model. Is there something to do to make the .compile and .fit methods work for multiple tensor inputs?
import numpy as np
import pandas as pd
import tensorflow as tf
import tensorflow.keras as keras
tf.keras.backend.set_floatx('float64')
m = 250 # samples
n_x = 1 # dim of x
n_tau = 11
x = (2 * np.random.rand(m, n_x).astype(np.float64) - 1) * 2
i = np.argsort(x[:, 0])
x = x[i] # to make plotting nicer
A = np.random.randn(n_x, 1)
y = x ** 2 + 0.3 * x + 0.4 * np.random.randn(m, 1).astype(np.float64)
y = y.dot(A) # y is 1d
y = y[:, :, None]
tau = np.linspace(1.0 / n_tau, 1 - 1.0 / n_tau, n_tau).astype(np.float64)
tau = tau[None, :, None]
def loss(tau_y, u):
tau = tau_y[0]
y = tau_y[1]
u = y - u
res = u ** 2 * (tau - tf.where(u <= np.float64(0.0), np.float64(1.0), np.float64(0.0)))
return tf.reduce_sum(tf.reduce_mean(res, axis=[1, 2]), axis=0)
tf.keras.backend.set_floatx('float64')
class My(tf.keras.models.Model):
def __init__(self):
super().__init__()
self._my_layer = tf.keras.layers.Dense(1, dtype=tf.float64)
def call(self, inputs):
tau = inputs[0]
y = inputs[1]
tf.print(tau.shape, y.shape)
return self._my_layer(tau)
model = My()
u = model((tau, y)) # calling model works
l = loss((tau, y), model((tau, y))) # call loss works
opt = tf.keras.optimizers.Adam(learning_rate=0.01)
model.compile(optimizer=opt, loss=loss)
# this fails with the error below
model.fit((tau, y), (tau, y))
# ValueError: Error when checking model target: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 1 array(s), for inputs ['output_1'] but instead got the following list of 2 arrays: [array([[[0.09090909],
# [0.17272727],
# [0.25454545],
# [0.33636364],
# [0.41818182],
# [0.5 ],
# [0.58181818],
# [0.66363636],
# [0.74545455],
# ...

How to do combination matrices in tf.Variable?

I have these 2 matrices and I need to combine them so:
these are them in code:
matrix_a = tf.Variable(np.zeros(big_shape, dtype=np.float32))
matrix_b = tf.Variable(np.zeros(small_shape, dtype=np.float32))
#here I need to combine them
How can I do that?
###################################################### EDITED
Thanks to #jdehesa I've written this code:
shape = (batch_size, window_size, window_size, num_channels)
# the variable we're going to optimize over
modifier = tf.Variable(np.zeros(shape, dtype=np.float32))
mask = tf.zeros((batch_size, image_size, image_size, num_channels), tf.float32)
# Get input shapes
modifier_shape = tf.shape(modifier)
mask_shape = tf.shape(mask)
# Make indices grid
oo, ii, jj, kk = tf.meshgrid(tf.range(modifier_shape[0]), tf.range(modifier_shape[1]), tf.range(modifier_shape[2], modifier_shape[3]), indexing='ij')
# Shift indices
ii += y_window
jj += x_window
# Scatter update
mask_to_apply = tf.tensor_scatter_nd_update(mask, tf.stack([oo, ii, jj, kk], axis=-1), modifier)
bot now I have this error:
ValueError: Requires start <= limit when delta > 0: 28/1 for 'range_2' (op: 'Range') with input shapes: [], [], [] and with computed input tensors: input[0] = <28>, input[1] = <1>, input[2] = <1>.
Why?
This is a way to do that:
import tensorflow as tf
# Input data (assumes two 2D tensors, `a` at least as big as `b`)
a = tf.zeros((4, 4), tf.int32)
b = tf.ones((2, 2), tf.int32)
# Get input shapes
a_shape = tf.shape(a)
b_shape = tf.shape(b)
# Make indices grid
ii, jj = tf.meshgrid(tf.range(b_shape[0]), tf.range(b_shape[1]), indexing='ij')
# Shift indices
ii += a_shape[0] - b_shape[0]
jj += a_shape[1] - b_shape[1]
# Scatter update
c = tf.tensor_scatter_nd_update(a, tf.stack([ii, jj], axis=-1), b)
tf.print(c)
# [[0 0 0 0]
# [0 0 0 0]
# [0 0 1 1]
# [0 0 1 1]]

Indexing 4D array with an indexing array along last two axes - NumPy / Python

I want to create a batch of zero images with several channels and with some one given pixel per image with value one.
If the images are indexed only by the number of channels, the following code do the work just fine:
num_channels = 3
im_size = 2
images = np.zeros((num_channels, im_size, im_size))
# random locations for the ones
pixels = np.random.randint(low=0, high=im_size,
size=(num_channels, 2))
images[np.arange(num_channels), pixels[:, 0], pixels[:, 1]] = 1
However, the analogous code fails if we want to consider the batch too:
batch_size = 4
num_channels = 3
im_size = 2
images = np.zeros((batch_size, num_channels, im_size, im_size))
# random locations for the ones
pixels = np.random.randint(low=0, high=im_size,
size=(batch_size, num_channels, 2))
images[np.arange(batch_size), np.arange(num_channels), pixels[:, :, 0], pixels[:, :, 1]] = 1
which gives the error
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (4,) (3,) (4,3) (4,3)
The following code will do the work, using an inefficient loop:
batch_size = 4
num_channels = 3
im_size = 2
images = np.zeros((batch_size, num_channels, im_size, im_size))
# random locations for the ones
pixels = np.random.randint(low=0, high=im_size,
size=(batch_size, num_channels, 2))
for k in range(batch_size):
images[k, np.arange(num_channels), pixels[k, :, 0], pixels[k, :, 1]] = 1
How would you obtain a vectorized solution?
A simple vectorized using advanced-indexing would be -
I,J = np.arange(batch_size)[:,None],np.arange(num_channels)
images[I, J, pixels[...,0], pixels[...,1]] = 1
Alternative easier way to get those I,J indexers would be with np.ogrid -
I,J = np.ogrid[:batch_size,:num_channels]

are tensorflow operations pointwise?

If I do the following:
r = (x - mn) / std
where x is of shape (batchSize, 100), mn, and std are all of length (1, 100)
Are the subtraction and division done pointwise? I would expect to r to be (batchSize, 100).
I cannot examine the shapes directly because using tf.keras.batch_flatten obliberates the shapes.
For example:
x.shape
TensorShape([Dimension(None), Dimension(314), Dimension(314), Dimension(8)])
x = K.batch_flatten(x)
<tf.Tensor 'conv2d_1/activity_regularizer/Reshape_2:0' shape=(?, ?) dtype=float32>
x.shape
TensorShape([Dimension(None), Dimension(None)])
Everything concerning Keras and Tensorflow is Numpy compatible as it could be. So let's have a look.
x = np.array([1,2,3,4,5])
m = np.array([1,1,1,1,1])
n = np.array([5,4,3,2,1])
std = 10
m_times_n = m * n
# [5 4 3 2 1]
x_minus_mn = x - m_times_n
# [-4 -2 0 2 4]
r = x_minus_mn / std
# [-0.4 -0.2 0. 0.2 0.4]
So they are pointwise. Or let's see what happens in Tensorflow:
tf.enable_eager_execution()
x = tf.constant([1,2,3,4,5])
m = tf.constant([1,1,1,1,1])
n = tf.constant([5,4,3,2,1])
std = tf.constant(10)
m_times_n = m * n
# tf.Tensor([5 4 3 2 1], shape=(5,), dtype=int32)
x_minus_mn = x - m_times_n
# tf.Tensor([-4 -2 0 2 4], shape=(5,), dtype=int32)
r = x_minus_mn / std
# tf.Tensor([-0.4 -0.2 0. 0.2 0.4], shape=(5,), dtype=float64)
Pointwise as well.
Also in your post you have mentioned that you have issues with tf.keras.batch_flatten. The resulting (?, ?) shape is because of the way tf.keras.batch_flatten works. Let's have a look:
# Assuming we have 5 images, with 320x320 size, and 3 channels
X = tf.ones((5, 320,320, 3))
flatten = tf.keras.backend.batch_flatten(X)
flatten.shape
# (5, 307200)
Taken from the documentation:
Turn a nD tensor into a 2D tensor with same 0th dimension.
And we are seeing the exact thing. The 0th (batch_size) has been kept, while all other dimensions were squeezed such that the resulting tensor is 2D.

How to convert [0,0,0,1,2,2] to [0,1,2,0,0,1]?

Using standard TensorFlow operators, how can I convert a 1D tensor which has values in ascending order to a 1D tensor in which each value is the number of times the value at the same index in the input tensor has appeared when scanning from left to right?
An example is given in the question title.
You can achieve this using tf.while_loop. I suggest the following solution:
import tensorflow as tf
def scan_accum(a):
def condition(a):
def c(counts, acc, i):
return tf.less(i, tf.gather(tf.shape(a), 0))
return c
def body(a):
def b(counts, acc, i):
current = tf.gather(a, i)
ant = tf.gather(a, tf.add(i, -1))
update = tf.scatter_nd(tf.reshape(i, shape=(1, 1)),
tf.expand_dims(acc, axis=0),
shape=tf.shape(counts))
counts_ = tf.cond(
pred=tf.equal(current, ant),
true_fn=lambda: counts + update,
false_fn=lambda: counts
)
acc_ = tf.cond(
pred=tf.equal(current, ant),
true_fn=lambda: tf.add(acc, 1),
false_fn=lambda: tf.constant(1, dtype=counts.dtype)
)
i_ = tf.add(i, 1)
return [counts_, acc_, i_]
return b
i = tf.constant(1)
counts = tf.zeros_like(a)
acc = tf.constant(1, dtype=counts.dtype)
counts, _, _ = tf.while_loop(cond=condition(a),
body=body(a),
loop_vars=[counts, acc, i])
return counts
a = tf.constant([0, 0, 0, 1, 2, 2])
with tf.Session() as sess:
print(sess.run(scan_accum(a))) # prints [0 1 2 0 0 1]