Как правильно обрабатывать многомерный массив NumPy - PullRequest
0 голосов
/ 14 января 2019

Я новичок в Python и немного борюсь с многомерными массивами в цикле for. Что у меня есть:

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]))

и я получаю что-то вроде:

[[[ 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

Я скопировал этот код из https://www.pyimagesearch.com/2017/08/21/deep-learning-with-opencv/, но похоже, что я что-то не так делаю, поскольку idx должен быть int, а вместо этого - массив

UPDATE:

Я пытался выяснить, что здесь происходит, но застрял в следующем: почему все вызовы argsort дают одинаковый результат? : О

>>> 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]]])

Плюс, почему данные изменяются, а не сортируются ли они?

1 Ответ

0 голосов
/ 14 января 2019

Ваш preds[0], присвоенный имени переменной, является трехмерным массивом:

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 применяется к массиву одинаковой формы:

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)

При этом исходном измерении размера 1 не имеет значения величина реверса или среза в этом измерении. Я подозреваю, что вы хотели повернуть вспять и нарезать последнее измерение, размер 7. НО, будь осторожен с этим. Argsort многомерного массива, даже если он применяется к одному измерению (последнее по умолчанию), трудно понять и использовать.

Форма соответствует массиву, но значения - диапазон 0-6, последнее измерение. numpy 1.15 добавил пару функций, чтобы упростить использование результата argsort (и некоторых других функций):

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.        ]]])

Обратите внимание, что строки теперь отсортированы, так же как и в np.sort(preds0, axis=-1).

Я мог бы выбрать одну «строку» массива индекса:

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 ])

Теперь у меня есть пять самых больших значений preds0[0,0,:] в обратном порядке.

И сделать это для всего preds0 массива:

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

или для более ранних версий:

preds0[[0], [[0],[1]], idxs[:,:,::-1][:,:,:5]]
...