Почему случайная запись элемента массива numpy намного медленнее, чем случайное чтение? - PullRequest
1 голос
/ 03 мая 2020

Следующий код является частью алгоритма бинаризации изображения. Я пытаюсь улучшить производительность этого алгоритма, но я нахожу узкое место в странном месте. (Нерелевантные части алгоритма опущены.)

@jit(nopython=True)
def make_buckets(img):
    height, width = img.shape

    buckets = np.zeros(256) 
    # buckets = np.full(256, 0) [I tried both, sometimes one works better than other]

    for h in range(height):
        for w in range(width):  
            g = img[h, w]
            a = buckets[g] + 1
            # buckets[g]  = 1
            # buckets[g]  = a

img = np.random.randint(0, 256, (224, 224))
%timeit make_buckets(img)

Время выполнения приведенного выше кода:

539 ns ± 12.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

, что хорошо. Это означает, что получение / доступ к buckets[g] внутри al oop совсем не требователен. Давайте посмотрим, что произойдет, если я раскомментирую эту строку: buckets[g] = 1

    for h in range(height):
        for w in range(width):  
            g = img[h, w]
            a = buckets[g] + 1
            buckets[g]  = 1
            # buckets[g]  = a

Время выполнения:

27.8 µs ± 865 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Это означает, что установка buckets[g] внутри al oop значительно увеличивает время выполнения.

Теперь, если я раскомментирую строку buckets[g] = a следующим образом:

    for h in range(height):
        for w in range(width):  
            g = img[h, w]
            a = buckets[g] + 1
            # buckets[g]  = 1
            buckets[g]  = a

Увеличение времени выполнения до:

37.8 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Это увеличение времени выполнения является последовательным, и в зависимости от матрицы img это может занять> 100 мкс. Это также означает, что установка элемента матрицы в переменную намного медленнее, чем установка его в константу. Может кто-нибудь объяснить, почему установка элемента матрицы в переменную al oop так сильно увеличивает время выполнения? Кроме того, можете ли вы предположить, что есть какой-то способ улучшить производительность, чем этот?

Я занимаюсь машинным обучением с миллионами изображений (рукописных документов), поэтому мой генератор данных должен быть достаточно быстрым, чтобы это не узкое место GPU. В конвейере генератора данных происходит множество манипуляций с изображениями, поэтому я хочу максимально оптимизировать каждую операцию. Эта бинаризация выполняется для каждого изображения, поэтому я хочу сократить время выполнения до нескольких микросекунд.

1 Ответ

0 голосов
/ 03 мая 2020

Я думаю, вы можете заменить свой код следующим:

def make_buckets(img):
    return np.bincount(img.reshape(-1), minlength=256)

Пожалуйста, попробуйте это и сообщите нам время.

Ссылка: https://numpy.org/doc/stable/reference/generated/numpy.bincount.html

...