/// <summary>
        /// Initializes a new instance of the <see cref="SimpleHeadPoseEstimator"/> class with the model files to estimate head pose.
        /// </summary>
        /// <param name="rollModelFile">The model file path to estimate roll angle.</param>
        /// <param name="pitchModelFile">The model file path to estimate pitch angle.</param>
        /// <param name="yawModelFile">The model file path to estimate yaw angle.</param>
        /// <exception cref="FileNotFoundException"><paramref name="rollModelFile"/>, <paramref name="pitchModelFile"/> or <paramref name="yawModelFile"/> does not exist.</exception>
        public SimpleHeadPoseEstimator(string rollModelFile,
                                       string pitchModelFile,
                                       string yawModelFile)
        {
            if (!File.Exists(rollModelFile))
            {
                throw new FileNotFoundException($"{nameof(rollModelFile)} does not exist.", nameof(rollModelFile));
            }
            if (!File.Exists(pitchModelFile))
            {
                throw new FileNotFoundException($"{nameof(pitchModelFile)} does not exist.", nameof(pitchModelFile));
            }
            if (!File.Exists(yawModelFile))
            {
                throw new FileNotFoundException($"{nameof(yawModelFile)} does not exist.", nameof(yawModelFile));
            }

            // gamma parameter is meaningless
            this._RollKernel  = new RadialBasisKernel <double, Matrix <double> >(0.1, 0, 0);
            this._PitchKernel = new RadialBasisKernel <double, Matrix <double> >(0.1, 0, 0);
            this._YawKernel   = new RadialBasisKernel <double, Matrix <double> >(0.1, 0, 0);

            this._RollEstimator  = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(this._RollKernel);
            this._PitchEstimator = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(this._PitchKernel);
            this._YawEstimator   = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(this._YawKernel);

            Krls <double, RadialBasisKernel <double, Matrix <double> > > .Deserialize(rollModelFile, ref this._RollEstimator);

            Krls <double, RadialBasisKernel <double, Matrix <double> > > .Deserialize(pitchModelFile, ref this._PitchEstimator);

            Krls <double, RadialBasisKernel <double, Matrix <double> > > .Deserialize(yawModelFile, ref this._YawEstimator);
        }
Пример #2
0
        private static void Main()
        {
            // Here we declare that our samples will be 1 dimensional column vectors.  The reason for
            // using a matrix here is that in general you can use N dimensional vectors as inputs to the
            // krls object.  But here we only have 1 dimension to make the example simple.


            // Now we are making a typedef for the kind of kernel we want to use.  I picked the
            // radial basis kernel because it only has one parameter and generally gives good
            // results without much fiddling.


            // Here we declare an instance of the krls object.  The first argument to the constructor
            // is the kernel we wish to use.  The second is a parameter that determines the numerical
            // accuracy with which the object will perform part of the regression algorithm.  Generally
            // smaller values give better results but cause the algorithm to run slower (because it tries
            // to use more "dictionary vectors" to represent the function it is learning.
            // You just have to play with it to decide what balance of speed and accuracy is right
            // for your problem.  Here we have set it to 0.001.
            //
            // The last argument is the maximum number of dictionary vectors the algorithm is allowed
            // to use.  The default value for this field is 1,000,000 which is large enough that you
            // won't ever hit it in practice.  However, here we have set it to the much smaller value
            // of 7.  This means that once the krls object accumulates 7 dictionary vectors it will
            // start discarding old ones in favor of new ones as it goes through the training process.
            // In other words, the algorithm "forgets" about old training data and focuses on recent
            // training samples. So the bigger the maximum dictionary size the longer its memory will
            // be.  But in this example program we are doing filtering so we only care about the most
            // recent data.  So using a small value is appropriate here since it will result in much
            // faster filtering and won't introduce much error.

            using (var rbk = new RadialBasisKernel <double, Matrix <double> >(0.1, 1, 1))
                using (var test = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(rbk, 0.001))
                {
                    // now we train our object on a few samples of the sinc function.
                    using (var m = Matrix <double> .CreateTemplateParameterizeMatrix(1, 1))
                    {
                        for (double x = -10; x <= 4; x += 1)
                        {
                            m[0] = x;
                            test.Train(m, Sinc(x));
                        }

                        // now we output the value of the sinc function for a few test points as well as the
                        // value predicted by krls object.
                        m[0] = 2.5;
                        Console.WriteLine($"{Sinc(m[0])}   {test.Operator(m)}");
                        m[0] = 0.1;
                        Console.WriteLine($"{Sinc(m[0])}   {test.Operator(m)}");
                        m[0] = -4;
                        Console.WriteLine($"{Sinc(m[0])}   {test.Operator(m)}");
                        m[0] = 5.0;
                        Console.WriteLine($"{Sinc(m[0])}   {test.Operator(m)}");

                        // The output is as follows:
                        // 0.239389   0.239362
                        // 0.998334   0.998333
                        // -0.189201   -0.189201
                        // -0.191785   -0.197267


                        // The first column is the true value of t          he sinc function and the second
                        // column is the output from the krls estimate.



                        // Another thing that is worth knowing is that just about everything in dlib is serializable.
                        // So for example, you can save the test object to disk and recall it later like so:
                        Krls <double, RadialBasisKernel <double, Matrix <double> > > .Serialize(test, "saved_krls_object.dat");

                        // Now let's open that file back up and load the krls object it contains.
                        using (var rbk2 = new RadialBasisKernel <double, Matrix <double> >(0.1, 1, 1))
                        {
                            var test2 = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(rbk2, 0.001);
                            Krls <double, RadialBasisKernel <double, Matrix <double> > > .Deserialize("saved_krls_object.dat", ref test2);

                            // If you don't want to save the whole krls object (it might be a bit large)
                            // you can save just the decision function it has learned so far.  You can get
                            // the decision function out of it by calling test.get_decision_function() and
                            // then you can serialize that object instead.  E.g.
                            var funct = test2.GetDecisionFunction();
                            DecisionFunction <double, RadialBasisKernel <double, Matrix <double> > > .Serialize(funct, "saved_krls_function.dat");
                        }
                    }
                }
        }
Пример #3
0
        private static int Main()
        {
            // The svm functions use column vectors to contain a lot of the data on which they
            // operate. So the first thing we do here is declare a convenient typedef.

            // This typedef declares a matrix with 2 rows and 1 column.  It will be the object that
            // contains each of our 2 dimensional samples.   (Note that if you wanted more than 2
            // features in this vector you can simply change the 2 to something else.  Or if you
            // don't know how many features you want until runtime then you can put a 0 here and
            // use the matrix.set_size() member function)
            //typedef matrix<double, 2, 1 > sample_type;

            // This is a typedef for the type of kernel we are going to use in this example.  In
            // this case I have selected the radial basis kernel that can operate on our 2D
            // sample_type objects
            //typedef radial_basis_kernel<sample_type> kernel_type;


            // Now we make objects to contain our samples and their respective labels.
            var samples = new List <SampleType>();
            var labels  = new List <double>();

            // Now let's put some data into our samples and labels objects.  We do this by looping
            // over a bunch of points and labeling them according to their distance from the
            // origin.
            for (var r = -20; r <= 20; ++r)
            {
                for (var c = -20; c <= 20; ++c)
                {
                    var samp = new SampleType();
                    samp.SetSize(2, 1);
                    samp[0] = r;
                    samp[1] = c;
                    samples.Add(samp);

                    // if this point is less than 10 from the origin
                    if (Math.Sqrt((double)r * r + c * c) <= 10)
                    {
                        labels.Add(+1);
                    }
                    else
                    {
                        labels.Add(-1);
                    }
                }
            }


            // Here we normalize all the samples by subtracting their mean and dividing by their
            // standard deviation.  This is generally a good idea since it often heads off
            // numerical stability problems and also prevents one large feature from smothering
            // others.  Doing this doesn't matter much in this example so I'm just doing this here
            // so you can see an easy way to accomplish this with the library.
            using (var normalizer = new VectorNormalizer <SampleType>())
            {
                // let the normalizer learn the mean and standard deviation of the samples
                normalizer.Train(samples);
                // now normalize each sample
                for (var i = 0; i < samples.Count; ++i)
                {
                    var ret = normalizer.Operator(samples[i]);
                    samples[i].Dispose();
                    samples[i] = ret;
                }


                // Now that we have some data we want to train on it.  However, there are two
                // parameters to the training.  These are the nu and gamma parameters.  Our choice for
                // these parameters will influence how good the resulting decision function is.  To
                // test how good a particular choice of these parameters is we can use the
                // cross_validate_trainer() function to perform n-fold cross validation on our training
                // data.  However, there is a problem with the way we have sampled our distribution
                // above.  The problem is that there is a definite ordering to the samples.  That is,
                // the first half of the samples look like they are from a different distribution than
                // the second half.  This would screw up the cross validation process but we can fix it
                // by randomizing the order of the samples with the following function call.
                Dlib.RandomizeSamples(samples, labels);

                // The nu parameter has a maximum value that is dependent on the ratio of the +1 to -1
                // labels in the training data.  This function finds that value.
                double maxNu = Dlib.MaximumNu(labels);

                // here we make an instance of the svm_nu_trainer object that uses our kernel type.
                using (var trainer = new SvmNuTrainer <double, RadialBasisKernel <double, Matrix <double> > >())
                {
                    // Now we loop over some different nu and gamma values to see how good they are.  Note
                    // that this is a very simple way to try out a few possible parameter choices.  You
                    // should look at the model_selection_ex.cpp program for examples of more sophisticated
                    // strategies for determining good parameter choices.
                    Console.WriteLine("doing cross validation");
                    for (var gamma = 0.00001; gamma <= 1; gamma *= 5)
                    {
                        for (var nu = 0.00001; nu < maxNu; nu *= 5)
                        {
                            // tell the trainer the parameters we want to use
                            using (var kernel = new RadialBasisKernel <double, Matrix <double> >(gamma, 0, 0))
                            {
                                trainer.Kernel = kernel;
                                trainer.Nu     = nu;

                                Console.Write($"gamma: {gamma}    nu: {nu}");
                                // Print out the cross validation accuracy for 3-fold cross validation using
                                // the current gamma and nu.  cross_validate_trainer() returns a row vector.
                                // The first element of the vector is the fraction of +1 training examples
                                // correctly classified and the second number is the fraction of -1 training
                                // examples correctly classified.
                                using (var ret = Dlib.CrossValidateTrainer(trainer, samples, labels, 3))
                                    Console.Write($"     cross validation accuracy: {ret}");
                            }
                        }
                    }


                    // From looking at the output of the above loop it turns out that a good value for nu
                    // and gamma for this problem is 0.15625 for both.  So that is what we will use.

                    // Now we train on the full set of data and obtain the resulting decision function.  We
                    // use the value of 0.15625 for nu and gamma.  The decision function will return values
                    // >= 0 for samples it predicts are in the +1 class and numbers < 0 for samples it
                    // predicts to be in the -1 class.
                    using (var kernel = new RadialBasisKernel <double, Matrix <double> >(0.15625, 0, 0))
                    {
                        trainer.Kernel = kernel;
                        trainer.Nu     = 0.15625;

                        // Here we are making an instance of the normalized_function object.  This object
                        // provides a convenient way to store the vector normalization information along with
                        // the decision function we are going to learn.
                        var learnedFunction = new NormalizedFunction <double, DecisionFunction <double, RadialBasisKernel <double, Matrix <double> > > >();
                        learnedFunction.Normalizer = normalizer; // save normalization information
                        using (var function = trainer.Train(samples, labels))
                        {
                            learnedFunction.Function = function; // perform the actual SVM training and save the results

                            // print out the number of support vectors in the resulting decision function
                            Console.WriteLine();

                            // ToDo: must support nested matrix
                            //Console.WriteLine($"number of support vectors in our learned_function is {learnedFunction.Function.basis_vectors.size()}");
                        }

                        // Now let's try this decision_function on some samples we haven't seen before.
                        using (var sample = new SampleType())
                        {
                            sample.SetSize(2, 1);

                            sample[0] = 3.123;
                            sample[1] = 2;
                            Console.WriteLine($"This is a +1 class example, the classifier output is {learnedFunction.Operator(sample)}");

                            sample[0] = 3.123;
                            sample[1] = 9.3545;
                            Console.WriteLine($"This is a +1 class example, the classifier output is {learnedFunction.Operator(sample)}");

                            sample[0] = 13.123;
                            sample[1] = 9.3545;
                            Console.WriteLine($"This is a -1 class example, the classifier output is {learnedFunction.Operator(sample)}");

                            sample[0] = 13.123;
                            sample[1] = 0;
                            Console.WriteLine($"This is a -1 class example, the classifier output is {learnedFunction.Operator(sample)}");
                        }


                        // We can also train a decision function that reports a well conditioned probability
                        // instead of just a number > 0 for the +1 class and < 0 for the -1 class.  An example
                        // of doing that follows:
                        var learnedProbabilisticFunction = new NormalizedFunction <double, ProbabilisticDecisionFunction <double, RadialBasisKernel <double, Matrix <double> > > >();
                        learnedProbabilisticFunction.Normalizer = normalizer;
                        using (var function = Dlib.TrainProbabilisticDecisionFunction <double,
                                                                                       RadialBasisKernel <double, Matrix <double> >,
                                                                                       SvmNuTrainer <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, samples, labels, 3))
                        {
                            learnedProbabilisticFunction.Function = function;

                            // Now we have a function that returns the probability that a given sample is of the +1 class.

                            // print out the number of support vectors in the resulting decision function.
                            // (it should be the same as in the one above)
                            Console.WriteLine();

                            // ToDo: must support nested matrix
                            //Console.WriteLine($"number of support vectors in our learned_pfunct  is {learnedProbabilisticFunction.Function.DecisionFunct.BasisVectors.size()}");
                        }


                        using (var sample = new SampleType())
                        {
                            sample.SetSize(2, 1);

                            sample[0] = 3.123;
                            sample[1] = 2;
                            Console.WriteLine($"This +1 class example should have high probability.  Its probability is: {learnedProbabilisticFunction.Operator(sample)}");

                            sample[0] = 3.123;
                            sample[1] = 9.3545;
                            Console.WriteLine($"This +1 class example should have high probability.  Its probability is: {learnedProbabilisticFunction.Operator(sample)}");

                            sample[0] = 13.123;
                            sample[1] = 9.3545;
                            Console.WriteLine($"This -1 class example should have low probability.  Its probability is: {learnedProbabilisticFunction.Operator(sample)}");

                            sample[0] = 13.123;
                            sample[1] = 0;
                            Console.WriteLine($"This -1 class example should have low probability.  Its probability is: {learnedProbabilisticFunction.Operator(sample)}");
                        }



                        // Another thing that is worth knowing is that just about everything in dlib is
                        // serializable.  So for example, you can save the learned_pfunct object to disk and
                        // recall it later like so:
                        NormalizedFunction <double, ProbabilisticDecisionFunction <double, RadialBasisKernel <double, Matrix <double> > > > .Serialize("saved_function.dat", learnedProbabilisticFunction);

                        // Now let's open that file back up and load the function object it contains.
                        learnedProbabilisticFunction.Dispose();
                        learnedProbabilisticFunction = NormalizedFunction <double, ProbabilisticDecisionFunction <double, RadialBasisKernel <double, Matrix <double> > > > .Deserialize("saved_function.dat");

                        // Note that there is also an example program that comes with dlib called
                        // the file_to_code_ex.cpp example.  It is a simple program that takes a
                        // file and outputs a piece of C++ code that is able to fully reproduce the
                        // file's contents in the form of a std::string object.  So you can use that
                        // along with the std::istringstream to save learned decision functions
                        // inside your actual C++ code files if you want.



                        // Note that there is also an example program that comes with dlib called the
                        // file_to_code_ex.cpp example.  It is a simple program that takes a file and outputs a
                        // piece of C++ code that is able to fully reproduce the file's contents in the form of
                        // a std::string object.  So you can use that along with the std::istringstream to save
                        // learned decision functions inside your actual C++ code files if you want.



                        // Lastly, note that the decision functions we trained above involved well over 200
                        // basis vectors.  Support vector machines in general tend to find decision functions
                        // that involve a lot of basis vectors.  This is significant because the more basis
                        // vectors in a decision function, the longer it takes to classify new examples.  So
                        // dlib provides the ability to find an approximation to the normal output of a trainer
                        // using fewer basis vectors.

                        // Here we determine the cross validation accuracy when we approximate the output using
                        // only 10 basis vectors.  To do this we use the reduced2() function.  It takes a
                        // trainer object and the number of basis vectors to use and returns a new trainer
                        // object that applies the necessary post processing during the creation of decision
                        // function objects.
                        using (var reduced = Dlib.Reduced2 <double,
                                                            RadialBasisKernel <double, Matrix <double> >,
                                                            SvmNuTrainer <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, 10))
                        {
                            Console.WriteLine();
                            using (var ret = Dlib.CrossValidateTrainer(reduced, samples, labels, 3))
                                Console.Write($"cross validation accuracy with only 10 support vectors: {ret}");
                        }

                        // Let's print out the original cross validation score too for comparison.
                        using (var ret2 = Dlib.CrossValidateTrainer(trainer, samples, labels, 3))
                            Console.Write($"cross validation accuracy with all the original support vectors: {ret2}");

                        // When you run this program you should see that, for this problem, you can reduce the
                        // number of basis vectors down to 10 without hurting the cross validation accuracy.


                        // To get the reduced decision function out we would just do this:
                        using (var reduced = Dlib.Reduced2 <double,
                                                            RadialBasisKernel <double, Matrix <double> >,
                                                            SvmNuTrainer <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, 10))
                            using (var function = reduced.Train(samples, labels))
                                learnedFunction.Function = function;
                        // And similarly for the probabilistic_decision_function:
                        using (var reduced = Dlib.Reduced2 <double,
                                                            RadialBasisKernel <double, Matrix <double> >,
                                                            SvmNuTrainer <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, 10))
                            using (var function = Dlib.TrainProbabilisticDecisionFunction(reduced, samples, labels, 3))
                                learnedProbabilisticFunction.Function = function;

                        learnedFunction.Dispose();
                        learnedProbabilisticFunction.Dispose();
                    }
                }
            }


            return(0);
        }
Пример #4
0
        private static int Main()
        {
            // The svm functions use column vectors to contain a lot of the data on which they
            // operate. So the first thing we do here is declare a convenient typedef.

            // This typedef declares a matrix with 2 rows and 1 column.  It will be the
            // object that contains each of our 2 dimensional samples.   (Note that if you wanted
            // more than 2 features in this vector you can simply change the 2 to something else.
            // Or if you don't know how many features you want until runtime then you can put a 0
            // here and use the matrix.set_size() member function)
            //typedef matrix<double, 2, 1 > sample_type;

            // This is a typedef for the type of kernel we are going to use in this example.
            // In this case I have selected the radial basis kernel that can operate on our
            // 2D sample_type objects
            //typedef radial_basis_kernel<sample_type> kernel_type;


            // Here we create an instance of the pegasos svm trainer object we will be using.
            using (var trainer = new SvmPegasos <double, RadialBasisKernel <double, Matrix <double> > >())
                using (var kernel = new RadialBasisKernel <double, Matrix <double> >(0.005, 0, 0))
                {
                    // Here we setup the parameters to this object.  See the dlib documentation for a
                    // description of what these parameters are.
                    trainer.SetLambda(0.00001);
                    trainer.Kernel = kernel;

                    // Set the maximum number of support vectors we want the trainer object to use
                    // in representing the decision function it is going to learn.  In general,
                    // supplying a bigger number here will only ever give you a more accurate
                    // answer.  However, giving a smaller number will make the algorithm run
                    // faster and decision rules that involve fewer support vectors also take
                    // less time to evaluate.
                    trainer.MaxNumSupportVector = 10;

                    var samples = new List <SampleType>();
                    var labels  = new List <double>();

                    // make an instance of a sample matrix so we can use it below
                    var center = new SampleType();
                    center.SetSize(2, 1);
                    center.Assign(new[] { 20d, 20d });

                    // Now let's go into a loop and randomly generate 1000 samples.
                    Dlib.SRand((uint)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds);
                    for (var i = 0; i < 10000; ++i)
                    {
                        // Make a random sample vector.
                        using (var r = Dlib.RandM(2, 1))
                        {
                            var sample = r * 40 - center;

                            // Now if that random vector is less than 10 units from the origin then it is in
                            // the +1 class.
                            if (Dlib.Length(sample) <= 10)
                            {
                                // let the svm_pegasos learn about this sample
                                trainer.Train(sample, +1);

                                // save this sample so we can use it with the batch training examples below
                                samples.Add(sample);
                                labels.Add(+1);
                            }
                            else
                            {
                                // let the svm_pegasos learn about this sample
                                trainer.Train(sample, -1);

                                // save this sample so we can use it with the batch training examples below
                                samples.Add(sample);
                                labels.Add(-1);
                            }
                        }
                    }

                    // Now we have trained our SVM.  Let's see how well it did.
                    // Each of these statements prints out the output of the SVM given a particular sample.
                    // The SVM outputs a number > 0 if a sample is predicted to be in the +1 class and < 0
                    // if a sample is predicted to be in the -1 class.

                    // Now let's try this decision_function on some samples we haven't seen before.
                    using (var sample = new SampleType())
                    {
                        sample.SetSize(2, 1);

                        sample[0] = 3.123;
                        sample[1] = 4;
                        Console.WriteLine($"This is a +1 example, its SVM output is: {trainer.Operator(sample)}");

                        sample[0] = 13.123;
                        sample[1] = 9.3545;
                        Console.WriteLine($"This is a -1 example, its SVM output is: {trainer.Operator(sample)}");

                        sample[0] = 13.123;
                        sample[1] = 0;
                        Console.WriteLine($"This is a -1 example, its SVM output is: {trainer.Operator(sample)}");
                    }



                    // The previous part of this example program showed you how to perform online training
                    // with the pegasos algorithm.  But it is often the case that you have a dataset and you
                    // just want to perform batch learning on that dataset and get the resulting decision
                    // function.  To support this the dlib library provides functions for converting an online
                    // training object like svm_pegasos into a batch training object.

                    // First let's clear out anything in the trainer object.
                    trainer.Clear();

                    // Now to begin with, you might want to compute the cross validation score of a trainer object
                    // on your data.  To do this you should use the batch_cached() function to convert the svm_pegasos object
                    // into a batch training object.  Note that the second argument to batch_cached() is the minimum
                    // learning rate the trainer object must report for the batch_cached() function to consider training
                    // complete.  So smaller values of this parameter cause training to take longer but may result
                    // in a more accurate solution.
                    // Here we perform 4-fold cross validation and print the results
                    using (var batchTrainer = Dlib.BatchCached <double,
                                                                RadialBasisKernel <double, Matrix <double> >,
                                                                SvmPegasos <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, 0.1))
                        using (var ret = Dlib.CrossValidateTrainer(batchTrainer, samples, labels, 4))
                            Console.Write($"cross validation: {ret}");

                    // Here is an example of creating a decision function.  Note that we have used the verbose_batch_cached()
                    // function instead of batch_cached() as above.  They do the same things except verbose_batch_cached() will
                    // print status messages to standard output while training is under way.
                    using (var verboseBatchCached = Dlib.VerboseBatchCached <double,
                                                                             RadialBasisKernel <double, Matrix <double> >,
                                                                             SvmPegasos <double, RadialBasisKernel <double, Matrix <double> > > >(trainer, 0.1))
                        using (var df = verboseBatchCached.Train(samples, labels))
                            using (var sample = new SampleType())
                            {
                                sample.SetSize(2, 1);

                                sample[0] = 3.123;
                                sample[1] = 4;
                                Console.WriteLine($"This is a +1 example, its SVM output is: {df.Operator(sample)}");

                                sample[0] = 13.123;
                                sample[1] = 9.3545;
                                Console.WriteLine($"This is a -1 example, its SVM output is: {df.Operator(sample)}");

                                sample[0] = 13.123;
                                sample[1] = 0;
                                Console.WriteLine($"This is a -1 example, its SVM output is: {df.Operator(sample)}");
                            }
                }

            return(0);
        }
Пример #5
0
        private static void Main()
        {
            // Here we declare that our samples will be 1 dimensional column vectors.  The reason for
            // using a matrix here is that in general you can use N dimensional vectors as inputs to the
            // krls object.  But here we only have 1 dimension to make the example simple.


            // Now we are making a typedef for the kind of kernel we want to use.  I picked the
            // radial basis kernel because it only has one parameter and generally gives good
            // results without much fiddling.


            // Here we declare an instance of the krls object.  The first argument to the constructor
            // is the kernel we wish to use.  The second is a parameter that determines the numerical
            // accuracy with which the object will perform part of the regression algorithm.  Generally
            // smaller values give better results but cause the algorithm to run slower (because it tries
            // to use more "dictionary vectors" to represent the function it is learning.
            // You just have to play with it to decide what balance of speed and accuracy is right
            // for your problem.  Here we have set it to 0.001.
            //
            // The last argument is the maximum number of dictionary vectors the algorithm is allowed
            // to use.  The default value for this field is 1,000,000 which is large enough that you
            // won't ever hit it in practice.  However, here we have set it to the much smaller value
            // of 7.  This means that once the krls object accumulates 7 dictionary vectors it will
            // start discarding old ones in favor of new ones as it goes through the training process.
            // In other words, the algorithm "forgets" about old training data and focuses on recent
            // training samples. So the bigger the maximum dictionary size the longer its memory will
            // be.  But in this example program we are doing filtering so we only care about the most
            // recent data.  So using a small value is appropriate here since it will result in much
            // faster filtering and won't introduce much error.

            using (var rbk = new RadialBasisKernel <double, Matrix <double> >(0.05, 1, 1))
                using (var test = new Krls <double, RadialBasisKernel <double, Matrix <double> > >(rbk, 0.001, 7))
                {
                    using (var rnd = new Rand())
                    {
                        // Now let's loop over a big range of values from the sinc() function.  Each time
                        // adding some random noise to the data we send to the krls object for training.
                        using (var m = Matrix <double> .CreateTemplateParameterizeMatrix(1, 1))
                        {
                            double mseNoise = 0;
                            double mse      = 0;
                            double count    = 0;
                            for (double x = -20; x <= 20; x += 0.01)
                            {
                                m[0] = x;
                                // get a random number between -0.5 and 0.5
                                double noise = rnd.GetRandomDouble() - 0.5;

                                // train on this new sample
                                test.Train(m, Sinc(x) + noise);

                                // once we have seen a bit of data start measuring the mean squared prediction error.
                                // Also measure the mean squared error due to the noise.
                                if (x > -19)
                                {
                                    ++count;
                                    mse      += Math.Pow(Sinc(x) - test.Operator(m), 2);
                                    mseNoise += Math.Pow(noise, 2);
                                }
                            }

                            mse      /= count;
                            mseNoise /= count;

                            // Output the ratio of the error from the noise and the mean squared prediction error.
                            Console.WriteLine($"prediction error:                   {mse}");
                            Console.WriteLine($"noise:                              {mseNoise}");
                            Console.WriteLine($"ratio of noise to prediction error: {mseNoise / mse}");

                            // When the program runs it should print the following:
                            //    prediction error:                   0.00735201
                            //    noise:                              0.0821628
                            //    ratio of noise to prediction error: 11.1756

                            // And we see that the noise has been significantly reduced by filtering the points
                            // through the krls object.
                        }
                    }
                }
        }
Пример #6
0
        private static void Main()
        {
            // Here we declare that our samples will be 2 dimensional column vectors.
            // (Note that if you don't know the dimensionality of your vectors at compile time
            // you can change the 2 to a 0 and then set the size at runtime)

            // Now we are making a typedef for the kind of kernel we want to use.  I picked the
            // radial basis kernel because it only has one parameter and generally gives good
            // results without much fiddling.
            using (var rbk = new RadialBasisKernel <double, Matrix <double> >(0.1d, 2, 1))
            {
                // Here we declare an instance of the kcentroid object.  The kcentroid has 3 parameters
                // you need to set.  The first argument to the constructor is the kernel we wish to
                // use.  The second is a parameter that determines the numerical accuracy with which
                // the object will perform the centroid estimation.  Generally, smaller values
                // give better results but cause the algorithm to attempt to use more dictionary vectors
                // (and thus run slower and use more memory).  The third argument, however, is the
                // maximum number of dictionary vectors a kcentroid is allowed to use.  So you can use
                // it to control the runtime complexity.
                using (var test = new KCentroid <double, RadialBasisKernel <double, Matrix <double> > >(rbk, 0.01, 15))
                {
                    // now we train our object on a few samples of the sinc function.
                    using (var m = Matrix <double> .CreateTemplateParameterizeMatrix(2, 1))
                    {
                        for (double x = -15; x <= 8; x += 1)
                        {
                            m[0] = x;
                            m[1] = Sinc(x);
                            test.Train(m);
                        }

                        using (var rs = new RunningStats <double>())
                        {
                            // Now let's output the distance from the centroid to some points that are from the sinc function.
                            // These numbers should all be similar.  We will also calculate the statistics of these numbers
                            // by accumulating them into the running_stats object called rs.  This will let us easily
                            // find the mean and standard deviation of the distances for use below.
                            Console.WriteLine("Points that are on the sinc function:");
                            m[0] = -1.5; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -1.5; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -0;   m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -0.5; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -4.1; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -1.5; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));
                            m[0] = -0.5; m[1] = Sinc(m[0]); Console.WriteLine($"   {test.Operator(m)}"); rs.Add(test.Operator(m));

                            Console.WriteLine();
                            // Let's output the distance from the centroid to some points that are NOT from the sinc function.
                            // These numbers should all be significantly bigger than previous set of numbers.  We will also
                            // use the rs.scale() function to find out how many standard deviations they are away from the
                            // mean of the test points from the sinc function.  So in this case our criterion for "significantly bigger"
                            // is > 3 or 4 standard deviations away from the above points that actually are on the sinc function.
                            Console.WriteLine("Points that are NOT on the sinc function:");
                            m[0] = -1.5; m[1] = Sinc(m[0]) + 4;   Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -1.5; m[1] = Sinc(m[0]) + 3;   Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -0;   m[1] = -Sinc(m[0]);      Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -0.5; m[1] = -Sinc(m[0]);      Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -4.1; m[1] = Sinc(m[0]) + 2;   Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -1.5; m[1] = Sinc(m[0]) + 0.9; Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");
                            m[0] = -0.5; m[1] = Sinc(m[0]) + 1;   Console.WriteLine($"   {test.Operator(m)} is {rs.Scale(test.Operator(m))} standard deviations from sinc.");

                            // And finally print out the mean and standard deviation of points that are actually from sinc().
                            Console.WriteLine($"\nmean: {rs.Mean}");
                            Console.WriteLine($"standard deviation: {rs.StdDev}");

                            // The output is as follows:

                            /*
                             *  Points that are on the sinc function:
                             *      0.869913
                             *      0.869913
                             *      0.873408
                             *      0.872807
                             *      0.870432
                             *      0.869913
                             *      0.872807
                             *
                             *  Points that are NOT on the sinc function:
                             *      1.06366 is 119.65 standard deviations from sinc.
                             *      1.02212 is 93.8106 standard deviations from sinc.
                             *      0.921382 is 31.1458 standard deviations from sinc.
                             *      0.918439 is 29.3147 standard deviations from sinc.
                             *      0.931428 is 37.3949 standard deviations from sinc.
                             *      0.898018 is 16.6121 standard deviations from sinc.
                             *      0.914425 is 26.8183 standard deviations from sinc.
                             *
                             *      mean: 0.871313
                             *      standard deviation: 0.00160756
                             */

                            // So we can see that in this example the kcentroid object correctly indicates that
                            // the non-sinc points are definitely not points from the sinc function.
                        }
                    }
                }
            }
        }
Пример #7
0
        private static void Main()
        {
            // Here we declare that our samples will be 2 dimensional column vectors.
            // (Note that if you don't know the dimensionality of your vectors at compile time
            // you can change the 2 to a 0 and then set the size at runtime)

            // Now we are making a typedef for the kind of kernel we want to use.  I picked the
            // radial basis kernel because it only has one parameter and generally gives good
            // results without much fiddling.
            using (var rbk = new RadialBasisKernel <double, Matrix <double> >(0.1d, 2, 1))
            {
                // Here we declare an instance of the kcentroid object.  It is the object used to
                // represent each of the centers used for clustering.  The kcentroid has 3 parameters
                // you need to set.  The first argument to the constructor is the kernel we wish to
                // use.  The second is a parameter that determines the numerical accuracy with which
                // the object will perform part of the learning algorithm.  Generally, smaller values
                // give better results but cause the algorithm to attempt to use more dictionary vectors
                // (and thus run slower and use more memory).  The third argument, however, is the
                // maximum number of dictionary vectors a kcentroid is allowed to use.  So you can use
                // it to control the runtime complexity.
                using (var kc = new KCentroid <double, RadialBasisKernel <double, Matrix <double> > >(rbk, 0.01, 8))
                {
                    // Now we make an instance of the kkmeans object and tell it to use kcentroid objects
                    // that are configured with the parameters from the kc object we defined above.

                    using (var test = new KKMeans <double, RadialBasisKernel <double, Matrix <double> > >(kc))
                    {
                        var samples = new List <Matrix <double> >();

                        using (var m = Matrix <double> .CreateTemplateParameterizeMatrix(2, 1))
                            using (var rnd = new Rand())
                            {
                                // we will make 50 points from each class
                                const int num = 50;

                                // make some samples near the origin
                                var radius = 0.5d;
                                for (var i = 0; i < num; ++i)
                                {
                                    double sign = 1;
                                    if (rnd.GetRandomDouble() < 0.5)
                                    {
                                        sign = -1;
                                    }
                                    m[0] = 2 * radius * rnd.GetRandomDouble() - radius;
                                    m[1] = sign * Math.Sqrt(radius * radius - m[0] * m[0]);

                                    // add this sample to our set of samples we will run k-means
                                    samples.Add(m.Clone());
                                }

                                // make some samples in a circle around the origin but far away
                                radius = 10.0;
                                for (var i = 0; i < num; ++i)
                                {
                                    double sign = 1;
                                    if (rnd.GetRandomDouble() < 0.5)
                                    {
                                        sign = -1;
                                    }
                                    m[0] = 2 * radius * rnd.GetRandomDouble() - radius;
                                    m[1] = sign * Math.Sqrt(radius * radius - m[0] * m[0]);

                                    // add this sample to our set of samples we will run k-means
                                    samples.Add(m.Clone());
                                }

                                // make some samples in a circle around the point (25,25)
                                radius = 4.0;
                                for (var i = 0; i < num; ++i)
                                {
                                    double sign = 1;
                                    if (rnd.GetRandomDouble() < 0.5)
                                    {
                                        sign = -1;
                                    }
                                    m[0] = 2 * radius * rnd.GetRandomDouble() - radius;
                                    m[1] = sign * Math.Sqrt(radius * radius - m[0] * m[0]);

                                    // translate this point away from the origin
                                    m[0] += 25;
                                    m[1] += 25;

                                    // add this sample to our set of samples we will run k-means
                                    samples.Add(m.Clone());
                                }

                                // tell the kkmeans object we made that we want to run k-means with k set to 3.
                                // (i.e. we want 3 clusters)
                                test.NumberOfCenters = 3;

                                // You need to pick some initial centers for the k-means algorithm.  So here
                                // we will use the dlib::pick_initial_centers() function which tries to find
                                // n points that are far apart (basically).
                                var initialCenters = Dlib.PickInitialCenters(3, samples, test.Kernel);

                                // now run the k-means algorithm on our set of samples.
                                test.Train(samples, initialCenters);

                                // now loop over all our samples and print out their predicted class.  In this example
                                // all points are correctly identified.
                                for (var i = 0; i < samples.Count / 3; ++i)
                                {
                                    Console.Write($"{test.Operator(samples[i])} ");
                                    Console.Write($"{test.Operator(samples[i + num])} ");
                                    Console.WriteLine($"{test.Operator(samples[i + 2 * num])}");
                                }

                                // Now print out how many dictionary vectors each center used.  Note that
                                // the maximum number of 8 was reached.  If you went back to the kcentroid
                                // constructor and changed the 8 to some bigger number you would see that these
                                // numbers would go up.  However, 8 is all we need to correctly cluster this dataset.
                                Console.WriteLine($"num dictionary vectors for center 0: {test.GetKCentroid(0).DictionarySize}");
                                Console.WriteLine($"num dictionary vectors for center 1: {test.GetKCentroid(1).DictionarySize}");
                                Console.WriteLine($"num dictionary vectors for center 2: {test.GetKCentroid(2).DictionarySize}");


                                // Finally, we can also solve the same kind of non-linear clustering problem with
                                // spectral_cluster().  The output is a vector that indicates which cluster each sample
                                // belongs to.  Just like with kkmeans, it assigns each point to the correct cluster.
                                using (var tmp = new RadialBasisKernel <double, Matrix <double> >(0.1, 2, 1))
                                {
                                    var assignments = Dlib.SpectralCluster(tmp, samples, 3);
                                    using (var mat = Dlib.Mat(assignments))
                                        Console.WriteLine($"{mat}");
                                }
                            }

                        samples.DisposeElement();
                    }
                }
            }
        }