Functions such as matrix multiplication perform column x row operations and then do a reduction operation. I want to do something similar, but I would like to replace the multiplication and addition operators with something else, such as max and min. I have something that works but it seems "ugly" at best.
# Setup
a = tf.reshape(tf.range(0.0, 8.0), [4, 2])
b = tf.reshape(tf.range(4.0, 12.0), [2, 4])
# Baseline
tf.matmul(a, b)
<tf.Tensor: shape=(4, 4), dtype=float32, numpy=
array([[ 8., 9., 10., 11.],
[ 32., 37., 42., 47.],
[ 56., 65., 74., 83.],
[ 80., 93., 106., 119.]], dtype=float32)>
# Can this part be done better?
a_b = tf.reshape(a, [4, 1, 2])
b_b = tf.reshape(tf.transpose(b), [1, 4, 2])
# The result is at least correct
tf.reduce_sum(a_b * b_b, -1)
<tf.Tensor: shape=(4, 4), dtype=float32, numpy=
array([[ 8., 9., 10., 11.],
[ 32., 37., 42., 47.],
[ 56., 65., 74., 83.],
[ 80., 93., 106., 119.]], dtype=float32)>
# And it can be extended to be generic
tf.reduce_min(tf.maximum(a_b, b_b), -1)
<tf.Tensor: shape=(4, 4), dtype=float32, numpy=
array([[4., 5., 6., 7.],
[4., 5., 6., 7.],
[4., 5., 6., 7.],
[6., 6., 6., 7.]], dtype=float32)>
As shown above, I have a workable solution, but I would expect a framework like tensorflow to have a more generic method to do this or at least a way to produce the intermediate tensor. The tf.meshgrid function seems to "almost" do what I want but the arguments are limited to rank 1 tensors.
Additionally, the above solution does not scale well. Some profiling indicates that the intermediate tensors are materialized, even in graph mode.
Related
I have two matrices. Matrix A is contains some values and matrix B contains indices. The shape of matrix A and B is (batch, values) and (batch, indices), respectively.
My goal is to select values from matrix A based on indices of matrix B along the batch dimension.
For example:
# Matrix A
<tf.Tensor: shape=(2, 5), dtype=float32, numpy=
array([[0., 1., 2., 3., 4.],
[5., 6., 7., 8., 9.]], dtype=float32)>
# Matrix B
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[0, 1],
[1, 2]], dtype=int32)>
# Expected Result
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[0., 1.],
[6., 7.]], dtype=int32)>
How can I achieve this in Tensorflow?
Many thanks in advance!
You can achieve this with the tf.gather function.
mat_a = tf.constant([[0., 1., 2., 3., 4.],
[5., 6., 7., 8., 9.]])
mat_b = tf.constant([[0, 1], [1, 2]])
out = tf.gather(mat_a, mat_b, batch_dims=1)
out.numpy()
array([[0., 1.],
[6., 7.]], dtype=float32)
I am using a simple convolutional network, however, I need to use very specific paddings: I want to copy the nearest pixel value, something like this:
1 2 3
4 5 6
7 8 9
to
1 1 2 3 3
1 1 2 3 3
4 4 5 6 6
7 7 8 9 9
7 7 8 9 9
While I have no problem calculating the pad itself, I cannot use it in convolution. Is there a way to put these values into a tensorflow pad? Or I can modify the image, so it will contain the pad, but how can I set the convolution to handle the first and last rows and columns as padding?
You can simnply call tf.pad with symmetric mode before your call to conv2d, while specifying that the convolution should use the VALID padding mode:
>>> a = tf.reshape(tf.range(9),(3,3))
>>> a
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]], dtype=float32)>
>>> padded_a = tf.pad(a,[[1,1],[1,1]],"SYMMETRIC")
>>> padded_a
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[0., 0., 1., 2., 2.],
[0., 0., 1., 2., 2.],
[3., 3., 4., 5., 5.],
[6., 6., 7., 8., 8.],
[6., 6., 7., 8., 8.]], dtype=float32)>
Now, if we create a simple 3x3 filter made of 1, we should have as result of the convolution the sum of the neighbouring elements (pad included), with the same shape as our original input:
>>> filters = tf.ones((3,3,1,1))
>>> conv_result = tf.nn.conv2d(padded_a[tf.newaxis,:,:,tf.newaxis], filters, padding="VALID", strides=1)
>>> tf.squeeze(conv_result) # just removing the batch and channel dimensions
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[12., 18., 24.],
[30., 36., 42.],
[48., 54., 60.]], dtype=float32)>
I run the following code in tensorflow 2.2
a = tf.constant([2.0, 3.0, 4.0])
b = tf.Variable([4.0, 3.0, 5.0])
c = a * b
Value of b is:
<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([4., 3., 5.], dtype=float32)>
Value of c is:
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([ 8., 9., 20.], dtype=float32)>
if I update the variable b now
b.assign( [ 1.0, 1.0 , 1.0] )
# b is now <tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([1., 1., 1.], dtype=float32)>
But when i print the value of c, which i expect it should have changed since b has changed, but c does not change
# c is still <tf.Tensor: shape=(3,), dtype=float32, numpy=array([ 8., 9., 20.], dtype=float32)>
My test is running in eager mode. tf.executing_eagerly() = True now
What is the reason behind?
c has been attributed by the former b, if you want to change c, it needs to re-execute c=a*b
I'm trying to feed 1D numpy arrays (flattend images) via a generator into a H5py data file in order to create training and validation matrices.
The following code was adapted from a solution (can't find it now) in which the data attribute of H5py's File objects's create_dataset function is provided data in the form of a call to np.fromiter which has a generator function as one of its arguments.
from scipy.misc import imread
import h5py
import numpy as np
import os
# Creating h5 data file
f = h5py.File('../data.h5', 'w')
# Source directory for image data
src = '/datasets/aic540/train/images/'
# Showing quantity and dimensionality of data
images = os.listdir(src)
ex_img = imread(src + images[0])
flat_img = ex_img.flatten()
print "# of images is {}".format(len(images))
print "image shape is {}".format(ex_img.shape)
print "flattened image shape is {}".format(flat_img.shape)
# Creating generator to feed in data to h5py's `create_dataset` function
gen = (imread(src + i).flatten().astype(np.int8) for i in os.listdir(src))
# Creating h5 dataset
f.create_dataset(name='training',
#shape=(59482, 1555200),
data=np.fromiter(gen, dtype=np.int8))
Output:
# of images is 59482
image shape is (540, 960, 3)
flattened image shape is (1555200,)
Traceback (most recent call last):
File "process_images.py", line 30, in <module>
data=np.fromiter(gen, dtype=np.int8))
ValueError: setting an array element with a sequence.
I've read when searching for this error in this context that the problem is that np.fromiter() needs a list and not a generator function (which seems opposed to the function that the name "fromiter" implies) -- wrapping the generator in a list call list(gen) allows the code to run but it, of course, uses up all the memory in the expansion of this list before the call to create_dataset is made.
How do I use a generator to feed data into an H5py data file?
If my approach is entirely wrong, what is the correct way to build a very large numpy matrix that doesn't fit in memory -- using H5py or otherwise?
The with a sequence error comes from what you are trying to feed fromiter, not the generator part.
In py3, range is generator like:
In [15]: np.fromiter(range(3),dtype=int)
Out[15]: array([0, 1, 2])
In [16]: np.fromiter((2*x for x in range(3)),dtype=int)
Out[16]: array([0, 2, 4])
But if I start with a 2d array (which imread produces, right?), and create a generator expression as you do:
In [17]: gen = (np.ones((2,3)).flatten().astype(np.int8) for i in range(3))
In [18]: list(gen)
Out[18]:
[array([1, 1, 1, 1, 1, 1], dtype=int8),
array([1, 1, 1, 1, 1, 1], dtype=int8),
array([1, 1, 1, 1, 1, 1], dtype=int8)]
I generate a list of arrays.
In [19]: gen = (np.ones((2,3)).flatten().astype(np.int8) for i in range(3))
In [21]: np.fromiter(gen, np.int8)
...
ValueError: setting an array element with a sequence.
np.fromiter creates a 1d array from an iterator that provides 'numbers' one at a time, not something that dishes out lists or arrays.
In any case, npfromiter creates a full array; not some sort of generator. There's nothing like an array 'generator'.
Even without chunking you can write data to the file by 'row' or other slice.
In [28]: f = h5py.File('test.h5', 'w')
In [29]: data = f.create_dataset(name='test',shape=(100,10))
In [30]: for i in range(100):
...: data[i,:] = np.arange(i,i+10)
...:
In [31]: data
Out[31]: <HDF5 dataset "test": shape (100, 10), type "<f4">
The equivalent in your case is to load an image, reshape it, and write it immediately to the h5py dataset. No need to collect all the images in an array or list.
read 10 rows:
In [33]: data[:10,:]
Out[33]:
array([[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.],
[ 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.],
[ 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.],
[ 4., 5., 6., 7., 8., 9., 10., 11., 12., 13.],
[ 5., 6., 7., 8., 9., 10., 11., 12., 13., 14.],
[ 6., 7., 8., 9., 10., 11., 12., 13., 14., 15.],
[ 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.],
[ 8., 9., 10., 11., 12., 13., 14., 15., 16., 17.],
[ 9., 10., 11., 12., 13., 14., 15., 16., 17., 18.]], dtype=float32)
Enabling chunking might help with really large datasets, but I don't experience in that area.
There is a minimal example of an RNN in the Skflow documentation. The input data is a matrix with shape (4,5). Why is the data split according to the following function for input?:
def input_fn(X):
return tf.split(1, 5, X)
This function returns a list of 5 arrays with shape 4,1
[array([[ 2.],
[ 2.],
[ 3.],
[ 2.]], dtype=float32), array([[ 1.],
[ 2.],
[ 3.],
[ 4.]], dtype=float32), array([[ 2.],
[ 3.],
[ 1.],
[ 5.]], dtype=float32), array([[ 2.],
[ 4.],
[ 2.],
[ 4.]], dtype=float32), array([[ 3.],
[ 5.],
[ 1.],
[ 1.]], dtype=f
and, what is the difference/impact on the RNN between the above function, or defining the function like this? As both input functions run
def input_fn(X):
return tf.split(1, 1, X)
Which returns the following:
[[[ 1., 3., 3., 2., 1.],
[ 2., 3., 4., 5., 6.]]
Presented here:
testRNN(self):
random.seed(42)
import numpy as np
data = np.array(list([[2, 1, 2, 2, 3],
[2, 2, 3, 4, 5],
[3, 3, 1, 2, 1],
[2, 4, 5, 4, 1]]), dtype=np.float32)
# labels for classification
labels = np.array(list([1, 0, 1, 0]), dtype=np.float32)
# targets for regression
targets = np.array(list([10, 16, 10, 16]), dtype=np.float32)
test_data = np.array(list([[1, 3, 3, 2, 1], [2, 3, 4, 5, 6]]))
def input_fn(X):
return tf.split(1, 5, X)
# Classification
classifier = skflow.TensorFlowRNNClassifier(
rnn_size=2, cell_type='lstm', n_classes=2, input_op_fn=input_fn)
classifier.fit(data, labels)
classifier.weights_
classifier.bias_
predictions = classifier.predict(test_data)
self.assertAllClose(predictions, np.array([1, 0]))