0

mclapply非常に大きな計画行列X(〜10GB)と応答ベクトルのフィッティング手順をモデル化するための交差検証を並列化するために使用しようとしていますyX次元がn-by-p:であるとしましょうn=1000, p=1,000,000Xは非常に巨大であるため、オブジェクトとしてバックアップさbig.matrixれ、ディスクに格納され、R パッケージのメソッドを使用してアクセスされますbigmemory

4 分割クロス検証のワークフローは次のとおりです。

  1. cv.ind長さ のインデックス ベクトルを設定しますn。これは 1 ~ 4 の一連の数値を格納し、 のどの観測値がXCV のどのフォールドに属するかを示します。
  2. 4 コアをセットアップします。i 番目のコアで、i 番目のフォールド CV の対応するトレーニングおよびテスト サブマトリックスをコピーします。
  3. 各コアの折り目ごとにモデルを当てはめます。
  4. 結果を収集し、返します。

交差検証関数は次のようになります。

cv.ncvreg <- function(X, y, ncore, nfolds=5, seed, cv.dir = getwd(), 
                      cv.ind) {
  ## some more setup ...
  ## ...
  ## ...
  ## pass the descriptor info to each core ##
  xdesc <- describe(X)
  ## use mclapply instead of parLapply
  fold.results <- parallel::mclapply(X = 1:nfolds, FUN = cvf, XX=xdesc, y=y, 
                                     cv.dir = cv.dir, cv.ind=cv.ind, 
                                     cv.args=cv.args,
                                     mc.set.seed = seed, mc.silent = F, 
                                     mc.cores = ncore, mc.preschedule = F)

  ## return results
}

R 関数cvfは各コアで実行されます。i 番目のフォールドのトレーニング/テスト行列を 2 つのbig.matrixオブジェクトとしてコピーし、モデルに適合させ、いくつかの統計を計算し、結果を返します。

cvf <- function(i, XX, y, cv.dir, cv.ind, cv.args) {
  ## argument 'XX' is the descriptor for big.matrix
  # reference to the big.matrix by descriptor info
  XX <- attach.big.matrix(XX)

  cat("CV fold #", i, "\t--Copy training-- Start time: ", format(Sys.time()), "\n\n")
  ## physically copy sub big.matrix for training
  idx.train <- which(cv.ind != i) ## get row idx for i-th fold training
  deepcopy(XX, rows = idx.train, type = 'double',
           backingfile = paste0('x.cv.train_', i, '.bin'),
           descriptorfile = paste0('x.cv.train_', i, '.desc'),
           backingpath = cv.dir)
  cv.args$X <- attach.big.matrix(paste0(cv.dir, 'x.cv.train_', i, '.desc'))
  cat("CV fold #", i, "\t--Copy training-- End time: ", format(Sys.time()), "\n\n")

  cat("CV fold #", i, "\t--Copy test-- Start time: ", format(Sys.time()), "\n\n")
  ## physically copy remaining part of big.matrix for testing
  idx.test <- which(cv.ind == i) ## get row idx for i-th fold testing
  deepcopy(XX, rows = idx.test, type = 'double',
           backingfile = paste0('x.cv.test_', i, '.bin'),
           descriptorfile = paste0('x.cv.test_', i, '.desc'),
           backingpath = cv.dir)
  X2 <- attach.big.matrix(paste0(cv.dir, 'x.cv.test_', i, '.desc'))
  cat("CV fold #", i, "\t--Copy test-- End time: ", format(Sys.time()), "\n\n")

  # cv.args$X <- XX[cv.ind!=i, , drop=FALSE]
  cv.args$y <- y[cv.ind!=i]
  cv.args$warn <- FALSE

  cat("CV fold #", i, "\t--Fit ncvreg-- Start time: ", format(Sys.time()), "\n\n")
  ## call 'ncvreg' function, fit penalized regression model
  fit.i <- ncvreg(X=cv.args$X, y=cv.args$y, family=cv.args$family, 
                  penalty = cv.args$penalty,lambda = cv.args$lambda, convex = cv.args$convex)

  # fit.i <- do.call("ncvreg", cv.args)
  cat("CV fold #", i, "\t--Fit ncvreg-- End time: ", format(Sys.time()), "\n\n")

  y2 <- y[cv.ind==i]
  yhat <- matrix(predict(fit.i, X2, type="response"), length(y2))

  loss <- loss.ncvreg(y2, yhat, fit.i$family)
  pe <- if (fit.i$family=="binomial") {(yhat < 0.5) == y2} else NULL
  list(loss=loss, pe=pe, nl=length(fit.i$lambda), yhat=yhat)
}

ここまでは、計画行列Xが大きすぎない場合 (n=1000, p=100,000サイズが ~1GB の場合)、コードは非常にうまく機能します。しかし、p=1,000,000それによって のサイズXが ~10GB になると、各コアでのモデル フィッティング手順が無限に実行されます!!!!! (次の部分):

#...
cat("CV fold #", i, "\t--Fit ncvreg-- Start time: ", format(Sys.time()), "\n\n")
## call 'ncvreg' function, fit penalized regression model
fit.i <- ncvreg(X=cv.args$X, y=cv.args$y, family=cv.args$family, 
                penalty = cv.args$penalty,lambda = cv.args$lambda, convex = cv.args$convex)
# fit.i <- do.call("ncvreg", cv.args)
cat("CV fold #", i, "\t--Fit ncvreg-- End time: ", format(Sys.time()), "\n\n")
#...

:

  1. 生のマトリックス (10GB) で 'ncvreg()' を 1 回実行すると、約 2.5 分かかります。
  2. forループではなくループを使用してクロス検証を順次実行するmclapplyと、コードは正常に機能し、各フォールド 'ncvreg()' のモデル フィッティングも正常に機能します (~2 分) が、プロセス全体には ~25 分かかります。
  3. 最初は同じ問題で「parLapply」を試しました。ここの理由により、「mclapply」に切り替えました。
  4. 各コアのデータ コピー ステップ (deepcopy部分) は適切に機能し、トレーニング データ セットとテスト データ セットをディスクにコピーしてファイルでバックアップするのに約 2 分かかります
  5. CPU 使用率を監視しようとしました。以下は 1 つのスクリーンショットです。左の図でわかるように、4 つのセッションのそれぞれが最大 25% の CPU 使用率を占めていますが、1 つのプロセスでは、kernel_taskが最大 100% の CPU を使用しています。時間が経過すると、kernel_taskは 150% の CPU を使用することさえあります。さらに、CPU 履歴パネル (右下) は、赤色の領域が緑色の領域を支配しているため、ほとんどの CPU 使用率がユーザーではなくシステムによるものであることを示しています。

ここに画像の説明を入力


私の質問:

  1. モデル フィッティング プロセスを並列に実行すると、時間がかかるのはなぜですか? 考えられる理由は何ですか?
  2. big.matrix の CV 手順を並列化する正しい方向に進んでいますか? 別の方法はありますか?

ここで私の問題を解決するのに役立つ洞察に感謝します。前もって感謝します!!

4

0 に答える 0