shuffle a tensor along an axis
Opened this issue · 8 comments
I'm having trouble shuffling a tensor along a specified axis. I tried using a shuffled array of indices to do this, like so:
var indices: [Int] = Array(0...cardinality)
indices.shuffle()
return data[indices]
The problem is that S4TF does not like integer arrays being used as indices. I get the error argument type '[Int]' does not conform to expected type 'TensorRangeExpression'
I'm having trouble shuffling a tensor along a specified axis. I tried using a shuffled array of indices to do this, like so:
var indices: [Int] = Array(0...cardinality) indices.shuffle() return data[indices]The problem is that S4TF does not like integer arrays being used as indices. I get the error
argument type '[Int]' does not conform to expected type 'TensorRangeExpression'
There's actually a name for this shuffling operation: Tensor.transposed(permutation: [Int])
.
Edit: transposed(permutation:)
is actually different from shuffling! #394 (comment)
Here's how to use it:
import TensorFlow
let data = Tensor<Float>(randomNormal: [1, 2, 3, 4, 5])
var indices: [Int] = Array(data.indices) // better than `Array(0..<data.rank)`
indices.shuffle()
print(data.shape)
print(data.transposed(permutation: indices).shape)
// [1, 2, 3, 4, 5]
// [4, 1, 5, 3, 2]
Swift supports type extensions, so you can define Tensor.randomPermutation
for convenience:
import TensorFlow
extension Tensor {
var randomPermutation: Tensor {
var permutation = Array(shape.indices)
permutation.shuffle()
return transposed(permutation: permutation)
}
}
let data = Tensor<Float>(randomNormal: [1, 2, 3, 4, 5])
print(data.shape)
print(data.randomPermutation.shape)
// [1, 2, 3, 4, 5]
// [4, 1, 5, 3, 2]
Hope this helps!
Thanks for the help! I ran into 2 problems trying to implement this.
First, I'm not entirely sure where the indices
attribute is coming from. I'm using the latest toolchain (0.7
) and am getting error: value of type 'Tensor<Float>' has no member 'indices'
when I run your first example.
Also, it looks like this code would shuffle the order of each axis of a tensor. My goal is to shuffle along an axis. For example:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
shuffled along the 0th axis could be [[4, 5, 6], [1, 2, 3], [7, 8, 9]]
, and shuffled along the 1th axis could be [[2, 1, 3], [5, 4, 6], [8, 7, 9]]
. This is like what tf.random.shuffle does
First, I'm not entirely sure where the
indices
attribute is coming from. I'm using the latest toolchain (0.7
) and am gettingerror: value of type 'Tensor<Float>' has no member 'indices'
when I run your first example.
Sorry! This was a typo that I just fixed. In Tensor.randomPermutation
, Array(indices)
should be Array(shape.indices)
.
Also, it looks like this code would shuffle the order of each axis of a tensor. My goal is to shuffle along an axis. For example:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
shuffled along the 0th axis could be[[4, 5, 6], [1, 2, 3], [7, 8, 9]]
, and shuffled along the 1th axis could be[[2, 1, 3], [5, 4, 6], [8, 7, 9]]
. This is like what tf.random.shuffle does
Aha, yes. It sounds like you want a "shuffled" function that is different than randomPermutation
- sorry for misunderstanding your question (and turning it into an easier one). I think the implementation is a bit more involved, but I have faith you can figure it out!
Reopening, as the original question (a "shuffle" function like tf.random.shuffle) has not yet been answered.
An example with _Raw.randomShuffle
:
import TensorFlow
let x = Tensor<Int32>(shape: [5, 2], scalars: Array<Int32>(0 ..< 10))
let y = _Raw.randomShuffle(value: x, seed: 1, seed: 2)
print(y) // [[8, 9], [2, 3], [4, 5], [6, 7], [0, 1]]
Even with the seeds I couldn't make this deterministic which surprised me. So the output shows the shuffling but will be different for each run.
An example with _Raw.gatherV2
:
import TensorFlow
let x = Tensor<Int32>(shape: [5, 2], scalars: Array<Int32>(0 ..< 10))
let y = _Raw.gatherV2(params: x, indices: Tensor<Int32>([1, 0]), axis: Tensor<Int32>(1))
print(y) // [[1, 0], [3, 2], [5, 4], [7, 6], [9, 8]]
I will do it.
here's a quick function that does exactly the same as tf.random.shuffle()
but also takes an axis dimension
def tf_shuffle_axis(value, axis=0, seed=None, name=None):
perm = list(range(tf.rank(value)))
perm[axis], perm[0] = perm[0], perm[axis]
value = tf.random.shuffle(tf.transpose(value, perm=perm))
value = tf.transpose(value, perm=perm)
return value