Compare two dimensions of the same tesnor

Hi All,

PyTorch newbie here. I have a tensor “AAA” with 5 dimensions and the length of each dimension is 1, 2, Z, Y, X.

To make the question easy, let’s say we divide AAA into two tensors by the second dimension so the sizes of resulting tensors A, B would look like A = [Z, Y, X] and B = [Z, Y, X]

I want to check if each element is in B > A (elementwise) and if each element is in B > a_threashold (a scalar value).

If both of those conditions are true, I want this value from B and its index. Now, if we can do this in the original tensor AAA without creating two-child tensors A and B is probably more efficient I guess.

I can easily do this by running three nested for loops and comparing each element like

for z in range(AAA.size(dim=2)):
 for y in range(AAA.size(dim=3)):
  for x in range(AAA.size(dim=4)):
   if AAA[0, 0, z, y, x] < AAA[0, 1, z, y, x] and AAA[0, 1, z, y, x]  > a_threashold:
     print(str(AAA[0, 1, z, y, x]) + "index" + str(z) + "\t" + str(y) + "\t" + str(z))

but this is unbelievably slow (I have like 500 million floating-point numbers in AAA).

I was thinking of using python multiprocessing but there might be a better PyTorch way?
Thank you so much!!!

>>> a = torch.ones(3,3)
>>> a[1,1] = 0
>>> a
tensor([[1., 1., 1.],
        [1., 0., 1.],
        [1., 1., 1.]])
>>> b = torch.zeros(3,3)
>>> b
tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])
>>> (a>b).any()
tensor(True)
>>> (a>b).all()
tensor(False)

1 Like

Thank you for your answer, maybe I was not clear. Let me try again

  1. Both A and B are in the same tensor
  2. When I compare, I want the actual values and their indices as well. Please be kind enough to check my 5 lines of code above. Thank you :slight_smile:

What I meant is that you don’t need loops to iterate over each dimension. This is very slow indeed and numpy and pytorch have bunch of tricks to evade loops completely, like broadcasting and vectorized operations.

>>> a = torch.ones(3,3)
>>> a[1,1] = 0
>>> a
tensor([[1., 1., 1.],
        [1., 0., 1.],
        [1., 1., 1.]])
>>> b = torch.zeros(3,3)
>>> b
tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

now let’s compare a and b directly:

>>> a>b
tensor([[ True,  True,  True],
        [ True, False,  True],
        [ True,  True,  True]])

or

>>> torch.where(a>b, a, b)
tensor([[1., 1., 1.],
        [1., 0., 1.],
        [1., 1., 1.]])

to get indices of where condition is True, we can use nonzero()

>>> (a>b).nonzero()
tensor([[0, 0],
        [0, 1],
        [0, 2],
        [1, 0],
        [1, 2],
        [2, 0],
        [2, 1],
        [2, 2]])
1 Like

Thank you so much. You are right, looping took me 55 minutes (maybe because the tensor was in the GPU) when I used your method, it took me 9 seconds. I am blown away. Sorry for maybe a silly question :). Your answer is very helpful. I have last two little questions that I am missing.

  1. I want to compare b>a and also b > threshold (a floating-point number). As I said earlier, a and b are both in the same tensor in different channels in the second dimension.

So I tried the following and It throws an error. I am stuck here.

x = AAA[0,0,:,:,:] < AAA[0,1,:,:,:] and AAA[0,1,:,:,:].ge(threshold)

print(x.nonzero())
			
  1. I am wondering whether the following line from the code above is safe
x = AAA[0,0,:,:,:] < AAA[0,1,:,:,:]

Or I should just slice the tensor first before comparison like

a = AAA[0,0,:,:,:] 

b = AAA[0,1,:,:,:]

x = a < b

Thank you so much for the whole wonderful PyTorch community :slight_smile:

Reason for the 1st issue is that you are trying to ‘and’ two multidimensional tensors, but this operation only supported with single boolean values. You can try to use something like torch.logical_and

Slices are just views of original tensor, so I don’t see any harm done

1 Like

This should work:

idxs1 = AAA[0, 1] > AAA[0, 0] 

idxs will be an index mask containg True and False, where True means that the condition for AAA[0, 1] > AAA[0, 0] holds. So you would access those values by AAA[idxs]

the same should work for the other condition:

idxs2 = AAA[0, 1] > threshold 

To get the indexes where it holds for both you would do

idxs3 = idxs1 & idxs2

or

idxs3 = torch.logical_and(idxs1, idxs2)
1 Like

When using Logical Operators in Python, you must define the order of operations through parentheses when there is more than one operation involved. If you’re getting an error, it is probably because Python can’t figure out the order in which you want the operations performed. Additionally, depending on what you are trying to accomplish, you may need two logical operators in your statement.

For instance, try:

x=(A[0,0,:,:,:] > A[0,1,:,:,:]) & (A[0,0,:,:,:] > A[0,1,:,:,:].ge(0.5))
1 Like