Улучшение производительности при столбчатом вычислении numpy ndarray (сокращение строк) ⇐ Python
Улучшение производительности при столбчатом вычислении numpy ndarray (сокращение строк)
Я выполняю сокращение строк в трехмерном ndarray (KxMxN), т. е. беру все значения столбца и использую функцию уменьшения для получения скалярного значения; в конечном итоге матрица KxMxN станет двумерным массивом ndarray порядка KxN. Подробности реализации я объясню по ходу дела.
Трехмерный ndarray состоит из чисел с плавающей запятой.
В следующем примере njit с numpy — лучшее, что я мог получить на данный момент. Мне интересно, есть ли возможности для дальнейшего улучшения с любой точки зрения.
Распараллеливание
cupy(распараллеливание графического процессора), dask (распараллеливание процессора) или numba не смогло превзойти следующее (мой вариант использования, по-видимому, является способом слишком незначительно, чтобы использовать мощность графического процессора, а у меня есть только графический процессор 8G). Есть большая вероятность, что эти инструменты можно использовать гораздо более продвинутым способом, о котором я не знал.
из numba import njit, guvectorize, float64, int64 из математического импорта sqrt импортировать число как NB импортировать numpy как np импортировать itertools # Создаём 2D ndarray m = np.random.rand(800,100) # Преобразуем его в список подматриц г-н = m.reshape(16,50,100) # Создайте матрицу индексов из комбинаторики # типичный для меня "выбрать 8 из 16", 12870 комбинаций # У меня есть собственный генератор комбинаций, но я не хотел его оптимизировать, и itertools действительно уже проделал достойную работу. x = np.array(list(itertools.combinations(np.arange(16),8)) ) # Теперь мы выберем 8 подматриц из mr и изменим их форму, чтобы они стали одной большей подматрицей; мы делаем это в понимании списка. # Это матрица, которую мы собираемся уменьшить. # Узкое место 1: Эта линия занимает больше всего времени, и я надеюсь улучшить ее, но я не уверен, что мы можем здесь что-то сделать. m3d = np.array([mr[idx_arr].reshape(400,100) для idx_arr в x]) # Мы создаем разные версии одной и той же функции сокращения. # Узкое место 2: Функция уменьшения — это еще одно место, которое мне хотелось бы улучшить. # col - значения столбца # дней - торговые дни в году #rf - безрисковая ставка # версия njit с функцией экземпляра `mean`, `std` и python `sqrt` @njit def nb_sr(col,days,rf): среднее значение = (col.mean() * дни) - RF std = col.std() * sqrt(дни) Возвращаемое среднее / стандартное # версия njit с numpy @njit def nb_sr_np (столбец, дни, РФ): среднее значение = (np.mean(col) * дни) -rf std = np.std(столбец) * np.sqrt(дни) Возвращаемое среднее / стандартное # гювекторизация с помощью numpy @guvectorize([(float64[:],int64,float64,float64[:])], '(n),(),()->()', nopython=True) def gu_sr_np(col,days,rf,res): среднее значение = (np.mean(col) * дни) - RF std = np.std(столбец) * np.sqrt(дни) res[0] = среднее / стандартное # Мы обертываем их так, чтобы их можно было применять к двумерной матрице с поддержкой списков. # Узкое место 3: Я подумывал о векторизации этой оболочки, но самое близкое, что мне удалось сделать, это понимание списка, что на самом деле не является векторизацией. защита nb_sr_wrapper(m2d): return [nb_sr(r, 252, .25) для r в m2d.T] защита nb_sr_np_wrapper(m2d): вернуть [nb_sr_np(r, 252, .25) для r в m2d.T] защита gu_sr_np_wrapper(m2d): вернуть [gu_sr_np(r, 252, .25) для r в m2d.T] # Окончательно! вот наш этап сравнительного анализа производительности. %timeit np.array([nb_sr_wrapper(m) для m в m3d.T]) # выход: 4,26 с ± 3,67 мс на цикл (среднее ± стандартное отклонение для 7 запусков, по 1 циклу в каждом) %timeit np.array([nb_sr_np_wrapper(m) для m в m3d.T]) 4,33 с ± 26,1 мс на цикл (среднее ± стандартное отклонение для 7 циклов, по 1 циклу в каждом) %timeit np.array([gu_sr_np_wrapper(m) для m в m3d.T]) 6,06 с ± 11,7 мс на цикл (среднее ± стандартное отклонение для 7 циклов, по 1 циклу в каждом)
Я выполняю сокращение строк в трехмерном ndarray (KxMxN), т. е. беру все значения столбца и использую функцию уменьшения для получения скалярного значения; в конечном итоге матрица KxMxN станет двумерным массивом ndarray порядка KxN. Подробности реализации я объясню по ходу дела.
Трехмерный ndarray состоит из чисел с плавающей запятой.
В следующем примере njit с numpy — лучшее, что я мог получить на данный момент. Мне интересно, есть ли возможности для дальнейшего улучшения с любой точки зрения.
Распараллеливание
cupy(распараллеливание графического процессора), dask (распараллеливание процессора) или numba не смогло превзойти следующее (мой вариант использования, по-видимому, является способом слишком незначительно, чтобы использовать мощность графического процессора, а у меня есть только графический процессор 8G). Есть большая вероятность, что эти инструменты можно использовать гораздо более продвинутым способом, о котором я не знал.
из numba import njit, guvectorize, float64, int64 из математического импорта sqrt импортировать число как NB импортировать numpy как np импортировать itertools # Создаём 2D ndarray m = np.random.rand(800,100) # Преобразуем его в список подматриц г-н = m.reshape(16,50,100) # Создайте матрицу индексов из комбинаторики # типичный для меня "выбрать 8 из 16", 12870 комбинаций # У меня есть собственный генератор комбинаций, но я не хотел его оптимизировать, и itertools действительно уже проделал достойную работу. x = np.array(list(itertools.combinations(np.arange(16),8)) ) # Теперь мы выберем 8 подматриц из mr и изменим их форму, чтобы они стали одной большей подматрицей; мы делаем это в понимании списка. # Это матрица, которую мы собираемся уменьшить. # Узкое место 1: Эта линия занимает больше всего времени, и я надеюсь улучшить ее, но я не уверен, что мы можем здесь что-то сделать. m3d = np.array([mr[idx_arr].reshape(400,100) для idx_arr в x]) # Мы создаем разные версии одной и той же функции сокращения. # Узкое место 2: Функция уменьшения — это еще одно место, которое мне хотелось бы улучшить. # col - значения столбца # дней - торговые дни в году #rf - безрисковая ставка # версия njit с функцией экземпляра `mean`, `std` и python `sqrt` @njit def nb_sr(col,days,rf): среднее значение = (col.mean() * дни) - RF std = col.std() * sqrt(дни) Возвращаемое среднее / стандартное # версия njit с numpy @njit def nb_sr_np (столбец, дни, РФ): среднее значение = (np.mean(col) * дни) -rf std = np.std(столбец) * np.sqrt(дни) Возвращаемое среднее / стандартное # гювекторизация с помощью numpy @guvectorize([(float64[:],int64,float64,float64[:])], '(n),(),()->()', nopython=True) def gu_sr_np(col,days,rf,res): среднее значение = (np.mean(col) * дни) - RF std = np.std(столбец) * np.sqrt(дни) res[0] = среднее / стандартное # Мы обертываем их так, чтобы их можно было применять к двумерной матрице с поддержкой списков. # Узкое место 3: Я подумывал о векторизации этой оболочки, но самое близкое, что мне удалось сделать, это понимание списка, что на самом деле не является векторизацией. защита nb_sr_wrapper(m2d): return [nb_sr(r, 252, .25) для r в m2d.T] защита nb_sr_np_wrapper(m2d): вернуть [nb_sr_np(r, 252, .25) для r в m2d.T] защита gu_sr_np_wrapper(m2d): вернуть [gu_sr_np(r, 252, .25) для r в m2d.T] # Окончательно! вот наш этап сравнительного анализа производительности. %timeit np.array([nb_sr_wrapper(m) для m в m3d.T]) # выход: 4,26 с ± 3,67 мс на цикл (среднее ± стандартное отклонение для 7 запусков, по 1 циклу в каждом) %timeit np.array([nb_sr_np_wrapper(m) для m в m3d.T]) 4,33 с ± 26,1 мс на цикл (среднее ± стандартное отклонение для 7 циклов, по 1 циклу в каждом) %timeit np.array([gu_sr_np_wrapper(m) для m в m3d.T]) 6,06 с ± 11,7 мс на цикл (среднее ± стандартное отклонение для 7 циклов, по 1 циклу в каждом)
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение