File: SynthConfigRunner.cs
Web Access
Project: src\src\Microsoft.ML.Sweeper\Microsoft.ML.Sweeper.csproj (Microsoft.ML.Sweeper)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.ML;
using Microsoft.ML.CommandLine;
using Microsoft.ML.Runtime;
using Microsoft.ML.Sweeper;
 
[assembly: LoadableClass(typeof(SynthConfigRunner), typeof(SynthConfigRunner.Options), typeof(SignatureConfigRunner),
    "", "Synth")]
 
namespace Microsoft.ML.Sweeper
{
    /// <summary>
    /// This class gives a simple way of running optimization experiments on synthetic functions, rather than on actual learning problems.
    /// It was initially created to test the sweeper methods on the Rastrigin function.
    /// </summary>
    public sealed class SynthConfigRunner : ExeConfigRunnerBase
    {
        public sealed class Options : OptionsBase
        {
            [Argument(ArgumentType.AtMostOnce, HelpText = "The number of threads to use for the sweep (default auto determined by the number of cores)", ShortName = "t")]
            public int? NumThreads;
        }
 
        private readonly ParallelOptions _parallelOptions;
 
        public SynthConfigRunner(IHostEnvironment env, Options options)
            : base(options, env, "SynthSweepEvaluator")
        {
            Host.CheckUserArg(options.NumThreads == null || options.NumThreads.Value > 0, nameof(options.NumThreads), "Must be positive");
            _parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = options.NumThreads ?? -1 };
            Host.AssertNonEmpty(options.OutputFolderName);
            ProcessFullExePath(options.Exe);
        }
 
        protected override IEnumerable<IRunResult> RunConfigsCore(ParameterSet[] sweeps, IChannel ch, int min)
        {
            List<IRunResult> results = new List<IRunResult>();
            for (int j = 0; j < sweeps.Length; j++)
            {
                double val = Rastrigin(sweeps[j]);
                results.Add(new RunResult(sweeps[j], val, true));
 
                // Write results out to files.
                string filePath = string.Format(@"{0}\{1}.out.txt", OutputFolder, min + j);
                string content = string.Format(@"{1}
 
OVERALL RESULTS
---------------------------------------
ACCURACY:            0.0000 (0.0000)
POS. PRECISION:      0.0000 (0.0000)
POS. RECALL:         0.0000 (0.0000)
NEG. PRECISION:      0.0000 (0.0000)
NEG. RECALL:         0.0000 (0.0000)
LOG-LOSS:            0.0000 (0.0000)
LOG-LOSS REDUCTION:  0.0000 (0.0000)
AUC:                 {0:#,0.0000000} (0.0000)
 
---------------------------------------
6/23/2016 11:32:57 AM	 Time elapsed(s): 1.000
", val, sweeps[j].ToString());
                var sw = new StreamWriter(filePath);
                sw.Write(content);
                sw.Flush();
                sw.Close();
            }
 
            return results;
        }
 
        /// <summary>
        /// Synthetic function used in the optimization literature to test optimization methods. Highly multi-modal,
        /// this functions causes problems for methods that get stuck at local optima (like hill-climbing methods).
        /// This synthetic function takes the place of an actual metric evaluation (hence, a synthetic runner).
        /// </summary>
        /// <param name="ps">The set of parameters to evaluate using the function.</param>
        /// <returns>The numerical evaluation of the parameter values.</returns>
        private double Rastrigin(ParameterSet ps)
        {
            double total = 0;
            foreach (var param in ps)
            {
                double val = float.Parse(param.ValueText);
                total += Math.Pow(val, 2) - 10 * Math.Cos(2 * Math.PI * val);
            }
            return (10 * ps.Count + total) > 0 ? 1.0 / (10 * ps.Count + total) : 1.0;
        }
    }
}