func randmatstat(t int) (float64, float64) { n := 5 v := make([]float64, t) w := make([]float64, t) ad := make([]float64, n*n) bd := make([]float64, n*n) cd := make([]float64, n*n) dd := make([]float64, n*n) P := mat64.NewDense(n, 4*n, nil) Q := mat64.NewDense(2*n, 2*n, nil) pTmp := mat64.NewDense(4*n, 4*n, nil) qTmp := mat64.NewDense(2*n, 2*n, nil) for i := 0; i < t; i++ { for i := range ad { ad[i] = rnd.NormFloat64() bd[i] = rnd.NormFloat64() cd[i] = rnd.NormFloat64() dd[i] = rnd.NormFloat64() } a := mat64.NewDense(n, n, ad) b := mat64.NewDense(n, n, bd) c := mat64.NewDense(n, n, cd) d := mat64.NewDense(n, n, dd) P.Copy(a) P.View(0, n, n, n).(*mat64.Dense).Copy(b) P.View(0, 2*n, n, n).(*mat64.Dense).Copy(c) P.View(0, 3*n, n, n).(*mat64.Dense).Copy(d) Q.Copy(a) Q.View(0, n, n, n).(*mat64.Dense).Copy(b) Q.View(n, 0, n, n).(*mat64.Dense).Copy(c) Q.View(n, n, n, n).(*mat64.Dense).Copy(d) pTmp.Mul(P.T(), P) pTmp.Pow(pTmp, 4) qTmp.Mul(Q.T(), Q) qTmp.Pow(qTmp, 4) v[i] = mat64.Trace(pTmp) w[i] = mat64.Trace(qTmp) } mv, stdv := stat.MeanStdDev(v, nil) mw, stdw := stat.MeanStdDev(v, nil) return stdv / mv, stdw / mw }
func (g *GP) marginalLikelihoodDerivative(x, grad []float64, trainNoise bool, mem *margLikeMemory) { // d/dTheta_j log[(p|X,theta)] = // 1/2 * y^T * K^-1 dK/dTheta_j * K^-1 * y - 1/2 * tr(K^-1 * dK/dTheta_j) // 1/2 * α^T * dK/dTheta_j * α - 1/2 * tr(K^-1 dK/dTheta_j) // Multiply by the same -2 // -α^T * K^-1 * α + tr(K^-1 dK/dTheta_j) // This first computation is an inner product. n := len(g.outputs) nHyper := g.kernel.NumHyper() k := mem.k chol := mem.chol alpha := mem.alpha dKdTheta := mem.dKdTheta kInvDK := mem.kInvDK y := mat64.NewVector(n, g.outputs) var noise float64 if trainNoise { noise = math.Exp(x[len(x)-1]) } else { noise = g.noise } // If x is the same, then reuse what has been computed in the function. if !floats.Equal(mem.lastX, x) { copy(mem.lastX, x) g.kernel.SetHyper(x[:nHyper]) g.setKernelMat(k, noise) //chol.Cholesky(k, false) chol.Factorize(k) alpha.SolveCholeskyVec(chol, y) } g.setKernelMatDeriv(dKdTheta, trainNoise, noise) for i := range dKdTheta { kInvDK.SolveCholesky(chol, dKdTheta[i]) inner := mat64.Inner(alpha, dKdTheta[i], alpha) grad[i] = -inner + mat64.Trace(kInvDK) } floats.Scale(1/float64(n), grad) bounds := g.kernel.Bounds() if trainNoise { bounds = append(bounds, Bound{minLogNoise, maxLogNoise}) } barrierGrad := make([]float64, len(grad)) for i, v := range x { // Quadratic barrier penalty. if v < bounds[i].Min { diff := bounds[i].Min - v barrierGrad[i] = -(barrierPow) * math.Pow(diff, barrierPow-1) } if v > bounds[i].Max { diff := v - bounds[i].Max barrierGrad[i] = (barrierPow) * math.Pow(diff, barrierPow-1) } } fmt.Println("noise, minNoise", x[len(x)-1], bounds[len(x)-1].Min) fmt.Println("barrier Grad", barrierGrad) floats.Add(grad, barrierGrad) //copy(grad, barrierGrad) }