Как реализовать двоичную классификацию SVM вручную (без использования функции прогнозирования), используя модель, обученную функцией fitcsvm? - PullRequest
0 голосов
/ 14 апреля 2020

Мне нужно реализовать двоичную классификацию SVM вручную (без использования функции прогнозирования), используя модель, обученную функцией fitcsvm. В документации по функции прогнозирования (https://www.mathworks.com/help/stats/classreg.learning.classif.compactclassificationsvm.predict.html) я нашел следующую формулу: Классификационная формула

Я реализовал эту функцию следующим образом:

function pred = svmPredict(model, X)
%SVMPREDICT returns a vector of predictions using a trained SVM model
%(fitcsvm). 
%   pred = SVMPREDICT(model, X) returns a vector of predictions using a 
%   trained SVM model (fitcsvm). X is a mxn matrix where there each 
%   example is a row. model is a svm model returned from fitcsvm.
%   predictions pred is a m x 1 column of predictions of {0, 1} values.
%

% Check if we are getting a column vector, if so, then assume that we only
% need to do prediction for a single example
if (size(X, 2) == 1)
    % Examples should be in rows
    X = X';
end

% Dataset 
m = size(X, 1);
p = zeros(m, 1);
pred = zeros(m, 1);

for i = 1:m
    prediction = 0;
    for j = 1:size(model.X, 1)
        prediction = prediction + ...
        model.alphas(j) * model.y(j) * ...
        model.kernelFunction(X(i,:)', model.X(j,:)');
    end
    p(i) = prediction + model.b;
end

% Convert predictions into 0 / 1
pred(p >= 0) =  1;
pred(p <  0) =  0;

end

Я реализовал функцию gaussianKernel следующим образом:

function sim = gaussianKernel(x1, x2, gamma)
%RBFKERNEL returns a radial basis function kernel between x1 and x2
%   sim = gaussianKernel(x1, x2) returns a gaussian kernel between x1 and x2
%   and returns the value in sim
% Ensure that x1 and x2 are column vectors
x1 = x1(:); x2 = x2(:);
% You need to return the following variables correctly.
norma = sqrt(sum((x1-x2).^2,"all"));

%sim = exp(-gamma*sum(norma,'all').^2);
sim= exp(-gamma*norma^2);

Следуя моему основному коду:

clear;
%% Load dataset from file
dataset =  readtable('cancer2.txt','PreserveVariableNames',true);
dataset = dataset{:,:}; % table to matrix
%% Preprocessing
% Shuffle examples
dataset = dataset(randperm(size(dataset, 1)),:);
% Separating features and labels
X = dataset(:,1:(end-1));
y = dataset(:,end);
% feature scaling
X = X./max(X);
%% Training, cross validation and test set
m = size(dataset,1);
aux60 = floor(m*0.6);
aux20 = floor(m*0.2);
% Training set
Xtrain = X(1:aux60,:);
ytrain = y(1:aux60,:);
% Cross validation set
Xval = X((aux60+1):(aux60+aux20),:);
yval = y((aux60+1):(aux60+aux20),:);
% Test set
Xtest = X((aux60+aux20+1):end,:);
ytest = y((aux60+aux20+1):end,:);
%% Training
% Grid search
[C,gamma] = gridSearch(Xtrain, ytrain, Xval, yval);
% Fitting
MATLABmodel = fitcsvm(Xtrain,ytrain,'KernelFunction','rbf', 'BoxConstraint',C,'KernelScale',gamma);
%% Classification 
% MATLAB function
[p1,~] = predict(MATLABmodel,Xtest);  
% My function
mymodel.X = MATLABmodel.SupportVectors;
mymodel.y = MATLABmodel.SupportVectorLabels;
gamma = MATLABmodel.KernelParameters.Scale;
mymodel.kernelFunction =  @(x1, x2)gaussianKernel(x1, x2, gamma);
mymodel.b = MATLABmodel.Bias;
mymodel.alphas = MATLABmodel.Alpha;
mymodel.w = 0; % I am using RBF kernel, so w is irrelevant
p2 = svmPredict(mymodel,Xtest);  
%% Results
fprintf('\nMATLAB predict function Test Set Accuracy: %f\n', mean(double(p1 == ytest)) * 100);
fprintf('My predict function Test Set Accuracy: %f\n', mean(double(p2 == ytest)) * 100);

Я реализовал функцию gridSearch следующим образом:

function [C, gamma] = gridSearch(X, y, Xval, yval)
%gridSearch returns your choice of C and gamma
%where you select the optimal (C, gamma) learning parameters to use for SVM
%with RBF kernel
%   [C, gamma] = gridSearch(X, y, Xval, yval) returns your choice of C and 
%   gamma.  This function to return the optimal C and gamma based on a 
%   cross-validation set.

C = 1e-2;
gamma = 1e0;
model = fitcsvm(X,y,'KernelFunction','rbf','BoxConstraint',C,'KernelScale',gamma);
[predictions,~] = predict(model,Xval); 
error = mean(double(predictions ~= yval));

Cgrid = [1e-2 1e-1 1e0 1e1 1e2 1e3];
gammagrid = [1e-7 1e-6 1e-5 1e-4 1e-3 1e-2 1e-1 1e0 1e1 1e2];
for i=1:length(Cgrid)
    for j=1:length(gammagrid)
        model = fitcsvm(X,y,'KernelFunction','rbf','BoxConstraint',Cgrid(i),'KernelScale',gammagrid(j));
        [predictions,~] = predict(model,Xval); 
        if mean(double(predictions ~= yval)) < error
            error = mean(double(predictions ~= yval));
            C = Cgrid(i);
            gamma = gammagrid(j); 
        end
    end
end
end 

«Cancer.txt» доступен в https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_breast_cancer.html

При запуске кода иногда p1 равен p2, а иногда p1 отличается от p2. Почему это происходит? Что еще делает функция предсказания для классификации примера, отличного от знака f (x)? Я пытаюсь применить это для разных наборов данных, но я получил тот же результат (иногда p1 == p2, а иногда p1 / = p2).

...