R 迴圈的平行運算 doSNOW+foreach

在建構模型時,或是模型模擬需要反覆的大量運算時,時間成本常常會高到讓開發者無法忍受。也因此有之前的 ParellelGPU 運算。但前面兩篇可以有效的加速的前提,是建立在資料結構與想要的結果可以使用向量運算的情況下。當在面臨資料無法使用向量運算時,像是連續的判斷式加上運算,即使 GPU 是 GTX 1080 也只是無法使用的下場,這篇想要介紹使用平行運算 (Parallel computing) 加速 for 迴圈的方法。

R套件: doSNOW+foreach

doSNOW, foreach 為 R 平行運算的套件,安裝方式與一般的套件一樣。透過套件可以將 for 迴圈改寫成 foreach 的格式。

# 安裝 doSNOW, foreach

install.packages("foreach")

install.packages("doSNOW")

library(foreach)

library(doSNOW)

# 設定使用幾個核心進行運算,在這裡設定使用8個核心,進行平行運算。

cl<-makeCluster(8) 

registerDoSNOW(cl)

foreach

foreach 跟 for 迴圈本質上非常接近,基本上運算是大致相同的,但是在資料儲存的方式不太一樣。for 會依據給定的順序產生資料並儲存;foreach 更像是一個函數,將給予資料在 foreach 裡面的運算方式,同時的運算並回傳給定的值。簡單的來說,如果只是使用 for 的話,在 for 迴圈裡儲存的資料在迴圈裡給定,foreach 存資料方式只存最後一筆並且以 list 格式回傳。也就是說 for 運算一次,想要的變數資料超過一個維度,如果想要使用 foreach ,較困難的地方是要另外寫 .comb 函數,將資料以特定方式儲存下來。

p <- foreach( i = 1:100, ...) %dopar% { … }

# p 就是想要回傳的值, 圓括弧裡有一些重要變數在下方介紹,大括弧裡則放的是運算的過程

.combine

在 foreach 的運算過程,會透過 .combine 的方式將每一次運算的結果組合,若沒有給定的話,會使用 list() 格式儲存不同的結果。下面列出小編使用的較特別的儲存格式。

# 將結果以 list 格式儲存,與預設的儲存格式不同為,p[[變數順序]] [[i]],如果使用預設的組合方式為 p[[i]] [[變數順序]]

comb <- function(x, ...) {
  lapply(seq_along(x),
         function(i) c(x[[i]], lapply(list(...), function(y) y[[i]])))
}

#將結果以 rbind 的方式儲存,記得結果一定要轉成 marix 格式。
comb <- function(x, ...) {  
  mapply(rbind,x,...,SIMPLIFY=FALSE)
}

.package

在 {} 中有使用的函數的套件名稱。只要使用非 base 的函數一定要在這裡宣告。

進度條

當 R 需要大量時間計算時,進度條可以方便我們知道它算到第幾項,對於小編來說是非常實用的功能。同樣的也需要再 .package 宣告 “tcltk" 這個套件

install.packages("tcltk")

p <- foreach( i = 1:100, ... .package = c(“tcltk”)) %dopar% {

 if(!exists("pb")) pb <- tkProgressBar("Parallel task","completed %", min=1, max=100)

  setTkProgressBar(pb, i, title = paste("進度估計",i)) , … }

結論

在進行模型訓練,或是模擬交易時,大部分的情況已經無法使用向量運算,這個時候 doSNOW, foreach 是最有效且無痛的加速方法,只需要確認好想要儲存的資料格式,並且寫出適合的 .combine 的函數就好,真心推薦給大家使用。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s