Exemplo n.º 1
0
Arquivo: nmf.go Projeto: frogs/biogo
func Factors(X, Wo, Ho *sparse.Sparse, tolerance float64, iterations int, limit time.Duration) (W, H *sparse.Sparse, ok bool) {
	W = Wo
	H = Ho
	to := time.Now()

	hT := H.T()
	wT := W.T()

	gW := W.Dot(H.Dot(hT)).Sub(X.Dot(hT))
	gH := wT.Dot(W).Dot(H).Sub(wT.Dot(X))

	gradient := gW.Stack(gH.T()).Norm(matrix.Fro)
	toleranceW := math.Max(0.001, tolerance) * gradient
	toleranceH := toleranceW

	wFilter := func(r, c int, v float64) bool {
		w := W.At(r, c)
		return v < 0 || w > 0 // wFilter called with gW as receiver, so v, _ = gW.At(r, c)
	}
	hFilter := func(r, c int, v float64) bool {
		h := H.At(r, c)
		return v < 0 || h > 0 // hFilter called with gH as receiver, so v, _ = gH.At(r, c)
	}

	var (
		subOk  bool
		iW, iH int
	)
	ok = true

	for i := 1; i < iterations; i++ {
		projection := sparse.Elements(gW.Filter(wFilter), (gH.Filter(hFilter))).Norm(matrix.Fro)
		if projection < tolerance*gradient || time.Now().Sub(to) > limit {
			break
		}

		if W, gW, iW, subOk = subproblem(X.T(), H.T(), W.T(), toleranceW, 1000); iW == 1 {
			toleranceW *= 0.1
		}
		ok = ok && subOk

		W = W.T()
		gW = gW.T()

		if H, gH, iH, subOk = subproblem(X, W, H, toleranceH, 1000); iH == 1 {
			toleranceH *= 0.1
		}
		ok = ok && subOk
	}

	return
}
Exemplo n.º 2
0
Arquivo: nmf.go Projeto: frogs/biogo
func subproblem(X, W, Ho *sparse.Sparse, tolerance float64, iterations int) (H, G *sparse.Sparse, i int, ok bool) {
	H = Ho.Copy()
	WtV := W.T().Dot(X)
	WtW := W.T().Dot(W)

	var alpha, beta float64 = 1, 0.1

	for i := 0; i < iterations; i++ {
		G = WtW.Dot(H).Sub(WtV)

		filter := func(r, c int, v float64) bool {
			h := H.At(r, c)
			return v < 0 || h > 0 // filter called with G as receiver, so v, _ = G.At(r, c)
		}
		if projection := G.Filter(filter).Norm(matrix.Fro); projection < tolerance {
			break
		}
	}

	var (
		decrease bool
		Hp       *sparse.Sparse
	)

	for j := 0; j < InnerLoop; j++ {
		Hn := H.Sub(G.Scalar(alpha))
		filter := func(r, c int, v float64) bool {
			return v > 0 // filter called with Hn as receiver, so v, _ = Hn.At(r, c)
		}
		Hn = Hn.Filter(filter)

		d := Hn.Sub(H)
		gd := G.MulElem(d).Sum()
		dQd := WtW.Dot(d).MulElem(d).Sum()
		sufficient := 0.99*gd+0.5*dQd < 0
		if j == 0 {
			decrease = !sufficient
			Hp = H.Copy()
		}
		if decrease {
			if sufficient {
				H = Hn
				ok = true
				break
			} else {
				alpha *= beta
			}
		} else {
			if !sufficient || Hp.Equals(Hn) {
				H = Hp
				ok = true
				break
			} else {
				alpha /= beta
				Hp = Hn.Copy()
			}
		}
	}

	return
}