2012-01-21 16 views
12

So che LIBSVM consente solo la classificazione uno contro uno quando si tratta di SVM multi-classe. Tuttavia, mi piacerebbe modificarlo un po 'per eseguire una classificazione univoca. Ho provato a eseguire uno contro tutti sotto. È questo l'approccio corretto?SVM multi-classe (uno contro tutti)

Il codice:

TrainLabel;TrainVec;TestVec;TestLaBel; 
u=unique(TrainLabel); 
N=length(u); 
if(N>2) 
    itr=1; 
    classes=0; 
    while((classes~=1)&&(itr<=length(u))) 
     c1=(TrainLabel==u(itr)); 
     newClass=c1; 
     model = svmtrain(TrainLabel, TrainVec, '-c 1 -g 0.00154'); 
     [predict_label, accuracy, dec_values] = svmpredict(TestLabel, TestVec, model); 
     itr=itr+1; 
    end 
itr=itr-1; 
end 

avrei potuto fare qualche errore. Mi piacerebbe sentire un feedback. Grazie.

Seconda parte: Come il moscone ha detto: Ho bisogno di fare Sum-pooling (o voto come soluzione semplificata) per fornire la risposta finale. Non sono sicuro di come farlo. Ho bisogno di aiuto su di esso; Ho visto il file Python ma non sono ancora molto sicuro. Ho bisogno di aiuto.

+0

Qual è la domanda esattamente? Stai chiedendo come eseguire la classificazione one-vs-all con LibSVM? Il programma produce il risultato che ti aspettavi? A proposito, i parametri LibSVM dovrebbero essere ''-c 1 -g 0.00153'' (mancava la virgoletta singola finale). – grapeot

+0

ho modificato la domanda ... – lakesh

+1

@lakesh: Ho postato una risposta a una domanda simile, potresti trovare utile: http://stackoverflow.com/a/9049808/97160 – Amro

risposta

10
%# Fisher Iris dataset 
load fisheriris 
[~,~,labels] = unique(species); %# labels: 1/2/3 
data = zscore(meas);    %# scale features 
numInst = size(data,1); 
numLabels = max(labels); 

%# split training/testing 
idx = randperm(numInst); 
numTrain = 100; numTest = numInst - numTrain; 
trainData = data(idx(1:numTrain),:); testData = data(idx(numTrain+1:end),:); 
trainLabel = labels(idx(1:numTrain)); testLabel = labels(idx(numTrain+1:end)); 
%# train one-against-all models 
model = cell(numLabels,1); 
for k=1:numLabels 
    model{k} = svmtrain(double(trainLabel==k), trainData, '-c 1 -g 0.2 -b 1'); 
end 

%# get probability estimates of test instances using each model 
prob = zeros(numTest,numLabels); 
for k=1:numLabels 
    [~,~,p] = svmpredict(double(testLabel==k), testData, model{k}, '-b 1'); 
    prob(:,k) = p(:,model{k}.Label==1); %# probability of class==k 
end 

%# predict the class with the highest probability 
[~,pred] = max(prob,[],2); 
acc = sum(pred == testLabel) ./ numel(testLabel) %# accuracy 
C = confusionmat(testLabel, pred)     %# confusion matrix 
4

Dal codice vedo che stai provando a trasformare le etichette prima in "qualche classe" rispetto a "non in questa classe", quindi invoca LibSVM per fare addestramento e test. Alcune domande e suggerimenti:

  1. Perché stai utilizzando l'originale TrainingLabel per l'allenamento? Secondo me, dovrebbe essere model = svmtrain(newClass, TrainVec, '-c 1 -g 0.00154');?
  2. Con il meccanismo di allenamento modificato, è inoltre necessario modificare la parte di previsione, ad esempio utilizzando la somma di pool per determinare l'etichetta finale. L'utilizzo dello switch -b in LibSVM per abilitare l'output di probabilità migliorerà anche la precisione.
+0

grazie mille ... btw, fai sai fare uno contro uno usando LIBSVM? Non sono sicuro di come farlo ... – lakesh

+1

Inserire semplicemente etichette diverse da 0 <=> 1 o -1 <=> 1 come input va bene. LibSVM lo riconoscerà e tenterà di fare una classificazione multi-classe. – grapeot

+0

allora quello è uno contro uno? – lakesh

1

Invece di stime di probabilità, è anche possibile utilizzare i valori decisionali come segue

[~,~,d] = svmpredict(double(testLabel==k), testData, model{k}); 
prob(:,k) = d * (2 * model{i}.Label(1) - 1); 

per raggiungere lo stesso scopo.