使用线性内核调整SVM时,R插入符非常慢

时间:2015-05-21 22:23:12

标签: r performance svm r-caret kernlab

使用caret调整SVM参数时,我发现了一种非常奇怪的行为。在没有调整的情况下训练单个模型时,具有径向基础内核的SVM比具有线性内核的SVM花费更多时间,这是预期的。然而,当在相同惩罚网格上调整具有两个内核的SVM时,具有线性内核的SVM比具有径向基础内核的SVM花费更多的时间。使用R 3.2和caret 6.0-47可以在Windows和Linux中轻松复制此行为。有谁知道为什么调整线性SVM比径向基核SVM需要更多的时间?

SVM linear
   user  system elapsed 
   0.51    0.00    0.52 

SVM radial
   user  system elapsed 
   0.85    0.00    0.84 

SVM linear tuning
   user  system elapsed 
 129.98    0.02  130.08 

SVM radial tuning
   user  system elapsed 
   2.44    0.05    2.48 

玩具示例代码如下:

library(data.table)
library(kernlab)
library(caret)

n <- 1000
p <- 10

dat <- data.table(y = as.factor(sample(c('p', 'n'), n, replace = T)))
dat[, (paste0('x', 1:p)) := lapply(1:p, function(x) rnorm(n, 0, 1))]
dat <- as.data.frame(dat)

sigmas <- sigest(as.matrix(dat[, -1]), na.action = na.omit, scaled = TRUE)
sigma  <- mean(as.vector(sigmas[-2]))

cat('\nSVM linear\n')
print(system.time(fit1 <- train(y ~ ., data = dat, method = 'svmLinear', tuneLength = 1,
                                 trControl = trainControl(method = 'cv', number = 3))))

cat('\nSVM radial\n')
print(system.time(fit2 <- train(y ~ ., data = dat, method = 'svmRadial', tuneLength = 1,
                                 trControl = trainControl(method = 'cv', number = 3))))

cat('\nSVM linear tuning\n')
print(system.time(fit3 <- train(y ~ ., data = dat, method = 'svmLinear',
                                 tuneGrid = expand.grid(C = 2 ^ seq(-5, 15, 5)),
                                 trControl = trainControl(method = 'cv', number = 3))))

cat('\nSVM radial tuning\n')
print(system.time(fit4 <- train(y ~ ., data = dat, method = 'svmRadial',
                                 tuneGrid = expand.grid(C = 2 ^ seq(-5, 15, 5), sigma = sigma),
                                 trControl = trainControl(method = 'cv', number = 3))))

2 个答案:

答案 0 :(得分:3)

看了之后,我不相信问题出在caret上,而是在kernlab的场景背后(后面)发生了什么。 正如其他地方所述,堆栈溢出SVM本身就是一种密集算法。 SVM的时间复杂度为O(n * n)。现在,这并不能解释SVM次呼叫之间的差异。然而,似乎正在发生的事情是在通过以SVM > .Local > .call.结尾的非常深的堆栈调用编译的C代码之后(.call是对已编译的c代码的调用并且在我的知识库之外)。大多数情况下,当您看到意外的慢速时间从R移动到C时,因为事情是如何传递的。由于你拉入矩阵,这有助于进一步假设命名或尺寸问题导致另一端的额外工作。
如果我们看看这个代码是如何分析的,那么瓶颈就会变得非常明显。

关于字体大小的道歉 - 它是一个深层叠加,我认为整体形状比单个功能更能讲述故事。随意垃圾邮件Ctrl +下面。

nSVM_linear看起来像一个健康的配置文件和许多友好的R函数。

nSVM_linear

nSVM radial

的相同交易

enter image description here

现在我们开始进行径向调整&#39;我们开始看到更平坦的结构,try-call堆栈开始倾斜,但一切似乎都在快速执行。

enter image description here

哇。完全不同的线性调整C调用结构在某些情况下需要超过100秒。

enter image description here

所以说,看起来你的瓶颈在C的编译kernlab代码中。由于软件包连接到libsvm,这似乎非常有效,我无法想象调用代码存在实际问题。实际上确定如何(基于安全的功能或来自R的输入问题)以及当从一个移动到另一个时问题发生的原因对于比我更好的人来说是一项工作。

答案 1 :(得分:0)

我在Linux上遇到了令人难以置信的svmRadial性能。事实证明,问题在于使用多核DoMCsvmRadial在单个核心上运行良好。 kernlab函数是caret中唯一表现出我已经看过的行为的函数。除了其他人提到的问题之外,还需要为kernlab添加一个问题。