使用线性内核调整 SVM 时,R 插入符号异常缓慢
Posted
技术标签:
【中文标题】使用线性内核调整 SVM 时,R 插入符号异常缓慢【英文标题】:R caret unusually slow when tuning SVM with linear kernel 【发布时间】:2015-08-03 19:21:18 【问题描述】:在使用caret
调整 SVM 参数时,我观察到一个非常奇怪的行为。在没有调整的情况下训练单个模型时,具有径向基内核的 SVM 比具有线性内核的 SVM 花费更多时间,这是意料之中的。然而,当在同一个惩罚网格上使用两个内核调整 SVM 时,使用线性内核的 SVM 比使用径向基内核的 SVM 花费的时间要多得多。这种行为可以很容易地在 Windows 和 Linux 中使用 R 3.2 和caret
6.0-47 重现。有谁知道为什么调整线性 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))))
【问题讨论】:
【参考方案1】:看过之后,我认为问题不在于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 秒。
话虽如此,您的瓶颈似乎在来自kernlab
的已编译C
代码中。由于包连接到libsvm
,这似乎非常有效,我无法想象调用的代码存在实际问题。实际上识别如何(基于安全的功能或来自 R 的输入问题)以及从一个移动到另一个时出现问题的原因是比我更好的人的工作。
【讨论】:
我也经历过。你应该给包作者 [Alexandros Karatzoglou, alexandros.karatzoglou@ci.tuwien.ac.at] 写个注释并参考这个(非常好的)分析。 我不认为包连接到libsvm
。来自 kernlab 小插图:“kernlab 的支持向量机实现 ksvm
,基于在 bsvm12
(Hsu 和 Lin 2002b)和 libsvm
(Chang 和 Lin 2001)中找到的优化器"。【参考方案2】:
我在 Linux 上遇到了非常糟糕的 svmRadial
性能。事实证明,问题在于使用多核DoMC
。 svmRadial
在单核上运行良好。 kernlab
函数是 caret
中唯一表现出我见过的这种行为的函数。除了其他人提到的问题之外,还要为kernlab
添加一个问题。
【讨论】:
以上是关于使用线性内核调整 SVM 时,R 插入符号异常缓慢的主要内容,如果未能解决你的问题,请参考以下文章
当 classProbs=TRUE 时,在 R 中使用插入符号的 SVM 的不同结果