Как включить код C или С++ в мой R-код, чтобы ускорить программу MCMC, используя алгоритм Metropolis-Hastings

Я ищу совет о том, как включить код C или С++ в свой R-код, чтобы ускорить программу MCMC, используя алгоритм Metropolis-Hastings. Я использую подход MCMC для моделирования вероятности, учитывая различные ковариаты, что индивидууму будет назначаться определенный ранг в иерархии социального статуса третьей стороной (судьей): каждый судья (приблизительно 80 человек в 4 деревнях) был задан ранжировать группу лиц (примерно 80, в 4 деревнях) на основе их оценки каждого отдельного социального статуса. Поэтому для каждого судьи у меня есть вектор рангов, соответствующий их суждению о каждой отдельной позиции в иерархии.

Чтобы моделировать это, я предполагаю, что при присвоении рангов судьи основывают свои решения на относительном значении некоторой скрытой меры отдельной утилиты u. Учитывая это, тогда можно предположить, что вектор рангов r, созданный данным судьей, является функцией ненаблюдаемого вектора u, описывающего полезность индивидуумов, в которых индивидууму с k-м наивысшим значением u будет присвоен k-й ранг. Я моделирую u, используя интересующие ковариации, как многомерную нормально распределенную переменную, а затем определяю вероятность наблюдаемых рангов, учитывая распределение u, сгенерированное моделью.

В дополнение к оценке влияния не более 5 ковариаций я также оцениваю гиперпараметры, описывающие отклонения между судьями и предметами. Поэтому для каждой итерации цепи я оцениваю многомерную нормальную плотность примерно в 8-10 раз. В результате 5000 итераций могут занять до 14 часов. Очевидно, что мне нужно запустить его более чем на 5000 запусков, и поэтому мне нужно средство для резкого ускорения процесса. Учитывая это, мои вопросы таковы:

(i) Правильно ли я предполагаю, что лучшие выигрыши в скорости будут выполняться при запуске некоторой, если не всей моей цепочки на C или С++?

(ii) при условии, что ответ на вопрос 1 да, как мне это сделать? Например, есть ли способ сохранить все мои R-функции, но просто выполнить цикл в C или С++: например, можно ли вызвать мои R-функции из C, а затем сделать цикл?

(iii) Я предполагаю, что я действительно хочу знать, как лучше всего подойти к включению кода C или С++ в мою программу.

Ответ 1

Сначала убедитесь, что ваша медленная версия R верна. Отладка кода R может быть проще, чем отладка кода C. Это сделано? Отлично. Теперь у вас есть правильный код, который вы можете сравнить с.

Затем, узнайте, что занимает время. Используйте Rprof для запуска кода и просмотра того, что занимает время. Я сделал это для некоторого кода, который унаследовал один раз, и обнаружил, что он тратит 90% времени на функцию t(). Это было потому, что у программиста была матрица А, и он делал t (A) в миллион местах. Я сделал один tA = t (A) в начале и заменил каждый t (A) на tA. Массивное ускорение без усилий. Сначала просмотрите свой код.

Теперь вы нашли свое узкое место. Это код, который вы можете ускорить в R? Это цикл, который вы можете прорисовать? Сделай это. Проверьте свои результаты против вашего золотого стандартного правильного кода. Всегда. Да, я знаю, что трудно сравнивать алгоритмы, которые полагаются на случайные числа, поэтому установите семена одинаковыми и повторите попытку.

Все еще не достаточно быстро? Хорошо, теперь, возможно, вам нужно переписать части (части самого низкого уровня, как правило, и те, которые занимают больше всего времени в профилировании) на C или С++ или Fortran, или если вы действительно собираетесь это сделать, в коде GPU.

Опять же, действительно проверьте, что код дает те же ответы, что и правильный R-код. Действительно проверьте это. Если на этом этапе вы обнаружите какие-либо ошибки в общем методе, исправьте их в том, что вы считали правильным кодом R и в своей последней версии, и повторите все ваши тесты. Создайте множество автоматических тестов. Запускайте их часто.

Читайте о рефакторинге кода. Он назывался рефакторингом, потому что, если вы сообщите своему боссу, что вы переписываете свой код, он или она скажет: "Почему вы не ввели его правильно в первый раз?". Если вы скажете, что вы переформатируете свой код, они скажут "хм... хорошо". ЭТО ПРОСТО ПРОФЕССИОНАЛЬНО.

Как говорили другие, Rcpp сделан из победы.

Ответ 2

Полный пример с использованием R, С++ и Rcpp - предоставленный этим сообщением в блоге, который был вдохновлен этот пост в блоге Даррена Уилкинсона (и у него есть больше последующих комментариев, UPS). Этот пример также включен в недавние выпуски Rcpp в каталоге RcppGibbs и должен вас поймать.

Ответ 3

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

http://darrenjw.wordpress.com/2011/07/31/faster-gibbs-sampling-mcmc-from-within-r/

(этот пост более уместен, чем мой пост, о котором говорит Дирк).

Ответ 4

Я думаю, что лучшим методом для интеграции C или С++ является пакет Rcpp от Dirk Eddelbuettel. Вы можете найти много информации на его веб-сайте. Существует также беседа в Google, которая доступна через youtube, которая может быть интересной.

Ответ 6

Я бы предложил сравнить каждый шаг сэмплера MCMC и определить узкое место. Если вы поместите каждый полный условный или M-H-шаг в функцию, вы можете использовать пакет компилятора R, который может дать вам прирост скорости 5% -10%. Следующим шагом будет использование RCPP.

Я думаю, было бы очень приятно иметь функцию RCPP общего назначения, которая генерирует только одну ничью, используя алгоритм M-H, учитывая функцию правдоподобия.

Однако с RCPP некоторые вещи становятся трудными, если вы знаете только язык R: нестандартные случайные распределения (особенно усеченные) и использование массивов. Вы должны думать больше, как программист C там.

Многовариантный нормальный факт - большая проблема в R. Dmvnorm очень неэффективна и медленна. Dmnorm быстрее, но это дало бы мне NaNs быстрее, чем dmvnorm в некоторых моделях.

Также не берется массив ковариационных матриц, поэтому во многих случаях невозможно векторизовать код. Тем не менее, если у вас есть общая ковариация и средства, вы можете векторизовать, что является стратегией R-ish для ускорения (и которая является противоположностью того, что вы бы сделали на C).