2013-07-17 3 views
5

Ich wollte benutzerdefinierte Kernel-Funktion für Ksvm in R verwenden. Also habe ich versucht, einen vanilladot-Kernel zu machen und mit "vacaldot" zu vergleichen, die in "Kernlab" als Übung eingebaut ist.(in R) Warum unterscheidet sich das Ergebnis von ksvm, das den benutzerdefinierten linearen Kernel verwendet, von dem von ksvm, das "vanilladot" verwendet?

Ich schreibe meinen Kernel wie folgt.

# 
###vanilla kernel with class "kernel" 
# 
kfunction.k <- function(){ 
    k <- function (x,y){crossprod(x,y)} 
    class(k) <- "kernel" 
    k} 
l<-0.1 ; C<-1/(2*l) 

###use kfunction.k 
tmp<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel=kfunction.k(), C = C) 
alpha(tmp)[[1]] 
ind<-alphaindex(tmp)[[1]] 
x.s<-x[ind,] ; y.s<-y[ind] 
w.class.k<-t(alpha(tmp)[[1]]*y.s)%*%x.s 
w.class.k 

Das Ergebnis dieser Operation ist äquivalent zu dem folgenden. Allerdings nicht.

# 
###use "vanilladot" 
# 
l<-0.1 ; C<-1/(2*l) 
tmp1<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel="vanilladot", C = C) 
alpha(tmp1)[[1]] 
ind1<-alphaindex(tmp1)[[1]] 
x.s<-x[ind1,] ; y.s<-y[ind1] 
w.tmp1<-t(alpha(tmp1)[[1]]*y.s)%*%x.s 
w.tmp1 

Ich denke, dass dieses Problem möglicherweise mit der Kernel-Klasse zusammenhängt. Wenn die Klasse auf "Kernel" eingestellt ist, ist dieses Problem aufgetreten. Wenn die Klasse jedoch auf "vanerkernel" gesetzt ist, entspricht das Ergebnis von ksvm, das den benutzerdefinierten Kernel verwendet, dem von ksvm, das "valladot" verwendet, das in Kernlab erstellt wird.

# 
###vanilla kernel with class "vanillakernel" 
# 
kfunction.v.k <- function(){ 
    k <- function (x,y){crossprod(x,y)} 
    class(k) <- "vanillakernel" 
    k} 
# The only difference between kfunction.k and kfunction.v.k is "class(k)". 
l<-0.1 ; C<-1/(2*l) 

###use kfunction.v.k 
tmp<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel=kfunction.v.k(), C = C) 
alpha(tmp)[[1]] 
ind<-alphaindex(tmp)[[1]] 
x.s<-x[ind,] ; y.s<-y[ind] 
w.class.v.k<-t(alpha(tmp)[[1]]*y.s)%*%x.s 
w.class.v.k 

Ich verstehe nicht, warum das Ergebnis von „vanilladot“ anders ist, wenn die Klasse auf „Kernel“.

Gibt es einen Fehler in meiner Operation?

Antwort

3

Erstens scheint es eine wirklich gute Frage!

Jetzt auf den Punkt. In den Quellen von ksvm können wir finden, wenn eine Linie zwischen der Verwendung von benutzerdefinierten Kernel und die Einbauten gezogen ist:

if (type(ret) == "spoc-svc") { 
      if (!is.null(class.weights)) 
       weightedC <- class.weights[weightlabels] * rep(C, 
        nclass(ret)) 
      else weightedC <- rep(C, nclass(ret)) 
      yd <- sort(y, method = "quick", index.return = TRUE) 
      xd <- matrix(x[yd$ix, ], nrow = dim(x)[1]) 
      count <- 0 
      if (ktype == 4) 
       K <- kernelMatrix(kernel, x) 
      resv <- .Call("tron_optim", as.double(t(xd)), as.integer(nrow(xd)), 
       as.integer(ncol(xd)), as.double(rep(yd$x - 1, 
        2)), as.double(K), as.integer(if (sparse) [email protected] else 0), 
       as.integer(if (sparse) [email protected] else 0), as.integer(sparse), 
       as.integer(nclass(ret)), as.integer(count), as.integer(ktype), 
       as.integer(7), as.double(C), as.double(epsilon), 
       as.double(sigma), as.integer(degree), as.double(offset), 
       as.double(C), as.double(2), as.integer(0), as.double(0), 
       as.integer(0), as.double(weightedC), as.double(cache), 
       as.double(tol), as.integer(10), as.integer(shrinking), 
       PACKAGE = "kernlab") 
      reind <- sort(yd$ix, method = "quick", index.return = TRUE)$ix 
      alpha(ret) <- t(matrix(resv[-(nclass(ret) * nrow(xd) + 
       1)], nclass(ret)))[reind, , drop = FALSE] 
      coef(ret) <- lapply(1:nclass(ret), function(x) alpha(ret)[, 
       x][alpha(ret)[, x] != 0]) 
      names(coef(ret)) <- lev(ret) 
      alphaindex(ret) <- lapply(sort(unique(y)), function(x) 
which(alpha(ret)[, 
       x] != 0)) 
      xmatrix(ret) <- x 
      obj(ret) <- resv[(nclass(ret) * nrow(xd) + 1)] 
      names(alphaindex(ret)) <- lev(ret) 
      svindex <- which(rowSums(alpha(ret) != 0) != 0) 
      b(ret) <- 0 
      param(ret)$C <- C 
     } 

Die wichtige Teile sind zwei Dinge, erstens, wenn wir ksvm mit unseren eigenen Kernel bieten dann ktype=4 (während für vanillakernel, ktype=0), so macht es zwei Änderungen:

  • im Falle von benutzerdefinierten Kernel, der Kernel-Matrix anstelle der tatsächlich mit dem Kernel
  • tron_optim Routine berechnet wird, ist r ein mit der Information über den Kernel

Jetzt, in den svm.cpp wir die tron Routinen finden, und in den tron_run (genannt von tron_optim), dass LINEAR Kernel eine separate Optimierungsroutine hat

if (param->kernel_type == LINEAR) 
    { 
    /* lots of code here */ 
    while (Cpj < Cp) 
     { 
     totaliter += s.Solve(l, prob->x, minus_ones, y, alpha, w, 
          Cpj, Cnj, param->eps, sii, param->shrinking, 
          param->qpsize); 
    /* lots of code here */ 
     } 
    totaliter += s.Solve(l, prob->x, minus_ones, y, alpha, w, Cp, Cn, 
          param->eps, sii, param->shrinking, param->qpsize); 
    delete[] w; 
    } 
else 
{  
    Solver_B s; 
    s.Solve(l, BSVC_Q(*prob,*param,y), minus_ones, y, alpha, Cp, Cn, 
    param->eps, sii, param->shrinking, param->qpsize); 
} 

Wie Sie sehen können, wird der lineare Fall auf die komplexere, detailliertere Art behandelt. Es gibt eine innere Optimierungsschleife, die den Löser viele Male aufruft.Es wäre wirklich tiefe Analyse der tatsächlichen Optimierung erfordert hier durchgeführt wird, aber zu diesem Schritt kann man Ihre Frage in der folgenden Art und Weise beantworten:

  • Es gibt keinen Fehler in Ihrem Betrieb
  • kernlab des SVM hat eine separate Routine für SVM Training mit linearen Kernel, die an den Code übergeben von der Art von Kernel basiert, „Kernel“ auf „vanillakernel“ machte die ksvmdenken, dass es tatsächlich funktioniert mit vanillakernel, und so durchgeführt diese Veränderung separate Optimierung routi ne
  • Es scheint nicht als ein Bug in der Tat, wie die lineare SVM ist in der Tat sehr unterschiedlich von der Kernel-Version in Bezug auf effiziente Optimierungstechniken. Heuristische und numerische Probleme, die beachtet werden müssen, sind sehr groß. Daher sind einige Näherungen erforderlich, die zu unterschiedlichen Ergebnissen führen können. Während für den reichen Feature-Bereich (wie diejenigen, die durch RBF-Kernel induziert werden) es eigentlich keine Rolle spielen sollte, für einfache Kernel-Linien lineare - diese Vereinfachungen können zu signifikanten Output-Änderungen führen.
+0

Ich denke, dass der relevante Code tatsächlich in einem anderen Teil der Quelle ist. Die Frage hat type = "C-svc", aber der Code in der Antwort zeigt type (ret) == "spoc-svc". Ich denke, der passende Code kommt nach type (ret) == "C-svc". [Hier] (https://github.com/cran/kernlab/blob/efd7d91521b439a993efb49cf8e71b57fae5fc5a/R/ksvm.R#L1056-L1145), nicht [hier] (https://github.com/cran/kernlab/blob/ efd7d91521b439a993efb49cf8e71b57fae5fc5a/R/ksvm.R # L1333-L1385). Recht? Beachten Sie, dass die C++ - Funktion smo_optim aufgerufen wird, nicht tron_optim – kdauria

+0

Eine verwandte [Antwort] (http://stackoverflow.com/questions/33813972/kernlab-kraziness-inconsistens-results-for-identical-problems) finden, dass 'qpsize' könnte der Schuldige sein. – kdauria

Verwandte Themen