I have successfully performed 2d interpolation in python using the RectBivariateSpline method from scipy.interpolate. However, it is performed on numpy arrays. I want to perform it on tensors solely using tensorflow.
This is what I have right now: It works if all are numpy arrays. However, I am having a hard time to rewrite it in tensorflow.
x_old = np.arange(0,256)
y_old = np.arange(0,256)
#x = tensor of shape [256,256]
#y = tensor of shape [256,256]
#in_im = tensor of shape [256,256,3]
#out_im = tensor of shape [256,256,3]
for d in range(0,3):
interpf = RectBivariateSpline( x_old, y_old, in_im[:,:,d])
out_im[:,:,d] = interpf.ev(x[:,:], y[:,:])
The resize operators in tf.image might be what you are looking for, e.g. tf.image.resize_bicubic (https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/image/resize_bicubic)
To convert tensors into numpy array is the solution.
This question about conversion might be helpful.
In short, Any tensor returned by Session.run or eval is a NumPy array.
Example code is below.
import tensorflow as tf
import numpy as np
from scipy.interpolate import RectBivariateSpline
x = tf.constant([1,2,3,4])
y = tf.constant([1,2,3,4,5])
vals = tf.constant([
[4,1,4,4,2],
[4,2,3,2,6],
[3,7,4,3,5],
[2,4,5,3,4]
])
sess = tf.Session()
x, y, vals = sess.run([x, y, vals]) # x, y vals are now ndarray
rect_B_spline = RectBivariateSpline(x, y, vals)
a = tf.constant([3.2, 3.8, 2.2])
b = tf.constant([2.4, 4.3, 3.3])
a = sess.run([a, b])
print(rect_B_spline.ev(a, b))
Related
I am currently stuck on a problem on which I am required to generate a curve of best fit which I am required to use a more precise x array from 250 to 100 in steps of 10. Here is my code below so far..
import numpy as np
from numpy import polyfit, polyval
import matplotlib.pyplot as plt
x = [250,300,350,400,450,500,550,600,700,750,800,900,1000]
x = np.array(x)
y = [0.791, 0.846, 0.895, 0.939, 0.978, 1.014, 1.046, 1.075, 1.102, 1.148, 1.169, 1.204, 1.234]
y= np.array(y)
r = polyfit(x,y,3)
fit = polyval(r, x)
plt.plot(x, fit, 'b')
plt.plot(x,y, color = 'r', marker = 'x')
plt.show()
If I understand correctly, you are trying to create an array of numbers from a to b by steps of c.
With pure python you can use:
list(range(a, b, c)) #in your case list(range(250, 1000, 10))
Or, since you are using numpy you can directly make the numpy array:
np.arange(a, b, c)
To create an array in steps you can use numpy.arange([start,] stop[, step]):
import numpy as np
x = np.arange(250,1000,10)
To generate values from 250-1000, use range(start, stop, step):
x = range(250,1001,10)
x = np.array(x)
I am currently using a modified version of the U-Net (https://arxiv.org/pdf/1505.04597.pdf) to segment cell organelles in microscopy images. Since I am using Keras, I took the code from https://github.com/zhixuhao/unet. However, in this version no weight map is implemented to force the network to learn the border pixels.
The results that I have obtained so far are quite good, but the network fails to separate objects that are close to each other. So I want to try and make use of the weight map mentioned in the paper. I have been able to generate the weight map (based on the given formula) for each label image, but I was unable to find out how to use this weight map to train my network and thus solve the above mentioned problem.
Do weight maps and label images have to be combined somehow or is there a Keras function that will allow me to make use of the weight maps? I am Biologist, who only recently started to work with neural networks, so my understanding is still limited. Any help or advice would be greatly appreciated.
In case it is still relevant: I needed to solve this recently. You can paste the code below into a Jupyter notebook to see how it works.
%matplotlib inline
import numpy as np
from skimage.io import imshow
from skimage.measure import label
from scipy.ndimage.morphology import distance_transform_edt
import numpy as np
def generate_random_circles(n = 100, d = 256):
circles = np.random.randint(0, d, (n, 3))
x = np.zeros((d, d), dtype=int)
f = lambda x, y: ((x - x0)**2 + (y - y0)**2) <= (r/d*10)**2
for x0, y0, r in circles:
x += np.fromfunction(f, x.shape)
x = np.clip(x, 0, 1)
return x
def unet_weight_map(y, wc=None, w0 = 10, sigma = 5):
"""
Generate weight maps as specified in the U-Net paper
for boolean mask.
"U-Net: Convolutional Networks for Biomedical Image Segmentation"
https://arxiv.org/pdf/1505.04597.pdf
Parameters
----------
mask: Numpy array
2D array of shape (image_height, image_width) representing binary mask
of objects.
wc: dict
Dictionary of weight classes.
w0: int
Border weight parameter.
sigma: int
Border width parameter.
Returns
-------
Numpy array
Training weights. A 2D array of shape (image_height, image_width).
"""
labels = label(y)
no_labels = labels == 0
label_ids = sorted(np.unique(labels))[1:]
if len(label_ids) > 1:
distances = np.zeros((y.shape[0], y.shape[1], len(label_ids)))
for i, label_id in enumerate(label_ids):
distances[:,:,i] = distance_transform_edt(labels != label_id)
distances = np.sort(distances, axis=2)
d1 = distances[:,:,0]
d2 = distances[:,:,1]
w = w0 * np.exp(-1/2*((d1 + d2) / sigma)**2) * no_labels
else:
w = np.zeros_like(y)
if wc:
class_weights = np.zeros_like(y)
for k, v in wc.items():
class_weights[y == k] = v
w = w + class_weights
return w
y = generate_random_circles()
wc = {
0: 1, # background
1: 5 # objects
}
w = unet_weight_map(y, wc)
imshow(w)
I think you want to use class_weight in Keras. This is actually simple to introduce in your model if you have already calculated the class weights.
Create a dictionary with your class labels and their associated weights. For example
class_weight = {0: 10.9,
1: 20.8,
2: 1.0,
3: 50.5}
Or create a 1D Numpy array of the same length as your number of classes. For example
class_weight = [10.9, 20.8, 1.0, 50.5]
Pass this parameter during training in your model.fit or model.fit_generator
model.fit(x, y, batch_size=batch_size, epochs=num_epochs, verbose=1, class_weight=class_weight)
You can look up the Keras documentation for more details here.
I have a case where matrix multiplication of two matrices with certain dimensions work in numpy, but doesn't work in tensorflow.
x = np.ndarray(shape=(10,20,30), dtype = float)
y = np.ndarray(shape=(30,40), dtype = float)
z = np.matmul(x,y)
print("np shapes: %s x %s = %s" % (np.shape(x), np.shape(y), np.shape(z)))
This works as expected and prints:
np shapes: (10, 20, 30) x (30, 40) = (10, 20, 40)
However in tensorflow when I try to multiply placeholder and variable of the same shapes as the numpy arrays above I get an error
x = tf.placeholder(tf.float32, shape=(10,20,30))
y = tf.Variable(tf.truncated_normal([30,40], name='w'))
print("tf shapes: %s x %s" % (x.get_shape(), y.get_shape()))
tf.matmul(x,y)
Results in
tf shapes: (10, 20, 30) x (30, 40)
InvalidArgumentError:
Shape must be rank 2 but is rank 3 for 'MatMul_12'
(op: 'MatMul') with input shapes: [10,20,30], [30,40].
Why does this operation fail?
Don't know why tf.matmul does not support this kind of multiplication (may be one of the core developers could provide a meaningful answer).
But if you just want to be able to multiply tensors in this way, take a look at tf.einsum function. It could operate with tensors of arbitrary rank.
As suggested by Dmytro tf.einsum can be used to multiply these two arrays.
x = np.ndarray(shape=(10,20,30), dtype = float)
y = np.ndarray(shape=(30,40), dtype = float)
These two operations produce exactly the same result:
np.einsum('ijk,kl->ijl', x, y)
np.matmul(x,y)
And corresponding tensorflow operation also works
tf.einsum('ijk,kl->ijl', tf_x,tf_y)
People already told you that you can use tf.einsum() to get the result you want.
import tensorflow as tf
x = tf.random_normal([10, 20, 30])
y = tf.random_normal([30, 40])
z = tf.einsum('ijk,kl->ijl', x, y)
The reason why tf.matmul() does not work the way you expected is written in the documentation.
The inputs must be matrices (or tensors of rank > 2, representing
batches of matrices), with matching inner dimensions, possibly after
transposition.
In your case you have a matrix y and a tensor x (rank 3 > 2). In your case inner dimensions do not match. If you want, them to match, you will need to have something like this:
import tensorflow as tf
a, b, c = 12, 50, 20
x = tf.random_normal([a, b, c])
y = tf.random_normal([a, c, b])
z = tf.matmul(x, y)
But clearly it calculates not the stuff you want.
Consider the following code snippet:
import theano.tensor as T
import theano.tensor
import numpy as np
batch_shape = (50, 40, 30, 30)
batch_size = batch_shape[0]
ncols = batch_shape[1]*batch_shape[2]*batch_shape[3]
minibatch = theano.tensor.tensor4(name='minibatch',
dtype=theano.config.floatX)
xflat = minibatch.reshape((batch_size,ncols))
partition = np.array([1, 2, 3])
xsub1 = xflat[:,partition]
partition = np.array([1])
xsub2 = xflat[:,partition]
print "xsub1.type: ", xsub1.type
print "xsub2.type: ", xsub2.type
If you run it, you get the following output:
xsub1.type: TensorType(float64, matrix)
xsub2.type: TensorType(float64, col)
Apparently indexing with an array of length 1 turns xsub2 into a col instead of a matrix. How can i make xsub2 be a matrix?
A col or "column vector" is the name Theano uses for a symbolic matrix that it knows contains only one column. It should be possible to use it just like a matrix.
Theano often doesn't know the shape of a particular symbolic tensor, only its dimensionality. However, in some circumstances, such as that given in the question, Theano is able to infer that a tensor has a particular special case of shape and can sometimes use this information to optimize the computation. This is why col (and row) exist as special cases of matrix.
If you think about the shape more than the type then you'll see that Theano is behaving just the same as numpy:
import theano
import theano.tensor
import numpy as np
def compute(minibatch):
xflat = minibatch.reshape((minibatch.shape[0], -1))
partition = np.array([1, 2, 3])
xsub1 = xflat[:, partition]
partition = np.array([1])
xsub2 = xflat[:, partition]
return xsub1, xsub2
def compile_theano_version():
minibatch = theano.tensor.tensor4(name='minibatch', dtype=theano.config.floatX)
xsub1, xsub2 = compute(minibatch)
print xsub1.type, xsub2.type
return theano.function([minibatch], [xsub1, xsub2])
def numpy_version(minibatch):
return compute(minibatch)
def main():
batch_shape = (50, 40, 30, 30)
minibatch = np.random.standard_normal(size=batch_shape).astype(theano.config.floatX)
xsub1, xsub2 = numpy_version(minibatch)
print xsub1.shape, xsub2.shape
theano_version = compile_theano_version()
xsub1, xsub2 = theano_version(minibatch)
print xsub1.shape, xsub2.shape
main()
This prints
(50L, 3L) (50L, 1L)
TensorType(float64, matrix) TensorType(float64, col)
(50L, 3L) (50L, 1L)
So a col is indeed a matrix with one column and not a vector.
To reproduce my problem, try this first (mapping with py_func):
import tensorflow as tf
import numpy as np
def image_parser(image_name):
a = np.array([1.0,2.0,3.0], dtype=np.float32)
return a
images = [[1,2,3],[4,5,6]]
im_dataset = tf.data.Dataset.from_tensor_slices(images)
im_dataset = im_dataset.map(lambda image:tuple(tf.py_func(image_parser, [image], [tf.float32])), num_parallel_calls = 2)
im_dataset = im_dataset.prefetch(4)
iterator = im_dataset.make_initializable_iterator()
print(im_dataset.output_shapes)
It will give you (TensorShape(None),)
However, if you try this (using direct tensorflow mapping instead of py_func):
import tensorflow as tf
import numpy as np
def image_parser(image_name)
return image_name
images = [[1,2,3],[4,5,6]]
im_dataset = tf.data.Dataset.from_tensor_slices(images)
im_dataset = im_dataset.map(image_parser)
im_dataset = im_dataset.prefetch(4)
iterator = im_dataset.make_initializable_iterator()
print(im_dataset.output_shapes)
It will give you the exact tensor dimension (3,)
This is a general problem with tf.py_func which is intended since TensorFlow cannot infer the output shape itself, see for instance this answer.
You could set the shape yourself if you need to, by moving the tf.py_func inside the parse function:
def parser(x):
a = np.array([1.0,2.0,3.0])
y = tf.py_func(lambda: a, [], tf.float32)
y.set_shape((3,))
return y
dataset = tf.data.Dataset.range(10)
dataset = dataset.map(parser)
print(dataset.output_shapes) # will correctly print (3,)