Split output of a layer in keras - python

Say, I have a layer with output dims (4, x, y). I want to split this into 4 separate (1, x, y) tensors, which I can use as input for 4 other layers.
What I'm essentially looking for is the opposite of the Merge layer. I know that there's no split layer in keras, but is there a simple way to do this in keras?

Are you looking for something like this?
import keras.backend as K
import numpy as np
val = np.random.random((4, 2, 3))
t = K.variable(value=val)
t1 = t[0, :, :]
t2 = t[1, :, :]
t3 = t[2, :, :]
t4 = t[3, :, :]
print('t1:\n', K.eval(t1))
print('t2:\n', K.eval(t2))
print('t3:\n', K.eval(t3))
print('t4:\n', K.eval(t4))
print('t:\n', K.eval(t))
It gives the following output:
t1:
[[ 0.18787734 0.1085723 0.01127671]
[ 0.06032621 0.14528386 0.21176969]]
t2:
[[ 0.34292713 0.56848335 0.83797884]
[ 0.11579451 0.21607392 0.80680907]]
t3:
[[ 0.1908586 0.48186591 0.23439431]
[ 0.93413448 0.535191 0.16410089]]
t4:
[[ 0.54303145 0.78971165 0.9961108 ]
[ 0.87826216 0.49061012 0.42450914]]
t:
[[[ 0.18787734 0.1085723 0.01127671]
[ 0.06032621 0.14528386 0.21176969]]
[[ 0.34292713 0.56848335 0.83797884]
[ 0.11579451 0.21607392 0.80680907]]
[[ 0.1908586 0.48186591 0.23439431]
[ 0.93413448 0.535191 0.16410089]]
[[ 0.54303145 0.78971165 0.9961108 ]
[ 0.87826216 0.49061012 0.42450914]]]
Note that, now t1, t2, t3, t4 is of shape(2,3).
print(t1.shape.eval()) # prints [2 3]
So, if you want to keep the 3d shape, you need to do the following:
t1 = t[0, :, :].reshape((1, 2, 3))
t2 = t[1, :, :].reshape((1, 2, 3))
t3 = t[2, :, :].reshape((1, 2, 3))
t4 = t[3, :, :].reshape((1, 2, 3))
Now, you get the spitted tensors in correct dimension.
print(t1.shape.eval()) # prints [1 2 3]
Hope that it will help you to solve your problem.

You can define Lambda layers to do the slicing for you:
from keras.layers import Lambda
from keras.backend import slice
.
.
x = Lambda( lambda x: slice(x, START, SIZE))(x)
For your specific example, try:
x1 = Lambda( lambda x: slice(x, (0, 0, 0), (1, -1, -1)))(x)
x2 = Lambda( lambda x: slice(x, (1, 0, 0), (1, -1, -1)))(x)
x3 = Lambda( lambda x: slice(x, (2, 0, 0), (1, -1, -1)))(x)
x4 = Lambda( lambda x: slice(x, (3, 0, 0), (1, -1, -1)))(x)

You can just simply use tf.split.

Related

Selective meshgrid in Tensorflow

Given the following code:
import tensorflow as tf
def combine(x, y):
xx, yy = tf.meshgrid(x, y, indexing='ij')
combo = tf.stack([tf.reshape(xx, [-1]), tf.reshape(yy, [-1])], axis=1)
print(combo)
x = tf.constant([11, 0, 7, 1])
combine(x, x)
I want to clean combo vector in order to obtain the following tf vector [(11, 0), (11, 7), (11, 1), (0, 7), (0, 1), (7, 1)]. Is it possible to do this in Tensorflow?
You can introduce a mask, to do get the desired result-
def combine(x, y):
xx, yy = tf.meshgrid(x, y, indexing='ij')
#create a mask to take the strictly upper triangular matrix
ones = tf.ones_like(xx)
mask = tf.cast(tf.linalg.band_part(ones, 0, -1) - tf.linalg.band_part(ones, 0, 0) , dtype=tf.bool)
x = tf.boolean_mask(xx, mask)
y = tf.boolean_mask(yy, mask)
combo = tf.stack([x, y], axis=1)
print(combo)
x = tf.constant([11, 0, 7, 1])
a = combine(x, x)
#output
[[11 0]
[11 7]
[11 1]
[ 0 7]
[ 0 1]
[ 7 1]],

how does the np.index_exp[] work in the 3D voxel / volumetric plot with rgb colors example

I am reading the example: https://matplotlib.org/stable/gallery/mplot3d/voxels_rgb.html#sphx-glr-gallery-mplot3d-voxels-rgb-py about creating a 3d sphere.
But I don't understand how the indexing works in the example. Can any one help me to understand. Thanks
> def midpoints(x):
> sl = ()
> for i in range(x.ndim):
>> x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]])
>> sl += np.index_exp[:]
>> print(np.index_exp[:-1])
>> print(x[np.index_exp[:-1]])
I know the "index_exp[:-1]" returns (slice(None,None,-1),) and "x[index_exp[:-1]]" will give result like this:
[[[0 0 0],
[0 0 0],
[0 0 0]],
[[1 1 1],
[1 1 1],
[1 1 1]]]
But I don't understand how the ```x[index_exp[:-1]]``` in the for loop only shows:
[[[1 1 1],
[1 1 1],
[1 1 1]]]
In the example, x, is one of the (17,17,17) arrays produced by
In [208]: r, g, b = np.indices((17, 17, 17)) / 16.0
...: rc = midpoints(r)
...: gc = midpoints(g)
...: bc = midpoints(b)
indices is like meshgrid and mgrid, creating grid arrays.
I haven't used np.index_exp, but I see it's the same as np.s_, except it always returns a tuple
In [225]: x = r.copy()
In [226]: ()+np.index_exp[:-1] # so this tuple can joined with sl
Out[226]: (slice(None, -1, None),)
In [227]: x[()+np.index_exp[:-1]].shape
Out[227]: (16, 17, 17)
In [228]: x[:-1].shape
Out[228]: (16, 17, 17)
so
x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]])/2.0
for the initial sl, this is
x = (x[:-1] + x[1:])/2.0
x[1:]-x[:-1] is widely used to take the difference between adjacent elements, np.diff. Here it just acts on the first dimension (of 3). So this is just the mean of adjacent points. Note both x[:-1] and x[1:] are (16,17,17) arrays.
The next bit just adds a [:] slice to sl:
In [230]: sl += np.index_exp[:]
In [231]: sl
Out[231]: (slice(None, None, None),)
In [232]: sl + np.index_exp[:-1]
Out[232]: (slice(None, None, None), slice(None, -1, None))
So this is doing
x[:, :-1] # which should be a (17,16,17) array
and the next iteration x[:,:, :-1] # (17,17,16)
This r varies only in the first dimension, so can compare its values with the midpoints with:
In [249]: r1 = midpoints(r)
In [250]: r[:5,0,0]
Out[250]: array([0. , 0.0625, 0.125 , 0.1875, 0.25 ])
In [251]: r1[:4,0,0]
Out[251]: array([0.03125, 0.09375, 0.15625, 0.21875])
So the use index_exp just allows them to write the (x[:-1]+x[1:])/2 averaging in a general way that applies to all 3 dimensions the r, g.b arraus/

Two tensorflow tensors of shape T1 = N*D, T2 = M*D; M < N. T1 has rows in T2. Find indices of rows in T1 tensor for each row in T2

I have two Tensors T1 (N * D dimension) and T2(M * D dimension)(M is less than N). T2 rows are guaranteed to be in T1. For each row in T2, Is there a way to find the indices of T1 where the row matches?
I am able to solve the problem using eager execution.
import tensorflow as tf
import numpy as np
tf.enable_eager_execution()
x = tf.random_normal([15,3])
y = x[:2] # first two entries
y= tf.concat([y,x[8:9]], 0)
output = []
for row in x:
if row.numpy() in y.numpy():
output.append(True)
else:
output.append(False)
Could someone provide help for executing without eager execution?
How do we perform the same operation if T1 and T2 are batches? i.e. T1 - B * N * D and T2 - B * M * D
P.S. How do we search for a row in Tensorflow?
Here is how you can do that:
import tensorflow as tf
def find_row_indices(t1, t2):
# Compare every pair of rows
eq = tf.equal(tf.expand_dims(t1, -3), tf.expand_dims(t2, -2))
# Find where all the elements in two rows match
matches = tf.reduce_all(eq, axis=-1)
# Find indices where match occurs
idx = tf.argmax(tf.cast(matches, tf.uint8), axis=-1)
# Find where there has been no match
has_match = tf.reduce_any(matches, axis=-1)
# Return match index of -1 if no match found
return tf.where(has_match, idx, -tf.ones_like(idx))
# Test
with tf.Graph().as_default():
tf.set_random_seed(100)
x = tf.random_normal([15, 3])
y = x[:2]
y = tf.concat([y, x[8:9]], 0)
idx = find_row_indices(x, y)
with tf.Session() as sess:
print(sess.run(idx))
# [0 1 8]
It has quadratic space and memory cost, because it compares every pair of rows to each other, so having two very big inputs could be problematic in some cases. Also, if there is more than one matching index, this method does not guarantee which one of them will be returned.
EDIT: The function above can also be used with arrays with more initial dimensions. For example:
import tensorflow as tf
with tf.Graph().as_default():
tf.set_random_seed(100)
x = tf.random_normal([4, 15, 3])
y = tf.gather_nd(x, [[[ 0, 3], [ 0, 6], [ 0, 2]],
[[ 1, 10], [ 1, 5], [ 1, 12]],
[[ 2, 8], [ 2, 1], [ 2, 0]],
[[ 3, 9], [ 3, 14], [ 3, 4]]])
idx = find_row_indices(x, y)
with tf.Session() as sess:
print(sess.run(idx))
# [[ 3 6 2]
# [10 5 12]
# [ 8 1 0]
# [ 9 14 4]]

Map function along arbitrary dimension with pytorch? numpy?

I wonder why I find no utility to map custom pytorch or numpy transformations along any dimensions of complicated tensors/arrays/matrices.
I think I remember that such a thing was available in R. With this fantasy tch.map utility you could do:
>>> import torch as tch # or numpy
>>> # one torch tensor
>>> a = tch.tensor([0, 1, 2, 3, 4])
>>> # one torch function (dummy) returning 2 values
>>> f = lambda x: tch.tensor((x + 1, x * 2))
>>> # map f along dimension 0 of a, expecting 2 outputs
>>> res = tch.map(f, a, 0, 2) # fantasy, optimized on CPU/GPU..
>>> res
tensor([[1, 0],
[2, 2],
[3, 4],
[4, 6],
[5, 8]])
>>> res.shape
torch.Size([5, 2])
>>> # another tensor
>>> a = tch.tensor(list(range(24))).reshape(2, 3, 4).type(tch.double)
>>> # another function (dummy) returning 2 values
>>> f = lambda x: tch.tensor((tch.mean(x), tch.std(x)))
>>> # map f along dimension 2 of a, expecting 2 outputs
>>> res = tch.map(f, a, 2, 2) # fantasy, optimized on CPU/GPU..
tensor([[[ 1.5000, 1.2910],
[ 5.5000, 1.2910],
[ 9.5000, 1.2910]],
[[13.5000, 1.2910],
[17.5000, 1.2910],
[21.5000, 1.2910]]])
>>> res.shape
torch.Size([2, 3, 2])
>>> # yet another tensor
>>> a = tch.tensor(list(range(12))).reshape(3, 4)
>>> # another function (dummy) returning 2x2 values
>>> f = lambda x: x + tch.rand(2, 2)
>>> # map f along all values of a, expecting 2x2 outputs
>>> res = tch.map(f, a, -1, (2, 2)) # fantasy, optimized on CPU/GPU..
>>> print(res)
tensor([[[[ 0.4827, 0.3043],
[ 0.8619, 0.0505]],
[[ 1.4670, 1.5715],
[ 1.1270, 1.7752]],
[[ 2.9364, 2.0268],
[ 2.2420, 2.1239]],
[[ 3.9343, 3.6059],
[ 3.3736, 3.5178]]],
[[[ 4.2063, 4.9981],
[ 4.3817, 4.4109]],
[[ 5.3864, 5.3826],
[ 5.3614, 5.1666]],
[[ 6.6926, 6.2469],
[ 6.7888, 6.6803]],
[[ 7.2493, 7.5727],
[ 7.6129, 7.1039]]],
[[[ 8.3171, 8.9037],
[ 8.0520, 8.9587]],
[[ 9.5006, 9.1297],
[ 9.2620, 9.8371]],
[[10.4955, 10.5853],
[10.9939, 10.0271]],
[[11.3905, 11.9326],
[11.9376, 11.6408]]]])
>>> res.shape
torch.Size([3, 4, 2, 2])
Instead, I keep finding myself messing around with complicated tch.stack, tch.squeeze, tch.reshape, tch.permute, etc., counting dimensions on my fingers not to get lost.
Does such a utility exist and I have missed it for some reason?
Is such a utility impossible to implement for some reason?

Evaluate normal cdfs at each of several points

I want to evaluate several normal CDFs, defined by a 4x3 grid of points, at each of 5 points.
import numpy as np
import scipy.stats
a = np.array([-1, 0, 1])
b = np.array([1, 2, 3, 4])
x = np.array([-.5, 0, .5, 1, 2])
grid_a, grid_b = np.meshgrid(a,b)
scipy.stats.norm(loc=grid_a, scale=grid_b).cdf(x)
Raises this exception:
ValueErrorTraceback (most recent call last)
<ipython-input-46-82423c7451d2> in <module>()
3 x = np.array([-.5, 0, .5, 1, 2])
4 grid_a, grid_b = np.meshgrid(a,b)
----> 5 scipy.stats.norm(loc=grid_a, scale=grid_b).cdf(x)
~/.envs/practice/lib/python3.6/site-packages/scipy/stats/_distn_infrastructure.py in cdf(self, x)
454
455 def cdf(self, x):
--> 456 return self.dist.cdf(x, *self.args, **self.kwds)
457
458 def logcdf(self, x):
~/.envs/practice/lib/python3.6/site-packages/scipy/stats/_distn_infrastructure.py in cdf(self, x, *args, **kwds)
1733 args = tuple(map(asarray, args))
1734 dtyp = np.find_common_type([x.dtype, np.float64], [])
-> 1735 x = np.asarray((x - loc)/scale, dtype=dtyp)
1736 cond0 = self._argcheck(*args) & (scale > 0)
1737 cond1 = self._open_support_mask(x) & (scale > 0)
ValueError: operands could not be broadcast together with shapes (5,) (4,3)
You have to reshape a, b and x to be compatible for broadcasting. You can do this, for example, by adding one trivial dimension to a and two trivial dimensions to b. That is, use a[:, None] (which has shape (3, 1)) and b[:, None, None] (which has shape (4, 1, 1)). (Instead of None, you might prefer the more explicit np.newaxis, but its value is just None.) Then with x having shape (5,) and the reshaped a and b having shapes (3, 1) and (4, 1, 1), respectively, the shape of the computed result with broadcasting is (4, 3, 5):
In [45]: from scipy.stats import norm
In [46]: a = np.array([-1, 0, 1])
In [47]: b = np.array([1, 2, 3, 4])
In [48]: x = np.array([-.5, 0, .5, 1, 2])
In [49]: c = norm.cdf(x, loc=a[:, None], scale=b[:, None, None])
In [50]: c.shape
Out[50]: (4, 3, 5)
In [51]: c
Out[51]:
array([[[0.69146246, 0.84134475, 0.9331928 , 0.97724987, 0.9986501 ],
[0.30853754, 0.5 , 0.69146246, 0.84134475, 0.97724987],
[0.0668072 , 0.15865525, 0.30853754, 0.5 , 0.84134475]],
[[0.59870633, 0.69146246, 0.77337265, 0.84134475, 0.9331928 ],
[0.40129367, 0.5 , 0.59870633, 0.69146246, 0.84134475],
[0.22662735, 0.30853754, 0.40129367, 0.5 , 0.69146246]],
[[0.56618383, 0.63055866, 0.69146246, 0.74750746, 0.84134475],
[0.43381617, 0.5 , 0.56618383, 0.63055866, 0.74750746],
[0.30853754, 0.36944134, 0.43381617, 0.5 , 0.63055866]],
[[0.54973822, 0.59870633, 0.64616977, 0.69146246, 0.77337265],
[0.45026178, 0.5 , 0.54973822, 0.59870633, 0.69146246],
[0.35383023, 0.40129367, 0.45026178, 0.5 , 0.59870633]]])
It also works to use the cdf() method of the "frozen" distribution norm(loc=a[:, None], scale=b[:, None, None]) like you did in the question:
In [52]: c = norm(loc=a[:, None], scale=b[:, None, None]).cdf(x)
In [53]: c.shape
Out[53]: (4, 3, 5)

Categories