optimatika / okAlgo

Idiomatic Kotlin extensions for ojAlgo
MIT License
26 stars 3 forks source link

ANN DSL #7

Open thomasnield opened 6 years ago

thomasnield commented 6 years ago

DSL needs to be implemented for artifical neural nework.

                val ann = ArtificialNeuralNetwork.builder(4, 4, 2).apply {

                    activator(0, ArtificialNeuralNetwork.Activator.IDENTITY)
                    activator(1, ArtificialNeuralNetwork.Activator.SIGMOID)

                    rate(.05)
                    //error(ArtificialNeuralNetwork.Error.HALF_SQUARED_DIFFERENCE)

                    val inputValues = inputs.asSequence().map { Primitive64Array.FACTORY.copy(* colorAttributes(it.color)) }
                            .toList()

                    val outputValues = inputs.asSequence().map { Primitive64Array.FACTORY.copy(*it.fontShade.outputValue) }
                            .toList()

                    randomise()
                    train(inputValues, outputValues)
                }.get()

                return ann.apply(Primitive64Array.FACTORY.copy(*colorAttributes(color))).let {
                    println("${it[0]} ${it[1]}")
                    if (it[0] > it[1]) FontShade.LIGHT else FontShade.DARK
                }
apete commented 6 years ago

Did it work for you? I'm open to any/all suggestions.

thomasnield commented 6 years ago

@apete so far yes this worked awesome. It worked with beautiful accuracy on my example after enough training and hyperparameter tuning.

I think would be good to rename apply() to predict(). The apply() is a scope function in Kotlin so it might be confusing.

I'm going to mess around with this on a few more simple examples, like modeling nonlinear equations.

apete commented 6 years ago

That apply(...) comes from java.util.function.UnaryOperator. Is using the various classes in that package problematic with Kotlin?

The NetworkBuilder just wraps the ANN. If you keep it you can continue to modify the underlying ANN. No guarantee it will stay this way, but it is how it works for now.

Also the results array is reused. You need to read/copy those values before you "predict" again.

thomasnield commented 6 years ago

@apete It's not showstopper, just might cause some confusion for Kotlin devs. In Kotlin every type has an apply() function to manipulate that item within a closure. Kotlin devs will think of this apply() which has been overridden by ojAlgo.

val myMutableItem = ...

myMutableItem.apply { 
      mutableProperty1 = 3
      mutableProperty2 = 5
}

Thankfully the Kotlin compiler will let a hard apply() function take precedence over the standard library's apply(). But I'd recommend using test(), predict(), or some other function name since it clashes with Kotlin scope functions. I know DL4J uses output() but I don't like that name :/

If not, no worries. It can be worked with.

thomasnield commented 6 years ago

And makes sense regarding the builder structure. I like it.