Using an Accord.NET SVM for face recognition (MulticlassSupportVectorMachine)

こ雲淡風輕ζ 提交于 2020-04-30 08:11:55

问题


I am using OpenFace Windows binaries and Accord .NET to create a C# version of this Python-based face recognition system.

OpenFace does most of the work, I just need to train an SVM to classify an unknown face (with probability), using known faces as the output classes.

A "face" in this context is a CSV file full of face measurements. Simple enough in theory. As this seems best done with one-vs-rest methods, I am trying to work from the MulticlassSupportVectorMachine example in the API.

However, as far as I can tell, that example uses the same inputs from its training data as the inputs for testing, so I'm not sure exactly where training ends and testing begins, but I assume its at the line that calls .Decide()

Here's what I'm trying now...

-Create a few simple container classes

    public class Result
    {
        public int[] predictions;
        public double[][] scores;
        public double[][] probability;
        public double error;
        public double loss;
    }

    public class KnownFaces
    {
        public double[][] input;
        public int[] output;
    }

    public class UnknownFaces
    {
        public double[][] input;
    }`

Grab the encoding for known faces

 // Load encoding from CSV
double[] aiden1Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\aiden1.csv");
double[] aiden2Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\aiden2.csv");
...
double[] kate1Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\kate1.csv");
double[] kate2Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\kate2.csv");
...
//... etc (about 20 pictures of each person)

Grab the encoding for unknown faces

double[] who1Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\who1.csv");
double[] who2Encoding = RecognizeFace.GetEncodingFromCSV(Application.StartupPath + @"\of\processed\who2.csv");
...

Put all of this in my containers

double[][] knownFacesFeatures = {
aiden1Encoding, aiden2Encoding, ... 
kate1Encoding, kate2Encoding, ...
};

double[][] unknownFacesFeatures = {
who1Encoding, who2Encoding ... 
};

RecognizeFace.KnownFaces knownFaces = new RecognizeFace.KnownFaces();
knownFaces.input = knownFacesFeatures;

RecognizeFace.UnknownFaces unknownFaces = new RecognizeFace.UnknownFaces();
unknownFaces.input = unknownFacesFeatures;

Classify the outputs of known faces

knownFaces.output = new int[]
    {
    0,0,0 ... // Aiden
    1,1,1 ...  // Kate
    ...
    };

Get the results:

RecognizeFace.Result r = RecognizeFace.RecognizeFaces(knownFaces, unknownFaces);

...

public static Result RecognizeFaces(KnownFaces knownFaces, UnknownFaces unknownFaces)
        {
            Result toReturn = new Result();

            // Create the multi-class learning algorithm for the machine
            var teacher = new MulticlassSupportVectorLearning<Gaussian>()
            {
                // Configure the learning algorithm to use SMO to train the
                //  underlying SVMs in each of the binary class subproblems.
                Learner = (param) => new SequentialMinimalOptimization<Gaussian>()
                {
                    // Estimate a suitable guess for the Gaussian kernel's parameters.
                    // This estimate can serve as a starting point for a grid search.
                    UseKernelEstimation = true
                }
            };
            // Learn a machine
            var machine = teacher.Learn(knownFaces.input, knownFaces.output);


            // Create the multi-class learning algorithm for the machine
            var calibration = new MulticlassSupportVectorLearning<Gaussian>()
            {
                Model = machine, // We will start with an existing machine

                // Configure the learning algorithm to use Platt's calibration
                Learner = (param) => new ProbabilisticOutputCalibration<Gaussian>()
                {
                    Model = param.Model // Start with an existing machine
                }
            };



            // Configure parallel execution options
            calibration.ParallelOptions.MaxDegreeOfParallelism = 1;

            // Learn a machine
            calibration.Learn(knownFaces.input, knownFaces.output);

            // Obtain class predictions for each sample
            int[] predicted = machine.Decide(unknownFaces.input);
            toReturn.predictions = predicted;

            // Get class scores for each sample
            double[][] scores = machine.Scores(unknownFaces.input);
            toReturn.scores = scores;

            // Get log-likelihoods (should be same as scores)
            double[][] logl = machine.LogLikelihoods(unknownFaces.input);

            // Get probability for each sample
            double[][] prob = machine.Probabilities(unknownFaces.input);
            toReturn.probability = prob;

            //Compute classification error using mean accuracy (mAcc)
            //double error = new HammingLoss(knownFaces.output).Loss(predicted);
            //double loss = new CategoryCrossEntropyLoss(knownFaces.output).Loss(prob);
            //toReturn.error = error;
            //toReturn.loss = loss;

            return toReturn;

        }

The problem is that if I uncomment the error / loss lines, I get an exception,

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Accord.Math.Optimization.Losses.HammingLoss.Loss(Int32[] actual)
   at NETFaceRecognition.RecognizeFace.RecognizeFaces(KnownFaces knownFaces, UnknownFaces unknownFaces) 

and if I leave them out, the code runs... and doesn't work. If I iterate int[] predictions, I get results that are simply wrong (usually):

Unknown Person #1's class: 2 Expected: 3 (Lena)
Unknown Person #2's class: 2 Expected: 3 (Lena)
Unknown Person #3's class: 2 Expected: 2 (James)
Unknown Person #4's class: 2 Expected: 2 (James)
Unknown Person #5's class: 3 Expected: (Unknown person, incorrect result expected)
Unknown Person #6's class: 0 Expected: 3 (Lena)
Unknown Person #7's class: 1 Expected: 2 (James)
Unknown Person #8's class: 3 Expected: 1 (Kate)

The gist of my questions is: Am I implementing the class correctly, with my problem residing somewhere in my data inputs, or have I misunderstood something important? TIA


回答1:


I'm pretty sure that you're getting the error because the dimensions don't match. Moreover, I think the logical mistake here you calc loses by inappropriate data sets. You learn on knownFaces and predict by unknownFaces.

double error = new HammingLoss(knownFaces.output).Loss(predicted);

You probably need to do cross validation on known part of data that not used in train part.

Do some think like that:

double error = new HammingLoss(knownFacesForPredicted.output).Loss(predicted);


来源:https://stackoverflow.com/questions/49243301/using-an-accord-net-svm-for-face-recognition-multiclasssupportvectormachine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!