Я пытаюсь решить некоторые неограниченные задачи нелинейной оптимизации на GPU (CUDA).
Целевая функция является гладкой нелинейной функцией, и ее градиент относительно дешев для аналитического вычисления, поэтому мне не нужно беспокоиться о численном приближении.
Я хочу решить эту проблему в основном с математическими операциями fp32 (по разным причинам), так какой метод нелинейной оптимизации более устойчив к ошибкам округления, но при этом имеет хорошую производительность? (например, сопряженный градиент / квазиньютон / область доверия), кто-нибудь пробовал BFGS на GPU с хорошими результатами?
Кстати, гессиан, если нужно, в моем случае относительно небольшой (обычно <64x64), но мне нужно одновременно решать тысячи из этих небольших оптимизационных задач.
источник
Ответы:
Я реализовал довольно широкий спектр нелинейных решателей на GPU, включая LBFGS, градиентный спуск Barzilai Borwein и нелинейный сопряженный градиент.
Для этого нелинейный сопряженный градиент Dai & Yuan был наиболее эффективным. В общем, другая версия нелинейного сопряженного градиента может быть более эффективной (например, CG-DESCENT), но также может быть сложнее в реализации.
В общем, LBFGS - очень хороший выбор, и, если вы действительно не стеснены в памяти, возможно, это лучшее место для начала.
И для сопряженного градиента, и для BFGS требуется поиск строк, и именно здесь fp32 становится проблемой. Вместо того, чтобы использовать стандартные условия Вульфа для поиска строки, я бы предложил использовать приблизительное условие Вольфа, предложенное здесь . Статья немного сложная, но важная вещь - уравнение 4.1. По сути, они явно вводят точность, с которой вы можете рассчитать свою функцию.
Соображения по поводу GPU:
У вас много мелких проблем, которые немного отличаются от моего варианта использования одной большой проблемы. Рассмотрите возможность запуска 1 задачи на блок GPU (или, скорее, деформации), если вы можете распараллелить вычисления функций и градиентов, чтобы использовать все потоки в блоке. Таким образом, это не проблема, если для разных задач требуется разное количество итераций.
Если это не вариант, я бы пошел с решателем LBFGS. Если ваша функция хорошо себя ведет, вам может потребоваться просто использовать размер шага 1 (избегая поиска строки) и просто запустить все задачи за фиксированное количество итераций.
источник
Я предлагаю вам использовать Levenberg Marquardt (вариант доверительной области), так как он используется во многих практических приложениях и демонстрирует очень хорошие показатели скорость-точность-точность. Более того, для GPU есть несколько библиотек (например, cuLM https://github.com/zitmen/cuLM ), которые вы можете попробовать. Если они не выполняют свою работу, у вас есть масса ресурсов для реализации. Внедрение LM совсем не сложно. Вам следует только позаботиться о минимизации связи с графическим процессором. Чтобы получить краткое представление:
http://on-demand.gputechconf.com/gtc/2012/presentations/S0231-Levenberg-Marquardt-Using-Block-Sparse-Matrices-on-CUDA.pdf
источник
Возможно, процедура имитации отжига может лучше обрабатывать ошибки округления (и ее легко распараллелить).
Вы начинаете с грубой сетки области поиска и начального параметра "температура"
На каждом шаге вы вычисляете возможные точки решения (можно также принять точки без решения с некоторой вероятностью, обратной к температуре)
Затем сохраните только решения на этом этапе и увеличьте температуру, что обеспечивает более мелкозернистую сетку для следующей итерации.
Делайте это до тех пор, пока температура не станет <заданный предел / порог точности
источник