2014-02-11 3 views
9

Мой учебный набор данных имеет около 200 000 записей, и у меня есть 500 функций. (Это данные о продажах в розничной организации). Большинство функций - 0/1 и хранится как разреженная матрица.Выполнение glmnet параллельно в R

Целью является предсказать вероятность покупки около 200 продуктов. Итак, мне нужно будет использовать те же 500 функций, чтобы предсказать вероятность покупки для 200 продуктов. Поскольку glmnet - естественный выбор для создания модели, я подумал о параллельном внедрении glmnet для 200 продуктов. (Так как все 200 моделей независимы) Но я застрял, используя foreach. Код я выполнил был:

foreach(i = 1:ncol(target)) %dopar% 
{ 
assign(model[i],cv.glmnet(x,target[,i],family="binomial",alpha=0,type.measure="auc",grouped=FALSE,standardize=FALSE,parallel=TRUE)) 
} 

модель представляет собой список - имея список 200 имен моделей, где я хочу, чтобы сохранить соответствующие модели.

Следующий код работает. Но он не использует параллельную структуру и занимает около одного дня!

for(i in 1:ncol(target)) 
{ assign(model[i],cv.glmnet(x,target[,i],family="binomial",alpha=0,type.measure="auc",grouped=FALSE,standardize=FALSE,parallel=TRUE)) 
} 

Может ли кто-нибудь указать мне, как использовать параллельную структуру в этом случае?

+0

вы зарегистрировались параллельно бэкенд во втором случае? Wh ich один? Вы хотите работать на одном многоядерном компьютере или в кластере? –

+0

Для второго - я использовал параллельную опцию в glmnet. Из того, что я понимаю, он использует это для параллелизации CV. Я работаю на одном многоядерном компьютере (четырехъядерный ядро ​​с 16-гигабайтным баром) – Rouse

ответ

18

Для того, чтобы параллельно выполнить «cv.glmnet», вы должны указать опцию parallel=TRUE, и зарегистрировать параллельный сервер foreach. Это позволяет вам выбрать параллельный бэкэнд, который лучше всего подходит для вашей вычислительной среды.

Вот документация для «параллельного» аргумента со страницы cv.glmnet людей:

параллели: Если «TRUE», используйте параллельный «Еогеаспа», чтобы соответствовать каждый раз. Необходимо зарегистрировать параллель перед рукой, например, «doMC» или другие. См. Пример ниже.

Вот пример с использованием пакета doParallel, который работает на Windows, Mac OS X и Linux:

library(doParallel) 
registerDoParallel(4) 
m <- cv.glmnet(x, target[,1], family="binomial", alpha=0, type.measure="auc", 
       grouped=FALSE, standardize=FALSE, parallel=TRUE) 

Этот вызов cv.glmnet будет выполняться параллельно с использованием четырех рабочих. В Linux и Mac OS X он выполнит задачи, используя «mclapply», в то время как в Windows он будет использовать «clusterApplyLB».

Вложенный параллелизм становится сложным, и может не помочь много с 4 рабочими. Я попытался бы использовать обычный цикл для цикла cv.glmnet (как в вашем втором примере) с зарегистрированным параллельным бэкэндом и посмотреть, что такое производительность, прежде чем добавить еще один уровень параллелизма.

Также обратите внимание, что присвоение «модели» в вашем первом примере не будет работать при регистрации параллельного бэкэнд. При параллельном запуске побочные эффекты обычно отбрасываются, как и в большинстве параллельных программных пакетов.

+1

(+1) Этот ответ верный. Однако я обнаружил, что, если моя матрица дизайна слишком велика, R не будет использовать дополнительные рабочие, потому что у меня недостаточно памяти для дополнительных копий! – Sycorax

+0

@ user777 Возможно, вы захотите попробовать использовать рабочих на нескольких компьютерах, чтобы получить доступ к более общей памяти. Это можно сделать либо с помощью doParallel, либо с помощью doMPI, но это небольшая работа, если у вас нет доступа к кластеру Linux с настройками. –

+1

Конечно! Настоящий трюк убеждает, что ваш босс, который вам нужен, может быть компьютером ... :) Я только сказал, что указать на OP, что его установка на рабочем столе может оказаться недостаточной. – Sycorax

1

Наткнулся на эту старую тему и подумал, что было бы полезно упомянуть, что с фреймворком future можно выполнять вложенные и параллельные вызовы foreach(). Например, предположим, что у вас есть три локальных машин (которые доступ SSH) и вы хотите запустить четыре ядра на каждом, то вы можете использовать:

library("doFuture") 
registerDoFuture() 
plan(list(
    tweak(cluster, workers = c("machine1", "machine2", "machine3")), 
    tweak(multiprocess, workers = 4L) 
)) 


model_fit <- foreach(ii = seq_len(ncol(target))) %dopar% { 
    cv.glmnet(x, target[,ii], family = "binomial", alpha = 0, 
      type.measure = "auc", grouped = FALSE, standardize = FALSE, 
      parallel = TRUE) 
} 
str(model_fit) 

«внешний» Еогеасп-цикл будет перебирать целей, таких, что каждая итерация обрабатывается отдельной машиной. Каждая итерация, в свою очередь, обрабатывает cv.glmnet(), используя четырех рабочих на любой машине, на которой она заканчивается.

(Конечно, если вы только получили доступ к одной машине, то это не имеет никакого смысла делать вложенную параллельную обработку ввода таких случаев, вы можете использовать:.

plan(list(
    sequential, 
    tweak(multiprocess, workers = 4L) 
)) 

распараллелить cv.glmnet() вызова, или в качестве альтернативы,

plan(list(
    tweak(multiprocess, workers = 4L), 
    sequential 
)) 

, или что то же самое только plan(multiprocess, workers = 4L), распараллеливание над цели.

Смежные вопросы