// [cdm 2012: The version that used to be here was clearly buggy;
        // I changed it a little, but didn't test it. It's now more correct, but
        // I think it is still conceptually faulty, since it will keep growing the
        // batch size so long as any minute improvement in the function value is
        // obtained, whereas the whole point of using a small batch is to get speed
        // at the cost of small losses.]
        public virtual int TuneBatch(Func function, double[] initial, long msPerTest, int bStart)
        {
            double[] xTest = new double[initial.Length];
            int      bOpt  = 0;
            double   min   = double.PositiveInfinity;

            this.maxTime = msPerTest;
            double prev = double.PositiveInfinity;

            // check for stochastic derivatives
            if (!(function is AbstractStochasticCachingDiffFunction))
            {
                throw new NotSupportedException();
            }
            AbstractStochasticCachingDiffFunction dFunction = (AbstractStochasticCachingDiffFunction)function;
            int  b          = bStart;
            bool toContinue = true;

            do
            {
                System.Array.Copy(initial, 0, xTest, 0, initial.Length);
                log.Info(string.Empty);
                log.Info("Testing with batch size:  " + b);
                bSize = b;
                ShutUp();
                this.Minimize(function, 1e-5, xTest);
                double result = dFunction.ValueAt(xTest);
                if (result < min)
                {
                    min  = result;
                    bOpt = bSize;
                    b   *= 2;
                    prev = result;
                }
                else
                {
                    if (result < prev)
                    {
                        b   *= 2;
                        prev = result;
                    }
                    else
                    {
                        if (result > prev)
                        {
                            toContinue = false;
                        }
                    }
                }
                log.Info(string.Empty);
                log.Info("Final value is: " + nf.Format(result));
                log.Info("Optimal so far is:  batch size: " + bOpt);
            }while (toContinue);
            return(bOpt);
        }
Пример #2
0
        /// <summary>
        /// This function tests to make sure that the sum of the stochastic calculated gradients is equal to the
        /// full gradient.
        /// </summary>
        /// <remarks>
        /// This function tests to make sure that the sum of the stochastic calculated gradients is equal to the
        /// full gradient.  This requires using ordered sampling, so if the ObjectiveFunction itself randomizes
        /// the inputs this function will likely fail.
        /// </remarks>
        /// <param name="x">is the point to evaluate the function at</param>
        /// <param name="functionTolerance">is the tolerance to place on the infinity norm of the gradient and value</param>
        /// <returns>boolean indicating success or failure.</returns>
        public virtual bool TestSumOfBatches(double[] x, double functionTolerance)
        {
            bool ret = false;

            log.Info("Making sure that the sum of stochastic gradients equals the full gradient");
            AbstractStochasticCachingDiffFunction.SamplingMethod tmpSampleMethod = thisFunc.sampleMethod;
            StochasticCalculateMethods tmpMethod = thisFunc.method;

            //Make sure that our function is using ordered sampling.  Otherwise we have no gaurentees.
            thisFunc.sampleMethod = AbstractStochasticCachingDiffFunction.SamplingMethod.Ordered;
            if (thisFunc.method == StochasticCalculateMethods.NoneSpecified)
            {
                log.Info("No calculate method has been specified");
            }
            approxValue = 0;
            approxGrad  = new double[x.Length];
            curGrad     = new double[x.Length];
            fullGrad    = new double[x.Length];
            double percent = 0.0;

            //This loop runs through all the batches and sums of the calculations to compare against the full gradient
            for (int i = 0; i < numBatches; i++)
            {
                percent = 100 * ((double)i) / (numBatches);
                //  update the value
                approxValue += thisFunc.ValueAt(x, v, testBatchSize);
                //  update the gradient
                thisFunc.returnPreviousValues = true;
                System.Array.Copy(thisFunc.DerivativeAt(x, v, testBatchSize), 0, curGrad, 0, curGrad.Length);
                //Update Approximate
                approxGrad = ArrayMath.PairwiseAdd(approxGrad, curGrad);
                double norm = ArrayMath.Norm(approxGrad);
                System.Console.Error.Printf("%5.1f percent complete  %6.2f \n", percent, norm);
            }
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // Get the full gradient and value, these should equal the approximates
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            log.Info("About to calculate the full derivative and value");
            System.Array.Copy(thisFunc.DerivativeAt(x), 0, fullGrad, 0, fullGrad.Length);
            thisFunc.returnPreviousValues = true;
            fullValue = thisFunc.ValueAt(x);
            diff      = new double[x.Length];
            if ((ArrayMath.Norm_inf(diff = ArrayMath.PairwiseSubtract(fullGrad, approxGrad))) < functionTolerance)
            {
                Sayln(string.Empty);
                Sayln("Success: sum of batch gradients equals full gradient");
                ret = true;
            }
            else
            {
                diffNorm = ArrayMath.Norm(diff);
                Sayln(string.Empty);
                Sayln("Failure: sum of batch gradients minus full gradient has norm " + diffNorm);
                ret = false;
            }
            if (System.Math.Abs(approxValue - fullValue) < functionTolerance)
            {
                Sayln(string.Empty);
                Sayln("Success: sum of batch values equals full value");
                ret = true;
            }
            else
            {
                Sayln(string.Empty);
                Sayln("Failure: sum of batch values minus full value has norm " + System.Math.Abs(approxValue - fullValue));
                ret = false;
            }
            thisFunc.sampleMethod = tmpSampleMethod;
            thisFunc.method       = tmpMethod;
            return(ret);
        }
        public virtual double[] Minimize(Func function, double functionTolerance, double[] initial, int maxIterations)
        {
            // check for stochastic derivatives
            if (!(function is AbstractStochasticCachingDiffFunction))
            {
                throw new NotSupportedException();
            }
            AbstractStochasticCachingDiffFunction dfunction = (AbstractStochasticCachingDiffFunction)function;

            dfunction.method = StochasticCalculateMethods.GradientOnly;

            /* ---
            *  StochasticDiffFunctionTester sdft = new StochasticDiffFunctionTester(dfunction);
            *  ArrayMath.add(initial, gen.nextDouble() ); // to make sure that priors are working.
            *  sdft.testSumOfBatches(initial, 1e-4);
            *  System.exit(1);
            *  --- */
            x               = initial;
            grad            = new double[x.Length];
            newX            = new double[x.Length];
            gradList        = new List <double[]>();
            numBatches      = dfunction.DataDimension() / bSize;
            outputFrequency = (int)System.Math.Ceil(((double)numBatches) / ((double)outputFrequency));
            Init(dfunction);
            InitFiles();
            bool have_max = (maxIterations > 0 || numPasses > 0);

            if (!have_max)
            {
                throw new NotSupportedException("No maximum number of iterations has been specified.");
            }
            else
            {
                maxIterations = System.Math.Max(maxIterations, numPasses) * numBatches;
            }
            Sayln("       Batchsize of: " + bSize);
            Sayln("       Data dimension of: " + dfunction.DataDimension());
            Sayln("       Batches per pass through data:  " + numBatches);
            Sayln("       Max iterations is = " + maxIterations);
            if (outputIterationsToFile)
            {
                infoFile.Println(function.DomainDimension() + "; DomainDimension ");
                infoFile.Println(bSize + "; batchSize ");
                infoFile.Println(maxIterations + "; maxIterations");
                infoFile.Println(numBatches + "; numBatches ");
                infoFile.Println(outputFrequency + "; outputFrequency");
            }
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //            Loop
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            Timing total   = new Timing();
            Timing current = new Timing();

            total.Start();
            current.Start();
            for (k = 0; k < maxIterations; k++)
            {
                try
                {
                    bool doEval = (k > 0 && evaluateIters > 0 && k % evaluateIters == 0);
                    if (doEval)
                    {
                        DoEvaluation(x);
                    }
                    int pass  = k / numBatches;
                    int batch = k % numBatches;
                    Say("Iter: " + k + " pass " + pass + " batch " + batch);
                    // restrict number of saved gradients
                    //  (recycle memory of first gradient in list for new gradient)
                    if (k > 0 && gradList.Count >= memory)
                    {
                        newGrad = gradList.Remove(0);
                    }
                    else
                    {
                        newGrad = new double[grad.Length];
                    }
                    dfunction.hasNewVals = true;
                    System.Array.Copy(dfunction.DerivativeAt(x, v, bSize), 0, newGrad, 0, newGrad.Length);
                    ArrayMath.AssertFinite(newGrad, "newGrad");
                    gradList.Add(newGrad);
                    grad = Smooth(gradList);
                    //Get the next X
                    TakeStep(dfunction);
                    ArrayMath.AssertFinite(newX, "newX");
                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    // THIS IS FOR DEBUG ONLY
                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    if (outputIterationsToFile && (k % outputFrequency == 0) && k != 0)
                    {
                        double curVal = dfunction.ValueAt(x);
                        Say(" TrueValue{ " + curVal + " } ");
                        file.Println(k + " , " + curVal + " , " + total.Report());
                    }
                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    // END OF DEBUG STUFF
                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    if (k >= maxIterations)
                    {
                        Sayln("Stochastic Optimization complete.  Stopped after max iterations");
                        x = newX;
                        break;
                    }
                    if (total.Report() >= maxTime)
                    {
                        Sayln("Stochastic Optimization complete.  Stopped after max time");
                        x = newX;
                        break;
                    }
                    System.Array.Copy(newX, 0, x, 0, x.Length);
                    Say("[" + (total.Report()) / 1000.0 + " s ");
                    Say("{" + (current.Restart() / 1000.0) + " s}] ");
                    Say(" " + dfunction.LastValue());
                    if (quiet)
                    {
                        log.Info(".");
                    }
                    else
                    {
                        Sayln(string.Empty);
                    }
                }
                catch (ArrayMath.InvalidElementException e)
                {
                    log.Info(e.ToString());
                    for (int i = 0; i < x.Length; i++)
                    {
                        x[i] = double.NaN;
                    }
                    break;
                }
            }
            if (evaluateIters > 0)
            {
                // do final evaluation
                DoEvaluation(x);
            }
            if (outputIterationsToFile)
            {
                infoFile.Println(k + "; Iterations");
                infoFile.Println((total.Report()) / 1000.0 + "; Completion Time");
                infoFile.Println(dfunction.ValueAt(x) + "; Finalvalue");
                infoFile.Close();
                file.Close();
                log.Info("Output Files Closed");
            }
            //System.exit(1);
            Say("Completed in: " + (total.Report()) / 1000.0 + " s");
            return(x);
        }
        public virtual double TuneDouble(Func function, double[] initial, long msPerTest, StochasticMinimizer.IPropertySetter <double> ps, double lower, double upper, double Tol)
        {
            double[] xtest = new double[initial.Length];
            this.maxTime = msPerTest;
            // check for stochastic derivatives
            if (!(function is AbstractStochasticCachingDiffFunction))
            {
                throw new NotSupportedException();
            }
            AbstractStochasticCachingDiffFunction dfunction = (AbstractStochasticCachingDiffFunction)function;
            IList <Pair <double, double> >        res       = new List <Pair <double, double> >();
            Pair <double, double> best = new Pair <double, double>(lower, double.PositiveInfinity);
            //this is set to lower because the first it will always use the lower first, so it has to be best
            Pair <double, double> low   = new Pair <double, double>(lower, double.PositiveInfinity);
            Pair <double, double> high  = new Pair <double, double>(upper, double.PositiveInfinity);
            Pair <double, double> cur   = new Pair <double, double>();
            Pair <double, double> tmp   = new Pair <double, double>();
            IList <double>        queue = new List <double>();

            queue.Add(lower);
            queue.Add(upper);
            //queue.add(0.5* (lower + upper));
            bool toContinue = true;

            this.numPasses = 10000;
            do
            {
                System.Array.Copy(initial, 0, xtest, 0, initial.Length);
                if (queue.Count != 0)
                {
                    cur.first = queue.Remove(0);
                }
                else
                {
                    cur.first = 0.5 * (low.First() + high.First());
                }
                ps.Set(cur.First());
                log.Info(string.Empty);
                log.Info("About to test with batch size:  " + bSize + "  gain: " + gain + " and  " + ps.ToString() + " set to  " + cur.First());
                xtest = this.Minimize(function, 1e-100, xtest);
                if (double.IsNaN(xtest[0]))
                {
                    cur.second = double.PositiveInfinity;
                }
                else
                {
                    cur.second = dfunction.ValueAt(xtest);
                }
                if (cur.Second() < best.Second())
                {
                    CopyPair(best, tmp);
                    CopyPair(cur, best);
                    if (tmp.First() > best.First())
                    {
                        CopyPair(tmp, high);
                    }
                    else
                    {
                        // The old best is now the upper bound
                        CopyPair(tmp, low);
                    }
                    // The old best is now the lower bound
                    queue.Add(0.5 * (cur.First() + high.First()));
                }
                else
                {
                    // check in the right interval next
                    if (cur.First() < best.First())
                    {
                        CopyPair(cur, low);
                    }
                    else
                    {
                        if (cur.First() > best.First())
                        {
                            CopyPair(cur, high);
                        }
                    }
                }
                if (System.Math.Abs(low.First() - high.First()) < Tol)
                {
                    toContinue = false;
                }
                res.Add(new Pair <double, double>(cur.First(), cur.Second()));
                log.Info(string.Empty);
                log.Info("Final value is: " + nf.Format(cur.Second()));
                log.Info("Optimal so far using " + ps.ToString() + " is: " + best.First());
            }while (toContinue);
            //output the results to screen.
            log.Info("-------------");
            log.Info(" RESULTS          ");
            log.Info(ps.GetType().ToString());
            log.Info("-------------");
            log.Info("  val    ,    function after " + msPerTest + " ms");
            foreach (Pair <double, double> re in res)
            {
                log.Info(re.First() + "    ,    " + re.Second());
            }
            log.Info(string.Empty);
            log.Info(string.Empty);
            return(best.First());
        }
Пример #5
0
        // 0=MinErr  1=Bradley
        public virtual double TuneFixedGain(Func function, double[] initial, long msPerTest, double fixedStart)
        {
            double[] xtest  = new double[initial.Length];
            double   fOpt   = 0.0;
            double   factor = 1.2;
            double   min    = double.PositiveInfinity;

            this.maxTime = msPerTest;
            double prev = double.PositiveInfinity;

            // check for stochastic derivatives
            if (!(function is AbstractStochasticCachingDiffFunction))
            {
                throw new NotSupportedException();
            }
            AbstractStochasticCachingDiffFunction dfunction = (AbstractStochasticCachingDiffFunction)function;
            int    it         = 1;
            bool   toContinue = true;
            double f          = fixedStart;

            do
            {
                System.Array.Copy(initial, 0, xtest, 0, initial.Length);
                log.Info(string.Empty);
                this.fixedGain = f;
                log.Info("Testing with batchsize: " + bSize + "    gain:  " + gain + "  fixedGain:  " + nf.Format(fixedGain));
                this.numPasses = 10000;
                this.Minimize(function, 1e-100, xtest);
                double result = dfunction.ValueAt(xtest);
                if (it == 1)
                {
                    f = f / factor;
                }
                if (result < min)
                {
                    min  = result;
                    fOpt = this.fixedGain;
                    f    = f / factor;
                    prev = result;
                }
                else
                {
                    if (result < prev)
                    {
                        f    = f / factor;
                        prev = result;
                    }
                    else
                    {
                        if (result > prev)
                        {
                            toContinue = false;
                        }
                    }
                }
                it += 1;
                log.Info(string.Empty);
                log.Info("Final value is: " + nf.Format(result));
                log.Info("Optimal so far is:  fixedgain: " + fOpt);
            }while (toContinue);
            return(fOpt);
        }