У меня есть функция Haskell, которая вызывает более 50% всех распределений моей программы, в результате чего 60% моего времени выполнения GC , Я запускаю небольшой стек (-K10K
), поэтому нет переполнения стека, но могу ли я сделать эту функцию быстрее, с меньшим распределением?Оптимизируйте функцию списка, которая создает слишком много мусора (не переполнение стека)
Целью здесь является вычислить произведение матрицы на вектор. Например, я не могу использовать hmatrix
, потому что это часть большей функции с использованием пакета ad
Automatic Differentiation, поэтому мне нужно использовать списки Num
. Во время выполнения я полагаю, что использование модуля Numeric.AD
означает, что мои типы должны быть Scalar Double
.
listMProd :: (Num a) => [a] -> [a] -> [a]
listMProd mdt vdt = go mdt vdt 0
where
go [] _ s = [s]
go ls [] s = s : go ls vdt 0
go (y:ys) (x:xs) ix = go ys xs (y*x+ix)
В основном мы цикл через матрицу, множительную и добавление аккумулятора, пока мы не достигнем конца вектора, сохранение результата, а затем продолжается снова перезапуск вектора. У меня есть тест quickcheck
, подтверждающий, что я получаю тот же результат, что и матричный/векторный продукт в hmatrix.
Я пробовал с foldl
, foldr
и т. Д. Ничего, что я пробовал, делает функцию быстрее (и некоторые вещи вроде foldr
вызывают утечку пространства).
Бег с профилированием говорит мне, на вершине того, что эта функция, где большую часть времени и распределения тратится, что есть грузы Cells
Создаются Cells
быть типом данных из ad
пакета.
Простой тест для запуска:
import Numeric.AD
main = do
let m :: [Double] = replicate 400 0.2
v :: [Double] = replicate 4 0.1
mycost v m = sum $ listMProd m v
mygrads = gradientDescent (mycost (map auto v)) (map auto m)
print $ mygrads !! 1000
Это на моей машине говорит мне, GC занят 47% времени.
Любые идеи?
Дополнительная информация! Как вы запускаете эту программу? Где ваш тестовый жгут? Какие конкретные типы вы используете? Каковы флаги и версии вашего компилятора Haskell? –
Добавлена информация. Эта функция вызывается через функцию ad grad, которая использует свои собственные типы (экземпляры Num). Профилирование показывает распределения «Ячейки». –
Некоторые недооцененные предложения: рассмотрели ли вы использование изменяемого состояния с 'ST'? И [stream-fusion] (https://hackage.haskell.org/package/stream-fusion-0.1.2.5/docs/Data-List-Stream.html)/[channelduit] (https: //hackage.haskell. орг/пакет/трубка)/[труба] (https://hackage.haskell.org/package/pipes)? Может быть (?), Может быть даже целесообразно преобразовать ваш векторный список во что-то другое, например. [unboxed vector] (http://lambda.jstolarek.com/2013/04/haskell-as-fast-as-c-a-case-study/)? У меня нет опыта в использовании каких-либо из этих методов, но, возможно, ссылки могут помочь вам в дальнейшем. –