Debian Linux (Wheezy) R-3.4.0 kmcudaR 套件安裝錯誤之修改

今天看到 R 軟體一個新套件 kmcudaR,裡面有新的 kmean 跟 knn 函數,宣稱可以使用 GPU,並且採用新的「Yinyang K-Means」(陰陽 K-Means?) 演算法,速度比傳統的 K-Means 集群法還快 1.6 倍到 2 倍,目前只有 Linux 跟 Mac 版本。

所以我就在我 Linux 機器上用 R 的 install.packages 方法嘗試安裝,結果出現 compile 錯誤。這裡把我自己修正該套件原始碼錯誤的步驟紀錄一下。

使用一般正常 install.packages(“kmcudaR”) 安裝時,R 會抓套件原始碼自動編譯,出現的錯誤是:

knn.cu(241): error: identifier "UINT32_MAX" is undefined

我上網查了一下,並且查詢這個套件的原始碼,發現幾個程式中都沒有定義 UNIT32_MAX,於是修正了這個錯誤並且重新安裝,但後來又發現其他好幾個錯誤,有些是已經能順利執行 library(kmcudaR) 之後,在跑函數時出現的記憶體錯亂。所以我從頭到尾修正了好幾個地方,最後才能順利把套件中的 kmeans 與 knn 順利執行成功。

電腦環境與相關軟體版本:

Intel i7 CPU, 64 GB 記憶體
GPU: GeForce GTX 1080 (2560 CUDA cores/8 GB Memory)
OS: Debian Linux 7.11(Wheezy)
GCC: 4.7.2
CUDA: 8.0
R: 3.4.0

以下是我修改跟重新包裝套件、重新編譯的過程:

Step 1.

先到任何 CRAN 分站下載 kmcudaR 的原始碼 kmcudaR_1.0.0.tar.gz,並用
tar zxvf kmcudaR_1.0.0.tar.gz
解壓縮,然後
cd kmcudaR/src

Step 2. 在 src 資料夾中新增一個檔案 miner.h,內容只有 1 行:

#define UINT32_MAX (0xffffffff)

Step 3. 在以下 4 個檔案的前端都加入 #include “miner.h”

kmcuda.cc
kmcudaR.cpp
kmeans.cu
knn.cu

Step 4. 修改 kmcudaR.cpp 檔: 在 391 行左右,改成以下藍色程式碼:

#ifndef __APPLE__
/* #pragma omp parallel for simd */
#pragma omp simd
for (uint32_t i = 0; i < samples_size; i++) {
assignments2_ptr[i] = assignments[i] + 1;
}

Step 5. 修改 kmcudaR.cpp 檔: 在 494 行左右,改成以下藍色程式碼:

#ifndef __APPLE__
/* #pragma omp parallel for simd */
#pragma omp simd
for (uint32_t i = 0; i < samples_size; i++) {
assignments_ptr[i] = assignments_sexp[i] - 1;
}

Step 6. (Optional) 修改 src/Makevars.in 檔: 搜尋 DCUDA_ARCH=52, 改成 61 :
註:這部分可能跟 GPU 顯示卡型號新舊有關,未必需要更改

%.o: %.cc $(cc_sources)
$(CXX) $(CXX_ARGS) -DCUDA_ARCH=61 $(R_INC) -I/usr.................

Step 7. 到 kmcudaR 解開資料夾的上一層,執行以下指令重新包裝、編譯、並安裝:

例如,如果您現在是在 src 資料夾,需用 cd ../..
另外,您需要把以下指令中的  /opt/R/bin/R 改成自己 Linux 上 R 可執行檔的路徑

/opt/R/bin/R CMD build kmcudaR
/opt/R/bin/R CMD INSTALL kmcudaR_1.0.0.tar.gz

Step 8. 進入 R 軟體開始測試:

?View Code LANGUAGE
library(kmcudaR)
samples = replicate(4, runif(16000))
result = kmeans_cuda(samples, 50, seed=777)
head(result$centroids)
 
result2 = knn_cuda(20, samples, result$centroids, result$assignments,
metric="L2", device=0, verbosity=0)
head(result2)