2011-08-24 5 views
6

Estoy probando libsvm y sigo el ejemplo para entrenar un svm en los datos heart_scale que vienen con el software. Quiero usar un kernel chi2 que me precomputo a mí mismo. La tasa de clasificación en los datos de entrenamiento cae al 24%. Estoy seguro de que calculo el kernel correctamente, pero supongo que debo estar haciendo algo mal. El código está abajo. ¿Puedes ver algún error? La ayuda sería muy apreciada.mal resultado al usar un kernel chi2 precalculado 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'); 

Así es como se precalculados el núcleo:

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 una aplicación SVM diferente (vlfeat) puedo obtener una tasa de clasificación de los datos de entrenamiento (sí, he probado en los datos de entrenamiento, simplemente para ver qué está pasando) alrededor del 90%. Así que estoy bastante seguro de que el resultado de libsvm es incorrecto.

Respuesta

0

El problema es la línea siguiente:

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

que debe ser:

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

gracias por responder a mi pregunta, acabo de ver su respuesta ahora. – Sallos

+0

@Sallos: aunque su fórmula estaba un poco apagada, el problema real es la normalización de los datos. Ver mi respuesta – Amro

15

Cuando se trabaja con máquinas de vectores de soporte, que es muy importante para normalizar el conjunto de datos como una etapa de pre-procesamiento . La normalización pone los atributos en la misma escala y evita que los atributos con valores grandes predispongan al resultado. También mejora la estabilidad numérica (minimiza la probabilidad de desbordamientos y subdesbordamientos debido a la representación en coma flotante).

También para ser exactos, su cálculo del kernel Chi-cuadrado está ligeramente apagado. En su lugar tomar la definición más abajo, y utilizar esta implementación más rápida para ello:

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 

Ahora consideremos el siguiente ejemplo utilizando el mismo conjunto de datos como usted (código de una adaptación de una previous answer mío):

%# 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) 

el resultado de la prueba de los datos:

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

y en los datos de entrenamiento, obtenemos alrededor del 90% de precisión como se esperaba:

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

train_train_kernel_matrix

+1

¡vaya! Genial, esa es una respuesta detallada. Gracias por tomarse el tiempo para pensar en mi problema. Sin duda ayudó. – Sallos

+2

@Sallos: me alegro de poder ayudar, por favor considere [aceptar] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) una respuesta si resuelve el problema – Amro