func (gdpe *gradientDescentParameterEstimator) Estimate(initialParameters []float64) ([]float64, error) { if gdpe.trainingSet == nil { return nil, gdeErrors.NewUntrainedEstimatorError() } if len(initialParameters) == 0 { return nil, gdeErrors.NewEmptyInitialParametersError() } gradient := func(guess []float64) ([]float64, error) { sumLossGradient := make([]float64, len(initialParameters)) for i := 0; i < gdpe.trainingSet.NumRows(); i++ { row, _ := gdpe.trainingSet.Row(i) features, _ := row.Features().(slice.FloatSlice) target, _ := row.Target().(slice.FloatSlice) x := features.Values() y := target.Values()[0] lossGradient, err := gdpe.plgf(guess, x, y) if err != nil { return nil, err } sumLossGradient = vectorutilities.Add(sumLossGradient, lossGradient) } return sumLossGradient, nil } return gradientdescent.GradientDescent(initialParameters, gdpe.learningRate, gdpe.precision, gdpe.maxIterations, gradient) }
var _ = Describe("GradientDescent", func() { var goodGradient func([]float64) ([]float64, error) BeforeEach(func() { goodGradient = func(x []float64) ([]float64, error) { g := make([]float64, len(x)) for i, xi := range x { g[i] = 2 * xi } return g, nil } }) Context("When given an empty initial guess", func() { It("Returns an error", func() { _, err := gradientdescent.GradientDescent([]float64{}, 0.05, 0.0005, 100000, goodGradient) Ω(err).Should(HaveOccurred()) }) }) Context("When the given gradient function returns an error", func() { It("Returns an error", func() { badGradient := func(x []float64) ([]float64, error) { return nil, errors.New("I'm bad") } _, err := gradientdescent.GradientDescent([]float64{0.3, -0.4}, 0.05, 0.0005, 100000, badGradient) Ω(err).Should(HaveOccurred()) }) }) Context("When given reasonable inputs", func() {