Я пытаюсь оптимизировать фрагмент кода, который решает большую разреженную нелинейную систему, используя метод внутренней точки. На этапе обновления это включает в себя вычисление матрицы Гессе H
, градиента g
, а затем решение d
в H * d = -g
для получения нового направления поиска.
Матрица Гессе имеет симметричную трехдиагональную структуру вида:
A.T * diag(b) * A + C
Я запустил line_profiler
для конкретной рассматриваемой функции:
Line # Hits Time Per Hit % Time Line Contents
==================================================
386 def _direction(n, res, M, Hsig, scale_var, grad_lnprior, z, fac):
387
388 # gradient
389 44 1241715 28220.8 3.7 g = 2 * scale_var * res - grad_lnprior + z * np.dot(M.T, 1. / n)
390
391 # hessian
392 44 3103117 70525.4 9.3 N = sparse.diags(1. / n ** 2, 0, format=FMT, dtype=DTYPE)
393 44 18814307 427597.9 56.2 H = - Hsig - z * np.dot(M.T, np.dot(N, M)) # slow!
394
395 # update direction
396 44 10329556 234762.6 30.8 d, fac = my_solver(H, -g, fac)
397
398 44 111 2.5 0.0 return d, fac
Глядя на результат, становится ясно, что построение H
— безусловно, самый дорогостоящий шаг — он занимает значительно больше времени, чем реальное определение нового направления.
Hsig
и M
— разреженные матрицы CSC, n
— плотный вектор, а z
— скаляр. Решатель, который я использую, требует, чтобы H
была разреженной матрицей CSC или CSR.
Вот функция, которая создает некоторые игрушечные данные с теми же форматами, размерами и разреженностью, что и мои настоящие матрицы:
import numpy as np
from scipy import sparse
def make_toy_data(nt=200000, nc=10):
d0 = np.random.randn(nc * (nt - 1))
d1 = np.random.randn(nc * (nt - 1))
M = sparse.diags((d0, d1), (0, nc), shape=(nc * (nt - 1), nc * nt),
format='csc', dtype=np.float64)
d0 = np.random.randn(nc * nt)
Hsig = sparse.diags(d0, 0, shape=(nc * nt, nc * nt), format='csc',
dtype=np.float64)
n = np.random.randn(nc * (nt - 1))
z = np.random.randn()
return Hsig, M, n, z
А вот мой оригинальный подход к построению H
:
def original(Hsig, M, n, z):
N = sparse.diags(1. / n ** 2, 0, format='csc')
H = - Hsig - z * np.dot(M.T, np.dot(N, M)) # slow!
return H
Сроки:
%timeit original(Hsig, M, n, z)
# 1 loops, best of 3: 483 ms per loop
Есть ли более быстрый способ построить эту матрицу?
np.dot(M.T, np.dot(N, M))
. Он точно работает на вашей машине? Вы хотите сделатьN.dot(M)
? - person YXD   schedule 18.04.2014numpy.dot()
переопределяется для разреженных матриц с этой фиксации а> 8 месяцев назад. - person ali_m   schedule 18.04.2014dot
, простоHsig - z * M.T * (N * M)
, но я не знаю, быстрее ли это. - person HYRY   schedule 18.04.2014np.dot()
кажется мне более естественным, чем*
. Реальной разницы в производительности нет, так как оба просто вызывают метод.__mul__()
разреженной матрицы. - person ali_m   schedule 18.04.2014