Мне нужно выполнить умножение точечного произведения между двумя одномерными массивами, а затем взять сумму списка как:
import numpy as np
import numba
import time
import random
a = np.array([1, 2, 3, 4, 5, 6],dtype=int8) # Same first array
b = [np.array([random.randint(0,100) for y in range(6)],dtype=float) for x in range(1, 1000000)] # iterable of 2nd array
c = np.zeros(len(b)) # to store results
@numba.njit() # benefits of numba
def sum_of_mul(list1, list2):
return np.dot(list1, list2)
tstart = time.perf_counter()
for i in range(len(c)):
c[i] = sum_of_mul(a, b[i])
final_average = np.sum(c) / len(c)
print('time taken', round(time.perf_counter() - tstart, 1))
Меня интересует только скорость умножения массива, а не настройка. Точечный продукт занимает около 1,2 секунды на моем компьютере.
Учитывая, что мой первый массив такой же, и оба моих массива имеют размер 6 элементов, есть ли более быстрый способ сделать это?
Каким-то образом превратить это в многомерное матричное умножение? Панды? Или использовать какую-нибудь причудливую библиотеку? У меня есть графический процессор AMD.
Я пробовал многопроцессорную обработку, и это занимает в 16 раз больше времени (скорее всего, потому, что я выполняю относительно тривиальную операцию с небольшим массивом).
numba помогла ускорить это.
Обновлено: Согласно принятому в настоящее время ответу, это также было огромным ускорением
np.mean(np.dot(a, b.T))
и убедившись, что a и b (/все) являются массивами numpy
На уровне Python numpy они разные. np.dot включает шаг sum.
Я понимаю вашу точку зрения, и я отредактировал вопрос. Не было улучшения скорости с np.dot по сравнению с np.sum(np.multiply))






Базовый уровень
Ваш код в моей системе занимает 1,16 секунды для последней части (без инициализации, так же, как вы ее измерили):
time taken 1.2
CPU times: user 1.16 s, sys: 176 ms, total: 1.33 s
Wall time: 1.16 s
Часть инициализации занимает 5,5 сек.
Мы можем сократить его до 6 мс с помощью чистого Numpy и до 3 мс с CuPy (CUDA).
Улучшения
int и float, которые являются 64-битными типами Python.С np.float32 в качестве базового типа для всех ваших массивов время сокращается вдвое:
a = np.array([1, 2, 3, 4, 5, 6],dtype=np.float32) # Same first array
b = [np.array([random.randint(0,100) for y in range(6)],dtype=np.float32) for x in range(1, 1000000)] # iterable of 2nd array
time taken 0.8
CPU times: user 743 ms, sys: 62 µs, total: 743 ms
Wall time: 762 ms
numpy для типов данных и алгоритмов.Ваш исходный код смешивает списки Python и массивы numpy. На моем компьютере для инициализации требуется 5,5.
Вместо списка 1_000_000 np.arrays(6,) каждый вы можете иметь один np.array(1_000_000, 6). Вы можете переписать эту часть как:
a = np.array([1, 2, 3, 4, 5, 6],dtype=np.float32) # Same first array
b = np.random.uniform(0, 100, (1000000, 6)).astype(np.float32) # 2nd array
Это занимает всего 59 мс.
Обратите внимание, что np.random возвращает результаты с dtype=np.float64.
Расчет будет очень простым с чистым Numpy:
np.mean(np.dot(a, b.T))
Это занимает 6 мс.
CPU times: user 13.7 ms, sys: 8.03 ms, total: 21.7 ms
Wall time: 6.1 ms
1050.432
Вы можете использовать CuPy - Nupy на CUDA. Cupy великолепен, потому что его API почти идентичен Numpy:
%pip install cupy
import cupy as cp
# initialization
a = cp.array([1, 2, 3, 4, 5, 6],dtype=np.float32) # Same first array
b = cp.random.uniform(0,100, (1000000, 6)).astype(np.float32) # 2nd array
# calculation
cp.mean(cp.dot(a, b.T))
Это занимает 2,9 мс (у меня CUDA 11.3 на карте Tesla K80).
CPU times: user 1.22 ms, sys: 11.8 ms, total: 13.1 ms
Wall time: 2.94 ms
1050.432
CuPy совместим с несколькими версиями CUDA. Установка CUDA — это немного другая тема, я считаю, что документация CuPy хорошо справляется с задачей, направляя ее в нужные места. https://docs.cupy.dev/ru/stable/install.html
Сначала проверьте, действительно ли вам нужен GPU. Чистый Numpy при правильном использовании дает действительно приличные скорости.
какие-нибудь сроки с cupy? У меня AMD GPU, так что заставить его работать будет сложно.
Сделанный. Я также обновил свой ответ, так как apply_along_axis был ненужным. Сроки исполнения сейчас разумные. 6 мс с чистым Numpy и 2,9 мс с Cupy. Я считаю, что чем больше массивы, тем больше может ускориться GPU.
Это здорово, делать np.mean(np.dot(a, b.T)) и следить за тем, чтобы все они были np.arrays, пока что это самое быстрое
Разве это не просто
np.dot(b,a)?np.array(b)это (1000000,6) форма иa(6,)`