1

I'm a Python newbie and struggling a bit with multi dimensional arrays in a for loop. What I have is:

CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
    "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
    "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
    "sofa", "train", "tvmonitor"]
...
...
idxs = np.argsort(preds[0])[::-1][:5]
    print(idxs)
    #loop over top 5 predictions & display them
    for (i, idx) in enumerate(idxs):
        # draw the top prediction on the input image
        print (idx)
        if i == 0:
            print (preds)
            text = "Label: {}, {:.2f}%".format(CLASSES[idx], preds[0][idx] * 100)

            cv2.putText(frame, text, (5, 25),  cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 2)

        # display the predicted label + associated probability to the
        # console   
        print("[INFO] {}. label: {}, probability: {:.5}".format(i + 1,CLASSES[idx], preds[0][idx]))

and I get something like:

[[[ 0.          7.          0.3361728   0.2269333   0.6589312
    0.70067763  0.8960621 ]
  [ 0.         15.          0.44955394  0.5509065   0.4315516
    0.6530549   0.7223625 ]]]
[[[0 3 2 4 5 6 1]
  [0 4 2 3 5 6 1]]]
[[0 3 2 4 5 6 1]
 [0 4 2 3 5 6 1]]
[[[[ 0.          7.          0.3361728   0.2269333   0.6589312
     0.70067763  0.8960621 ]
   [ 0.         15.          0.44955394  0.5509065   0.4315516
     0.6530549   0.7223625 ]]]]
Traceback (most recent call last):
  File "real_time_object_detection.py", line 80, in <module>
    text = "Label: {}, {:.2f}%".format(CLASSES[idx], preds[0][idx] * 100)
TypeError: only integer scalar arrays can be converted to a scalar index

I've copied this code from https://www.pyimagesearch.com/2017/08/21/deep-learning-with-opencv/ but it looks like I'm doing something wrong as idx should be an int but instead is an array

UPDATE:

I tried to figure out what's going on here but I got stuck with the following: why do all argsort calls give the same result? :o

>>> preds[0] = [[[ 0.,          7.,          0.3361728,   0.2269333,   0.6589312,0.70067763,  0.8960621 ],[ 0.,         15.,          0.44955394,  0.5509065,   0.4315516,0.6530549,   0.7223625 ]]]
>>> print(preds[0])
[[[0.0, 7.0, 0.3361728, 0.2269333, 0.6589312, 0.70067763, 0.8960621], [0.0, 15.0, 0.44955394, 0.5509065, 0.4315516, 0.6530549, 0.7223625]]]
>>> import numpy as np
>>> np.argsort(preds[0])
array([[[0, 3, 2, 4, 5, 6, 1],
        [0, 4, 2, 3, 5, 6, 1]]])
>>> np.argsort(preds[0])[::-1]
array([[[0, 3, 2, 4, 5, 6, 1],
        [0, 4, 2, 3, 5, 6, 1]]])
>>> np.argsort(preds[0])[::-1][:5]
array([[[0, 3, 2, 4, 5, 6, 1],
        [0, 4, 2, 3, 5, 6, 1]]])

Plus why does it seem to alter the data, should it not just sort it?

3
  • 1
    What's the shape of preds? Or more relevantly preds[0]? (1,2,7)? Make sure you shape matches the expectations of the code you are copying. I suspect it has too many dimension. argsort on a 3d array without axis specified looks suspicious. Commented Jan 14, 2019 at 4:18
  • @hpaulj argsort should work fine without axis defined: "Axis along which to sort. The default is -1 (the last axis). If None, the flattened array is used." I've added a print of preds[0] above, I'm not sure how to address this Commented Jan 14, 2019 at 5:00
  • 1
    Sorry, I missed the default of -1. Thought it was flattening. Commented Jan 14, 2019 at 5:04

1 Answer 1

1

Your preds[0], assigned to a variable name is a 3d array:

In [449]: preds0 = np.array([[[ 0.,          7.,          0.3361728,   0.2269333
     ...: ,   0.6589312,0.70067763,  0.8960621 ],[ 0.,         15.,          0.4
     ...: 4955394,  0.5509065,   0.4315516,0.6530549,   0.7223625 ]]])
In [450]: preds0.shape
Out[450]: (1, 2, 7)

argsort applied to that is an array of the same shape:

In [451]: np.argsort(preds0)
Out[451]: 
array([[[0, 3, 2, 4, 5, 6, 1],
        [0, 4, 2, 3, 5, 6, 1]]])
In [452]: _.shape
Out[452]: (1, 2, 7)

With that size 1 initial dimension, not amount of reversing or slicing on that dimension makes a difference. I suspect you wanted to reverse and slice the last dimension, the size 7 one. BUT, be careful about that. The argsort of a multidimensional array, even when applied to one dimension (the default last), is a hard thing to understand, and to use.

The shape matches the array, but the values are the range of 0-6, the last dimension. numpy 1.15 added a couple of functions to make it easier to use the result of argsort (and some other functions):

In [455]: np.take_along_axis(preds0, Out[451], axis=-1)
Out[455]: 
array([[[ 0.        ,  0.2269333 ,  0.3361728 ,  0.6589312 ,
          0.70067763,  0.8960621 ,  7.        ],
        [ 0.        ,  0.4315516 ,  0.44955394,  0.5509065 ,
          0.6530549 ,  0.7223625 , 15.        ]]])

Notice that rows are now sorted, same as produced by np.sort(preds0, axis=-1).

I could pick one 'row' of the index array:

In [459]: idxs = Out[451]
In [461]: idx = idxs[0,0]
In [462]: idx
Out[462]: array([0, 3, 2, 4, 5, 6, 1])
In [463]: idx[::-1]               # reverse
Out[463]: array([1, 6, 5, 4, 2, 3, 0])
In [464]: idx[::-1][:5]           # select
Out[464]: array([1, 6, 5, 4, 2])
In [465]: preds0[0,0,Out[464]]
Out[465]: array([7.        , 0.8960621 , 0.70067763, 0.6589312 , 0.3361728 ])

Now I have the five largest values of preds0[0,0,:] in reverse order.

And to do it to the whole preds0 array:

np.take_along_axis(preds0, idxs[:,:,::-1][:,:,:5], axis=-1)

or for earlier versions:

preds0[[0], [[0],[1]], idxs[:,:,::-1][:,:,:5]]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.