-
Notifications
You must be signed in to change notification settings - Fork 74.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TensorFlow equivalent to numpy.repeat #8246
Comments
See
tf.while_loop .
|
Dear @shoyer , I am currently working on this with a new op in |
@a-lattas Great! Please replace |
What's the status of this update? |
since the thread is still open, I will paste my solution here def np_repeat(tensor, repeats):
"""
Args:
input: A Tensor. 1-D or higher.
repeats: A list. Number of repeat for each dimension, length must be the same as the number of dimensions in input
Returns:
A Tensor. Has the same type as input. Has the shape of tensor.shape * repeats
"""
assert len(repeats) == tensor.ndim, "dimension must match"
repeated = tensor
for axis, repeat in enumerate(repeats):
repeated = np.repeat(repeated, repeat, axis = axis)
return repeated
def tf_repeat(tensor, repeats):
"""
Args:
input: A Tensor. 1-D or higher.
repeats: A list. Number of repeat for each dimension, length must be the same as the number of dimensions in input
Returns:
A Tensor. Has the same type as input. Has the shape of tensor.shape * repeats
"""
with tf.variable_scope("repeat"):
expanded_tensor = tf.expand_dims(tensor, -1)
multiples = [1] + repeats
tiled_tensor = tf.tile(expanded_tensor, multiples = multiples)
repeated_tesnor = tf.reshape(tiled_tensor, tf.shape(tensor) * repeats)
return repeated_tesnor
def repeat_test():
shape = [1,3,3,3,2]
repeat = [1,2,2,3,1]
tensor = np.random.randn(*shape)
np_repeated_tensor = np_repeat(tensor, repeat)
tf_tensor = tf.constant(tensor)
g = tf.get_default_graph()
tf_new = tf_repeat(tf_tensor, repeat)
with tf.Session(graph=g) as sess:
tf_repeated_tensor = tf_new.eval()
# tf_repeated_tensor = np.array(tf_repeated_tensor)
if np.allclose(np_repeated_tensor, tf_repeated_tensor):
print("tf_repeat is the same as np_repeat")
else:
print("something wrong") |
👍 for what seems like a basic feature |
need one! |
Added a PR #15224 for the fix. |
@qianyizhang In numpy.repeat we can assign the number of repetitions for each element, e.g. |
This looks like it was fixed bu #15224. Please update the issue when new information becomes available, and we will reopen the issue. Thanks! |
#15224 was indeed a PR to add tf.repeat, but it was closed without merging. Reopening. |
@shoyer , any updates on this? |
I haven't been looking at this, but check the referenced PRs above. |
Unfortunately @qianyizhang's answer doesn't help with the following use of np.repeat:
Also has there been a merged PR? |
@sachinruk have you found a good solution for that use case? I would love to hear about it. In the meantime, if your scenario permits tf.py_func you can try my simple solution below.
|
At least for 1D tensors, a combination of tf.cumsum and tf.sparse_to_dense should do the trick:
This prints:
The trick is to use something like Generalizing to higher dim is made complicated by the fact that sparse_to_dense only accepts 1d sparse_values input... so probably using another function there is better. |
Just found this hidden implementation. It's not a part of the exported API, so you'll have to be a little dirty to acces it. from tensorflow.python.ops.ragged.ragged_util import repeat |
@yongtang Thanks for your work on this. I've been playing with this implementation (and the hidden version) for a while now, but just recently benchmarked performance and... well, it leaves a lot to be desired. For modestly sized arrays it can be significantly improved in terms of both speed and memory usage by def gather_repeat(values, repeats, axis=0):
indices = tf.repeat(tf.range(tf.shape(values)[axis]), repeats)
return tf.gather(values, indices, axis=axis) (note I haven't tested different axes/confirmed it covers all edge cases) For the very modestly sized arrays in the example below you can get a ~30% speed up and 75% memory reduction. Larger tensors result in converging computation time, but the memory factor remains roughly constant. From what I understand, Using pip-installed tf 1.15.0-dev20190821 , GTX-1070, python 3.6 from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
max_repeats = 100
nrows = 1000
ndims = 100
def gather_repeat(values, repeats, axis=0):
indices = tf.repeat(tf.range(tf.shape(values)[axis]), repeats)
return tf.gather(values, indices, axis=axis)
def get_args():
r = np.random.RandomState(123) # pylint: disable=no-member
repeats = (r.uniform(size=(nrows,),) * max_repeats).astype(np.int64)
values = r.uniform(size=(nrows, ndims)).astype(np.float32)
return tf.constant(values), tf.constant(repeats)
def benchmark_base():
with tf.Graph().as_default():
values, repeats = get_args()
op = tf.repeat(values, repeats, axis=0)
with tf.Session() as sess:
print('***********************')
print('base')
tf.test.Benchmark().run_op_benchmark(sess, op)
def benchmark_gather():
with tf.Graph().as_default():
values, repeats = get_args()
op = gather_repeat(values, repeats, axis=0)
with tf.Session() as sess:
print('***********************')
print('gather')
tf.test.Benchmark().run_op_benchmark(sess, op)
def ensure_same():
with tf.Graph().as_default():
values, repeats = get_args()
base = tf.repeat(values, repeats, axis=0)
gathered = gather_repeat(values, repeats, axis=0)
max_err = tf.reduce_max(tf.abs(gathered - base))
with tf.Session() as sess:
print('Max error: {}'.format(sess.run(max_err)))
if __name__ == '__main__':
benchmark_base()
benchmark_gather()
ensure_same() Output: ***********************
base
entry {
name: "TensorFlowBenchmark.run_op_benchmark"
iters: 10
wall_time: 0.002911686897277832
extras {
key: "allocator_maximum_num_bytes_GPU_0_bfc"
value {
double_value: 79595528.0
}
}
extras {
key: "allocator_maximum_num_bytes_gpu_host_bfc"
value {
double_value: 24.0
}
}
}
***********************
gather
entry {
name: "TensorFlowBenchmark.run_op_benchmark"
iters: 10
wall_time: 0.0021082162857055664
extras {
key: "allocator_maximum_num_bytes_GPU_0_bfc"
value {
double_value: 20176400.0
}
}
extras {
key: "allocator_maximum_num_bytes_gpu_host_bfc"
value {
double_value: 197768.0
}
}
}
Max error: 0.0 |
@jackd If you have the cycles to write up an optimized kernel solution for this (incl. a gradient function), I'll help make sure it gets accepted. (I'm the original author of the pure-python version, and a faster version would help speed up several RaggedTensor operations.) |
This is a popular question on StackOverflow:
http://stackoverflow.com/questions/35361467/tensorflow-numpy-repeat-alternative
But note that the answer so far only works for some use cases (the one presented in the question).
The best I could come up with for a general solution uses
tf.while_loop
, which is pretty verbose (and maybe slower than necessary). I'll add a link to the implementation I wrote fortf.contrib.training.resample_at_rate
after the next internal/github sync.The text was updated successfully, but these errors were encountered: