Как повысить производительность автоматического дифференцирования?

Мне трудно оптимизировать программу, которая по большей части использует функцию ads conjugateGradientDescent.

По сути, мой код представляет собой перевод кода старых документов, написанного на Matlab и C. Я не измерял, но этот код выполняется с частотой несколько итераций в секунду. У меня порядка минут на итерацию...

Код доступен в этих репозиториях:

Рассматриваемый код можно запустить, выполнив следующие команды:

$ cd aer-utils
$ cabal sandbox init
$ cabal sandbox add-source ../aer
$ cabal run learngabors

Используя средства профилирования GHC, я подтвердил, что спуск на самом деле является той частью, которая занимает большую часть времени:

Flamegraph одной итерации

(интерактивная версия здесь: https://dl.dropboxusercontent.com/u/2359191/learngabors.svg)

-s говорит мне, что производительность довольно низкая:

Productivity  33.6% of total user, 33.6% of total elapsed

Из того, что я собрал, есть две вещи, которые могут привести к более высокой производительности:

  • Распаковка: в настоящее время я использую пользовательскую реализацию матрицы (в src/Data/SimpleMat.hs). Это был единственный способ заставить ad работать с матрицами (см. выполнять автоматическое дифференцирование по hmatrix?). Я предполагаю, что использование матричного типа, такого как newtype Mat w h a = Mat (Unboxed.Vector a), позволит добиться лучшей производительности за счет распаковки и слияния. Я нашел какой-то код, который имеет ad экземпляров для распакованных векторов, но до сих пор я не смог использовать их с conjugateGradientFunction.

  • Матричные производные: в письме, которое я просто не могу найти в данный момент, Эдвард упоминает, что было бы лучше использовать Forward экземпляров для типов матриц вместо того, чтобы матрицы заполнялись Forward экземплярами. У меня есть смутное представление о том, как этого добиться, но мне еще предстоит выяснить, как реализовать это с точки зрения классов типов ads.

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


person fho    schedule 17.06.2015    source источник
comment
Вопрос к аудитории: Cabal run использует под капотом что-то вроде runhaskell, т.е. часть проблемы заключается в том, что этот код интерпретируется, а не компилируется?   -  person John F. Miller    schedule 18.06.2015
comment
@JohnF.Miller cabal run запускает скомпилированный код. Запуск того же самого из GHCi (т.е. использование :main) еще медленнее.   -  person fho    schedule 18.06.2015


Ответы (1)


Здесь вы столкнулись с наихудшим сценарием для текущей библиотеки ad.

FWIW- Вы не сможете использовать существующие ad классы/типы с "матричным/векторным объявлением". Это потребует значительных инженерных усилий, см. https://github.com/ekmett/ad/issues/2

Что касается того, почему вы не можете распаковать: conjugateGradient требует возможности использовать режим Kahn или два уровня прямого режима для ваших функций. Первый не позволяет работать с неупакованными векторами, поскольку типы данных содержат синтаксические деревья и не могут быть распакованы. По разным техническим причинам я не понял, как заставить его работать с «лентой» фиксированного размера, как в стандартном режиме Reverse.

Я думаю, что «правильный» ответ здесь для нас - сесть и выяснить, как правильно сделать матричную/векторную AD и интегрировать ее в пакет, но я признаюсь, что сейчас я слишком тонко отснял время, чтобы уделить этому внимание. заслуживает.

Если у вас будет возможность зайти на #haskell-lens на irc.freenode.net, я буду рад поговорить о дизайне в этом пространстве и дать совет. Алекс Лэнг также много работал над ad, часто присутствует там и может иметь идеи.

person Edward KMETT    schedule 16.09.2015