VB NMF Example

← All NMath Code Examples

 

Imports System
Imports System.Text
Imports System.Collections.Generic

Imports CenterSpace.NMath.Core

Imports System.IO

Namespace CenterSpace.NMath.Examples.VisualBasic

  A .NET example in Visual Basic illustrating Non-negative Matrix Factorization (NMF)
  Module NMFExample

    Sub Main()
      Load the example data into a DataFrame
      Dim Frame As DataFrame = DataFrame.Load("NMFExample.dat", False, False, ",", True)

      Construct a Nonnegative Matrix Factorization object that will perform 200
      iterations when computing the factors.
      Dim Fact As NMFact = New NMFact(200)

      Now, perform the factorization data = WH Imports the the default initial
      initial values for WH (which are uniform random in (0, 1) ), the default
      update algorithm (NMFMultiplicativeUpdate) and k = 2.
      Fact.Factor(Frame, 2)

      Look at the results. Note that since the initial values for W and H are
      random, the results will not be exactly the same on each run of the
      program.
      Console.WriteLine()
      Console.WriteLine("Output 0, Default initial W, H, and algorithm -----------------")
      PrintResults(Fact)
      Note that the values of W and H are not close to the expected values

      Set up some initial values for W and H so we can play with some of the 
      factorizations parameters and observe the effects without the random
      variations induced by random initial values.
      Dim RNG As RandGenUniform = New RandGenUniform(124)
      Dim initialW As DoubleMatrix = New DoubleMatrix(3, 2, RNG)
      Dim initialH As New DoubleMatrix(2, 4, RNG)

      Factor and print the results
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 1 -------------------------------------------------------")
      PrintResults(Fact)

      Note that the factorization is pretty darn good - the cost function 
      is on the order of 10e-18 and the difference of the elements of WH
      and V are all on the order of 10e-9 or 10e-10. But we are not close
      to the expected results. This shows the non-uniqueness of NMF 
      solutions. Lets up the number of iterations to, say, 1000 and see
      if our factorization improves:
      Fact.NumIterations = 1000
      initialW = New DoubleMatrix(3, 2, RNG)
      initialH = New DoubleMatrix(2, 4, RNG)
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 2, 1000 iterations ----------------------------------")
      PrintResults(Fact)

      Cost goes way down, all the elements of V - WH are 0 or on the order
      of 10e-15 - thats basically 0 within the limits of a double precision
      number (15 significant digits). Within machine precision, the 
      factorization is exact and the solution is definitely a local minimum
      of the function ||V - WH||. Lets try and make it converge to the 
      expected solution by setting the initial values very close to the 
      expected values.
      initialW = New DoubleMatrix("3x2[1 5  2 1  3 4]")
      initialW = initialW + 0.01
      initialH = New DoubleMatrix("2x4[1 4 3 2  8 1 2 7]")
      initialH = initialH - 0.01
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 3, initial W, H close to expected values --------------------")
      PrintResults(Fact)

      Wow. We still converge to the same solution as before. That solution
      must be a very strong attractor for this algorithm. Lets try a 
      different algorithm. The GD-CLS algorithm uses the multiplicative
      method, which is basically a version of the gradient descent (GD) 
      optimization scheme, to approximate the basis vector matrix W. H
      is calculated Imports a constrained least squares (CLS).
      Fact.UpdateAlgorithm = New NMFGdClsUpdate()
      Dim delta As Double = 0.01
      initialW = New DoubleMatrix("3x2[1 5  2 1  3 4]")
      initialW = initialW + delta
      initialH = New DoubleMatrix("2x4[1 4 3 2  8 1 2 7]")
      initialH = initialH + delta
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 4, GD-CLS algorithm initial W, H close to expected values -----")
      PrintResults(Fact)

      Now, thats more like it. We can find the expected solution if we 
      out right on top of it.

      Console.WriteLine()
      Console.WriteLine("Press Enter Key")
      Console.Read()
    End Sub

    Sub PrintResults(ByVal Fact As NMFact)
      Matrices rounded for better legibility

      Look at the results:
      Console.WriteLine()
      Console.WriteLine("Factored Matrix: ")
      Console.WriteLine(Fact.V.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("W: ")
      Console.WriteLine(Fact.W.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("H: ")
      Console.WriteLine(Fact.H.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("Cost (error) = " & Fact.Cost)

      Look at the product of the factors and the difference from
      the factored matrix V
      Dim WH As DoubleMatrix = NMathFunctions.Product(Fact.W, Fact.H)
      Dim D As DoubleMatrix = Fact.V - WH
      Console.WriteLine()
      Console.WriteLine("WH = ")
      Console.WriteLine(WH.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("V - WH = ")
      Console.WriteLine(D.ToTabDelimited("G5"))
      Console.WriteLine()

    End Sub
  End Module
End Namespace

← All NMath Code Examples
Top