2011-08-24 11 views
6

Sto provando libsvm e seguo l'esempio per l'addestramento di un svm sui dati heart_scale forniti con il software. Voglio usare un kernel di chi2 che mi precalcolo. Il tasso di classificazione sui dati di allenamento scende al 24%. Sono sicuro di aver calcolato correttamente il kernel, ma suppongo di dover fare qualcosa di sbagliato. Il codice è sotto Riesci a vedere qualche errore? L'aiuto sarebbe molto apprezzato.cattivo risultato quando si utilizza il kernel chi2 precompilato con libsvm (matlab)

%read in the data: 
[heart_scale_label, heart_scale_inst] = libsvmread('heart_scale'); 
train_data = heart_scale_inst(1:150,:); 
train_label = heart_scale_label(1:150,:); 

%read somewhere that the kernel should not be sparse 
ttrain = full(train_data)'; 
ttest = full(test_data)'; 

precKernel = chi2_custom(ttrain', ttrain'); 
model_precomputed = svmtrain2(train_label, [(1:150)', precKernel], '-t 4'); 

questo è come il kernel è precalcolata:

function res=chi2_custom(x,y) 
a=size(x); 
b=size(y); 
res = zeros(a(1,1), b(1,1)); 
for i=1:a(1,1) 
    for j=1:b(1,1) 
     resHelper = chi2_ireneHelper(x(i,:), y(j,:)); 
     res(i,j) = resHelper; 
    end 
end 
function resHelper = chi2_ireneHelper(x,y) 
a=(x-y).^2; 
b=(x+y); 
resHelper = sum(a./(b + eps)); 

Con un'implementazione SVM diversa (vlfeat) posso ottenere un tasso di classificazione sui dati di allenamento (sì, ho provato con i dati di allenamento, basta per vedere cosa sta succedendo) circa il 90%. Quindi sono abbastanza sicuro che il risultato di libsvm sia sbagliato.

risposta

0

Il problema è il seguente riga:

resHelper = sum(a./(b + eps)); 

Va:

resHelper = 1-sum(2*a./(b + eps)); 
+0

grazie per la risposta alla mia domanda, ho appena visto la risposta adesso. – Sallos

+0

@Sallos: anche se la tua formula era leggermente fuori, il vero problema è la normalizzazione dei dati. Vedi la mia risposta – Amro

15

Quando si lavora con macchine support vector, è molto importante per normalizzare il set di dati come una fase di pre-processing . Normalizzazione inserisce gli attributi nella stessa scala e impedisce agli attributi con valori elevati di influenzare il risultato. Migliora anche la stabilità numerica (riduce al minimo la probabilità di overflow e underflow dovuti alla rappresentazione in virgola mobile).

Anche per essere precisi, il calcolo del kernel Chi-quadrato è leggermente fuori. Invece prendere la definizione di seguito, e utilizzare questa implementazione più veloce per esso:

chi_squared_kernel

function D = chi2Kernel(X,Y) 
    D = zeros(size(X,1),size(Y,1)); 
    for i=1:size(Y,1) 
     d = bsxfun(@minus, X, Y(i,:)); 
     s = bsxfun(@plus, X, Y(i,:)); 
     D(:,i) = sum(d.^2 ./ (s/2+eps), 2); 
    end 
    D = 1 - D; 
end 

Ora consideri il seguente esempio utilizzando lo stesso set di dati, come si (codice tratto da un previous answer di miniera):

%# read dataset 
[label,data] = libsvmread('./heart_scale'); 
data = full(data);  %# sparse to full 

%# normalize data to [0,1] range 
mn = min(data,[],1); mx = max(data,[],1); 
data = bsxfun(@rdivide, bsxfun(@minus, data, mn), mx-mn); 

%# split into train/test datasets 
trainData = data(1:150,:); testData = data(151:270,:); 
trainLabel = label(1:150,:); testLabel = label(151:270,:); 
numTrain = size(trainData,1); numTest = size(testData,1); 

%# compute kernel matrices between every pairs of (train,train) and 
%# (test,train) instances and include sample serial number as first column 
K = [ (1:numTrain)' , chi2Kernel(trainData,trainData) ]; 
KK = [ (1:numTest)' , chi2Kernel(testData,trainData) ]; 

%# view 'train vs. train' kernel matrix 
figure, imagesc(K(:,2:end)) 
colormap(pink), colorbar 

%# train model 
model = svmtrain(trainLabel, K, '-t 4'); 

%# test on testing data 
[predTestLabel, acc, decVals] = svmpredict(testLabel, KK, model); 
cmTest = confusionmat(testLabel,predTestLabel) 

%# test on training data 
[predTrainLabel, acc, decVals] = svmpredict(trainLabel, K, model); 
cmTrain = confusionmat(trainLabel,predTrainLabel) 

il risultato sui dati di test:

Accuracy = 84.1667% (101/120) (classification) 
cmTest = 
    62  8 
    11 39 

e sui dati di allenamento, si ottiene circa il 90% di precisione come vi aspettavate:

Accuracy = 92.6667% (139/150) (classification) 
cmTrain = 
    77  3 
    8 62 

train_train_kernel_matrix

+1

oh, cool - questa è una risposta dettagliata. Grazie per aver dedicato del tempo a pensare al mio problema. Ha sicuramente aiutato. – Sallos

+2

@Sallos: felice di poterti aiutare, per favore considera [accetta] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) una risposta se risolve il problema – Amro