使用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))))
答案 0 :(得分:3)
看了之后,我不相信问题出在caret
上,而是在kernlab
的场景背后(后面)发生了什么。
正如其他地方所述,堆栈溢出SVM
本身就是一种密集算法。 SVM
的时间复杂度为O(n * n)。现在,这并不能解释SVM
次呼叫之间的差异。然而,似乎正在发生的事情是在通过以SVM > .Local > .call.
结尾的非常深的堆栈调用编译的C代码之后(.call
是对已编译的c代码的调用并且在我的知识库之外)。大多数情况下,当您看到意外的慢速时间从R
移动到C
时,因为事情是如何传递的。由于你拉入矩阵,这有助于进一步假设命名或尺寸问题导致另一端的额外工作。
如果我们看看这个代码是如何分析的,那么瓶颈就会变得非常明显。
关于字体大小的道歉 - 它是一个深层叠加,我认为整体形状比单个功能更能讲述故事。随意垃圾邮件Ctrl +下面。
nSVM_linear
看起来像一个健康的配置文件和许多友好的R函数。
nSVM radial
try-call
堆栈开始倾斜,但一切似乎都在快速执行。
C
调用结构在某些情况下需要超过100秒。
所以说,看起来你的瓶颈在C
的编译kernlab
代码中。由于软件包连接到libsvm
,这似乎非常有效,我无法想象调用代码存在实际问题。实际上确定如何(基于安全的功能或来自R的输入问题)以及当从一个移动到另一个时问题发生的原因对于比我更好的人来说是一项工作。
答案 1 :(得分:0)
我在Linux上遇到了令人难以置信的svmRadial
性能。事实证明,问题在于使用多核DoMC
。 svmRadial
在单个核心上运行良好。 kernlab
函数是caret
中唯一表现出我已经看过的行为的函数。除了其他人提到的问题之外,还需要为kernlab
添加一个问题。