#python #numpy
#python #numpy
Вопрос:
Я столкнулся с некоторыми (загадочными?) проблема с производительностью при умножении матрицы-вектора NumPy.
Я написал следующий фрагмент, чтобы проверить скорость умножения матрицы на вектор:
import timeit
for i in range(90, 101):
tm = timeit.repeat('np.matmul(a, b)', number = 10000,
setup = 'import numpy as np; a, b = np.random.rand({0},{0}), np.random.rand({0})'.format(i))
print(i, sum(tm) / 5)
На некоторых машинах результат нормальный:
90 0.08936462279998522
91 0.08872119059979014
92 0.09083068459967762
93 0.09311594780047017
94 0.09907015420012613
95 0.10136517100036144
96 0.10339414420013782
97 0.10627872140012187
98 0.1102267580001353
99 0.11277738099979615
100 0.11471197419996315
На некоторых машинах умножение замедлилось до размера 96:
90 0.03618830284103751
91 0.03737151022069156
92 0.03295294055715203
93 0.02851409767754376
94 0.02677299762144685
95 0.028137388220056892
96 0.1916038074065
97 0.16719966367818415
98 0.18511182265356182
99 0.1806833743583411
100 0.17172936061397195
Некоторые даже замедлились в 1000 раз:
90 0.04183819475583732
91 0.029678784403949977
92 0.02486871089786291
93 0.02882006801664829
94 0.028613184532150625
95 0.02956576123833656
96 31.16711748293601
97 27.803299666382372
98 31.368976181373
99 27.71114011341706
100 26.219610543036833
Версия Python / NumPy одинакова на всех машинах, которые я тестировал (3.7.2 / 1.16.2). Операционная система также та же (Arch Linux).
Какова возможная причина этого? И почему это происходит при размере 96?
Комментарии:
1. Каковы процессоры машин?
2. @HemersonTacon Обычный: Intel Core i5-7200U; остальные: Intel Xeon E5-2620 v4 (разные машины с одинаковым процессором). Также тестируется E5-2620 с коэффициентом замедления около 4.
Ответ №1:
Я думаю, что я получил, наконец, правильный ответ и объяснение, почему:
- Эта проблема исправлена в версии Python 3.8.0a2 (текущая версия для предварительного тестирования)
- Проблема существует в Python версии 3.7.2 (последняя версия) для Windows и macOS.
Я написал немного более длинную программу для тестирования моих компьютеров Widows и macOS. Похоже, что NumPy в версии 3.7 начал запускать функцию matmul во всех четырех логических процессорах на моих компьютерах. Я не вижу этого в 3.8.02a:
$ python3.8 numpy_matmul.py $ python3.7 numpy_matmul.py
Python version : 3.8.0a2 Python version : 3.7.2
build:('v3.8.0a2:23f4589b4b', build:('v3.7.2:9a3ffc0492',
Feb 25 2019 10:59:08') 'Dec 24 2018 02:44:43')
compiler: compiler:
Clang 6.0 (clang-600.0.57) Clang 6.0 (clang-600.0.57)
Tested by Python code only : Tested by Python code only :
90 time = 0.1132 cpu = 0.1100 90 time = 0.1535 cpu = 0.1236
91 time = 0.1133 cpu = 0.1130 91 time = 0.1264 cpu = 0.1263
92 time = 0.1079 cpu = 0.1077 92 time = 0.1089 cpu = 0.1087
93 time = 0.1146 cpu = 0.1145 93 time = 0.1226 cpu = 0.1224
94 time = 0.1176 cpu = 0.1174 94 time = 0.1273 cpu = 0.1271
95 time = 0.1216 cpu = 0.1215 95 time = 0.1372 cpu = 0.1371
96 time = 0.1115 cpu = 0.1114 96 time = 0.2854 cpu = 0.8933
97 time = 0.1231 cpu = 0.1229 97 time = 0.2887 cpu = 0.9033
98 time = 0.1174 cpu = 0.1173 98 time = 0.2836 cpu = 0.8963
99 time = 0.1330 cpu = 0.1301 99 time = 0.3100 cpu = 0.9108
100 time = 0.1130 cpu = 0.1128 100 time = 0.3149 cpu = 0.9087
Tested with timeit.repeat : Tested with timeit.repeat :
90 time = 0.1060 cpu = 0.1066 90 time = 0.1238 cpu = 0.3264
91 time = 0.1091 cpu = 0.1097 91 time = 0.1233 cpu = 0.1240
92 time = 0.1021 cpu = 0.1027 92 time = 0.1138 cpu = 0.1128
93 time = 0.1149 cpu = 0.1156 93 time = 0.1324 cpu = 0.1327
94 time = 0.1135 cpu = 0.1139 94 time = 0.1319 cpu = 0.1326
95 time = 0.1170 cpu = 0.1177 95 time = 0.1325 cpu = 0.1331
96 time = 0.1069 cpu = 0.1076 96 time = 0.2879 cpu = 0.8886
97 time = 0.1192 cpu = 0.1198 97 time = 0.2867 cpu = 0.8986
98 time = 0.1151 cpu = 0.1155 98 time = 0.3034 cpu = 0.8854
99 time = 0.1200 cpu = 0.1207 99 time = 0.2867 cpu = 0.8966
100 time = 0.1146 cpu = 0.1153 100 time = 0.2901 cpu = 0.9018
Вот numpy_matmul.py:
import time
import timeit
import numpy as np
import platform
def correct_cpu(cpu_time):
pv1, pv2, _ = platform.python_version_tuple()
pcv = platform.python_compiler()
if pv1 == '3' and '5' <= pv2 <= '8' and pcv =='Clang 6.0 (clang-600.0.57)':
cpu_time /= 2.0
return cpu_time
def test(func, n, name):
print('nTested %s :' % name)
for i in range(90, 101):
t = time.perf_counter()
c = time.process_time()
tm = func(i, n)
t = time.perf_counter() - t
c = correct_cpu(time.process_time() - c)
st = t if tm <= 0.0 else tm
print('= time = %.4f cpu = %.4f' % (i, st, c))
if abs(t-st)/st > 0.02:
print(' time!= %.4f' % t)
def test1(i, n):
a, b = np.random.rand(i, i), np.random.rand(i)
for _ in range(n):
np.matmul(a, b)
return 0.0
def test2(i, n):
s = 'import numpy as np;'
'a, b = np.random.rand({0},{0}), np.random.rand({0})'
s = s.format(i)
r = 'np.matmul(a, b)'
t = timeit.repeat(stmt=r, setup=s, number=n)
return sum(t)
def test3(i, n):
s = 'import numpy as np;'
'a, b = np.random.rand({0},{0}), np.random.rand({0})'
s = s.format(i)
r = 'np.matmul(a, b)'
return timeit.timeit(stmt=r, setup=s, number=n)
print('Python version :', platform.python_version())
print(' build :', platform.python_build())
print(' compiler :', platform.python_compiler())
num = 10000
test(test1, 5 * num, 'by Python code only')
test(test2, num, 'with timeit.repeat')
test(test3, 5 * num, 'with timeit.timeit')
Комментарии:
1. Спасибо! Я отключил многопоточность NumPy и получил нормальные результаты. Поскольку NumPy в среде первого теста не скомпилирован с поддержкой многопоточности, он ведет себя нормально.
Ответ №2:
На 96 ваш тест достигает некоторой программной / аппаратной проблемы: 96*96*96 = 884 736. Приблизьтесь к 1 му и умножьте на 8 байт для числа с плавающей точкой: 7,077,888. Процессор Intel i5 имеет кэш L3 объемом 6 МБ. У моего iMac процессор такого типа, и у него проблема с замедлением при размере 96. Процессор Intel® Core ™ i5-7200U имеет 3 МБ кэш-памяти L3 и не имеет этой проблемы. Таким образом, это может быть программный алгоритм, некорректно работающий с размером кэша 6 МБ.
Комментарии:
1. Память, используемая массивом 96 * 96, должна быть 96*96*8 = 72 КБ, не 96*96*96*8 ? Более того, промахи в кэше вряд ли окажут такое значительное влияние.
2. Да, вы правы. Извините, я увидел 6 МБ и хотел сопоставить свои вычисления. Также имеется кэш L2 объемом 256 КБ. Моему NumPy два года. В GitHub они исправили три ошибки в конце 2018 github.com/numpy/numpy/commits /…