Самый быстрый способ создания массивов numy или случайным образом распределенных 0 и 1 - PullRequest
0 голосов
/ 13 декабря 2018

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

Я пробовал:

def gen_mask_1(size, p=0.75):
    return np.random.binomial(1, p, size)


def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

, где p - вероятность наличия 1

Скорость этих двух подходов сопоставима.

%timeit gen_mask_1(size=2048)
%timeit gen_mask_2(size=2048)

45.9 µs ± 575 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
47.4 µs ± 372 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Существуют ли более быстрые методы?

ОБНОВЛЕНИЕ

Следуя предложениямдо сих пор, я протестировал несколько дополнительных реализаций.Я не смог заставить @njit работать при установке parallel=True (TypingError: Failed in nopython mode pipeline (step: convert to parfors)), он работает без, но, думаю, менее эффективно.Я нашел привязку Python для Intel mlk_random (спасибо @MatthieuBrucher за подсказку!) Здесь: https://github.com/IntelPython/mkl_random Пока что использование mlk_random вместе с подходом @ nxpnsv дает лучший результат.

@njit
def gen_mask_3(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

def gen_mask_4(size, p=0.75):
    return (np.random.rand(size) < p).astype(int)

def gen_mask_5(size):
    return np.random.choice([0, 1, 1, 1], size=size)

def gen_mask_6(size, p=0.75):
    return (mkl_random.rand(size) < p).astype(int)

def gen_mask_7(size):
    return mkl_random.choice([0, 1, 1, 1], size=size)

%timeit gen_mask_4(size=2048)
%timeit gen_mask_5(size=2048)
%timeit gen_mask_6(size=2048)
%timeit gen_mask_7(size=2048)

22.2 µs ± 145 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
25.8 µs ± 336 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
7.64 µs ± 133 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
29.6 µs ± 1.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Другой вариант - numpy.random.choice, с вводом 0 с и 1 с, где пропорция 1 с равна p.Например, для p = 0,75 используйте np.random.choice([0, 1, 1, 1], size=n):

In [303]: np.random.choice([0, 1, 1, 1], size=16)
Out[303]: array([1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])

Это быстрее, чем np.random.binomial:

In [304]: %timeit np.random.choice([0, 1, 1, 1], size=10000)
71.8 µs ± 368 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [305]: %timeit np.random.binomial(1, 0.75, 10000)
174 µs ± 348 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Для обработки произвольного значения для p, вы можете использовать p параметр np.random.choice, но тогда код будет медленнее, чем np.random.binomial:

In [308]: np.random.choice([0, 1], p=[0.25, 0.75], size=16)
Out[308]: array([1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0])

In [309]: %timeit np.random.choice([0, 1], p=[0.25, 0.75], size=10000)
227 µs ± 781 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
0 голосов
/ 18 декабря 2018

Как я уже сказал в комментарии, вопрос реализации

def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

можно улучшить, используя это сравнение, получая bool, которое затем можно преобразовать в int.Это удаляет два сравнения с замаскированными заданиями, которые у вас есть, и делает довольно симпатичный вкладыш:)

def gen_mask_2(size, p=0.75):
    return = (np.random.rand(size) < p).astype(int)
0 голосов
/ 13 декабря 2018

Вы можете использовать компилятор Numba и ускорить процесс, применив декоратор njit к своим функциям.Ниже приведен пример для очень большого size

from numba import njit

def gen_mask_1(size, p=0.75):
    return np.random.binomial(1, p, size)

@njit(parallel=True)
def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

%timeit gen_mask_1(size=100000)
%timeit gen_mask_2(size=100000)

2.33 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
512 µs ± 25.1 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
...