2015-07-01 4 views
3

У меня есть две матрицы - A 3033x3033, а X - 3033x20. Я бегу следующие строки (как это было предложено в the answer to another question I asked):NumPy tensordot MemoryError

n, d = X.shape 
c = X.reshape(n, -1, d) - X.reshape(-1, n, d) 
return np.tensordot(A.reshape(n, n, -1) * c, c, axes=[(0,1),(0,1)]) 

На последней строке, Python просто останавливается и говорит «MemoryError». Как я могу обойти это, либо изменив некоторые настройки на Python, либо выполнив эту операцию более эффективным с точки зрения памяти?

+0

Какая '.shape' вы ожидаете результата? – farenorth

+0

Кроме того, вы указали формы A и X перед манипуляцией в коде? Что такое 'n',' d'? Вы должны упростить свой код, чтобы мы могли легче помочь вам (например, помочь мне помочь). Разделите свою последнюю строку на несколько, например: 'in1 ​​= A.reshape (n, n, -1) * c', затем выполните' np.tensordot (in1, c, axes = [(0,1), (0, 1)]) '. Я предполагаю, что ваша проблема возникает во второй части. Тогда вы можете просто указать размеры 'in1' и' c', а не заставлять меня выяснять, что происходит. – farenorth

ответ

2

Вот функция, которая делает вычисления без каких-либо для петель и без какого-либо большого временного массива. См. related question для более длительного ответа, в комплекте с тестовым скриптом.

def fbest(A, X): 
    "" 
    KA_best = np.tensordot(A.sum(1)[:,None] * X, X, axes=[(0,), (0,)]) 
    KA_best += np.tensordot(A.sum(0)[:,None] * X, X, axes=[(0,), (0,)]) 
    KA_best -= np.tensordot(np.dot(A, X), X, axes=[(0,), (0,)]) 
    KA_best -= np.tensordot(X, np.dot(A, X), axes=[(0,), (0,)]) 
    return KA_best 

Я профилированный код с массивами размера: enter image description here

Я люблю sp.einsum кстати. Это отличное место для запуска при ускорении операций массива путем удаления для циклов. Вы можете много сделать SOOOO с одним вызовом sp.einsum.

Преимущество np.tensordot заключается в том, что оно связано с любой быстрой библиотекой, установленной вами (то есть MKL). Таким образом, tensordot будет работать быстрее и параллельно, когда у вас будут установлены нужные библиотеки.

2

Если заменить последнюю строку с

return np.einsum('ij,ijk,ijl->kl',A,c,c) 

избежать создавая A.reshape(n, n, -1) * c (3301 по 3301 на 20) промежуточный продукт, который я думаю, что ваша главная проблема.

Мое впечатление, что версия, которую я даю, скорее всего медленнее (для случаев, когда она не исчерпывается памятью), но я ее не приуменьшил.

Возможно, вы могли пойти дальше и не создавать c, но я не могу сразу увидеть, как это сделать. Это будет случай следующего написания всего этого в терминах сумм матричных указаний и понимания того, что он упростил.

0

Вы можете использовать формат с двумя вложенными циклами, итерациями по последнему измерению X. Теперь это последнее измерение - 20, так что, надеюсь, он все равно будет достаточно эффективным и, что более важно, оставить минимальный объем памяти. Вот реализация -

n, d = X.shape 
c = X.reshape(n, -1, d) - X.reshape(-1, n, d) 
out = np.empty((d,d)) # d is a small number: 20 
for i in range(d): 
    for j in range(d): 
     out[i,j] = (A*c[:,:,i]*(c[:,:,j])).sum() 

return out 

Вы можете заменить последнюю строку с np.einsum -

out[i,j] = np.einsum('ij->',A*c[:,:,i]*c[:,:,j])  
Смежные вопросы