Как получить больше производительности от автоматической дифференциации?
Мне сложно оптимизировать программу, которая полагается на функцию ad
conjugateGradientDescent
для большей части работы.
В основном мой код является переводом кода старых документов, который написан в Matlab и C. Я его не оценил, но это код работает с несколькими итерациями в секунду. Мина находится в порядке минут на итерацию...
Код доступен в этих репозиториях:
Этот код можно запустить, выполнив следующие команды:
$ cd aer-utils
$ cabal sandbox init
$ cabal sandbox add-source ../aer
$ cabal run learngabors
Используя средства профилирования GHCs, я подтвердил, что спуск фактически является частью, которая занимает большую часть времени:
![Flamegraph of one iteration]()
(интерактивная версия здесь: https://dl.dropboxusercontent.com/u/2359191/learngabors.svg)
-s
говорит мне, что производительность довольно низкая:
Productivity 33.6% of total user, 33.6% of total elapsed
Из того, что я собрал, есть две вещи, которые могут привести к повышению производительности:
-
Unboxing: В настоящее время я использую реализацию пользовательской матрицы (в src/Data/SimpleMat.hs
). Это был единственный способ получить ad
для работы с матрицами (см. Как сделать автоматическое дифференцирование на hmatrix?). Я предполагаю, что использование матричного типа, такого как newtype Mat w h a = Mat (Unboxed.Vector a)
, обеспечит лучшую производительность из-за распаковки и слияния. Я нашел некоторый код, который имеет экземпляры ad
для распакованных векторов, но до сих пор я не смог использовать их с помощью conjugateGradientFunction
.
-
Матричные производные: В электронном письме, которое я просто не могу найти в тот момент, Эдвард упоминает, что было бы лучше использовать экземпляры Forward
для матричных типов вместо матриц, заполненных Forward
экземпляры. Я имею слабое представление о том, как этого достичь, но еще не понял, как реализовать его в терминах классов типа ad
.
Это, вероятно, вопрос, который слишком широк для ответа на SO, поэтому, если вы готовы помочь мне здесь, не стесняйтесь обращаться ко мне в Github.
Ответы
Ответ 1
В настоящее время вы используете сценарий для наименьшего сценария для текущей библиотеки ad
.
FWIW. Вы не сможете использовать существующие классы/типы ad
с "матричным/векторным объявлением". Это было бы довольно большое инженерное усилие, см. https://github.com/ekmett/ad/issues/2
Что касается того, почему вы не можете распаковать: conjugateGradient
требует использования режима Kahn
или двух уровней прямого режима для ваших функций. Первое исключает его из работы с нерасположенными векторами, поскольку типы данных несут деревья синтаксиса и не могут быть распакованы. По различным техническим причинам я не понял, как заставить его работать с лентой фиксированного размера, как в стандартном режиме Reverse
.
Я думаю, что "правильный" ответ здесь для нас, чтобы сесть и выяснить, как правильно получить матрицу/вектор AD и интегрировать в пакет, но я признаюсь, что я слишком мало времени, чтобы дать ему внимание, которое оно заслуживает.
Если у вас есть шанс качать # haskell-lens на irc.freenode.net, я с удовольствием расскажу о проектах в этом пространстве и дам совет. Алекс Ланг также много работал над ad
и часто присутствует там и может иметь идеи.