#python #performance #scipy #sparse-matrix #galois-field
#python #Производительность #scipy #разреженная матрица #галуа-поле
Вопрос:
Мне нужно увеличить скорость моего алгоритма. Метод принимает две матрицы в качестве аргумента и выполняет точечное умножение. Единственная проблема заключается в том, что элементы должны быть умножены как октеты в GF (256), а затем добавлены как XOR. Поскольку я имею дело с очень большими разреженными матрицами, производительность ужасна.
def matrix_oct_mult(U, V, OCT_EXP, OCT_LOG):
temp_sum = 0
if shape(U)[1] == None and shape(V)[1] == None:
for i in range(len(U)):
temp_sum = oct_sum(temp_sum, oct_mult(U[i], V[i], OCT_EXP, OCT_LOG))
return temp_sum
assert shape(U)[1] == shape(V)[0], "Wrong size requirements for matrix dot multiplication"
temp_sum = 0
W = sp.lil_matrix((shape(U)[0], shape(V)[1]))
for i in range (shape(U)[0]):
for z in range(shape(V)[1]):
for j in range (shape(U)[1]):
temp_sum = oct_sum(temp_sum, oct_mult(U[i, j], V[j, z], OCT_EXP, OCT_LOG))
W[i, z] = temp_sum
temp_sum = 0
return W
Как вы можете видеть, я пробовал с классом lil, но производительность по-прежнему низкая.
Есть ли какие-либо эффективные способы решения этой проблемы?
Комментарии:
1. Python не является компилируемым языком, и вложенные циклы для операций с матрицами всегда будут исключительно медленными. Вам следует реструктурировать свою проблему для работы со стандартными матричными операциями или написать это на скомпилированном языке по вашему выбору.
2. Я не понимаю, где вы используете преимущество разреженности
U
илиV
или результатаW
. Для такой итерации было бы лучше использовать обычныйndarray
(или даже списки списков). Даже сlil
доступом к элементу разреженной матрицы происходит медленно.
Ответ №1:
Поскольку Python интерпретируется, вложенные for
циклы, как известно, имеют низкую производительность. Тогда как эквивалентные for
циклы в C были бы быстрыми. Таким образом, наилучшая производительность достигается при скомпилированном коде.
По этой причине я написал библиотеку Python под названием galois, которая расширяет массивы NumPy для работы с полями Галуа. Я написал код на Python, но JIT скомпилировал его с использованием Numba, поэтому арифметика поля Галуа работает так же быстро или почти так же быстро, как и арифметика собственного массива NumPy, см. Это Сравнение производительности .
Библиотека поддерживает линейную алгебру на матрицах полей Галуа с использованием стандартных двоичных операторов (
, @
, etc) и обычных функций линейной алгебры NumPy. Большинство этих подпрограмм также скомпилированы JIT для ускорения.
Я полагаю, что вы пытаетесь выполнить матричное умножение на две матрицы ( (M,N) x (N,K)
). Вот пример, в galois
котором это делается.
In [1]: import galois
# Create the GF(2^8) field using AES's irreducible polynomial -- your's may be different
In [2]: GF = galois.GF(2**8, irreducible_poly=0x11b)
In [3]: print(GF.properties)
GF(2^8):
characteristic: 2
degree: 8
order: 256
irreducible_poly: x^8 x^4 x^3 x 1
is_primitive_poly: False
primitive_element: x 1
In [4]: A = GF.Random((3,4)); A
Out[4]:
GF([[ 35, 130, 167, 111],
[ 58, 161, 194, 200],
[244, 65, 160, 8]], order=2^8)
In [5]: B = GF.Random((4,5)); B
Out[5]:
GF([[ 50, 59, 23, 34, 38],
[ 16, 59, 162, 80, 250],
[205, 145, 114, 9, 40],
[212, 250, 162, 210, 72]], order=2^8)
In [6]: A @ B
Out[6]:
GF([[144, 236, 142, 90, 89],
[ 83, 171, 34, 2, 117],
[192, 1, 20, 208, 127]], order=2^8)