|
@@ -99,7 +99,7 @@ import (
|
|
|
// L = len(Sizes) - Number of neural network layers
|
|
|
|
|
|
type NeuralNetwork struct {
|
|
|
- layerCount int
|
|
|
+ LayerCount int
|
|
|
Sizes []int
|
|
|
Biases []*mat.Dense
|
|
|
Weights []*mat.Dense
|
|
@@ -125,15 +125,15 @@ func NewNeuralNetwork(sizes []int, gradientDescentInitializer GradientDescentIni
|
|
|
|
|
|
nn = &NeuralNetwork{}
|
|
|
nn.Sizes = sizes
|
|
|
- nn.layerCount = len(sizes)
|
|
|
- nn.Biases = make([]*mat.Dense, nn.layerCount)
|
|
|
- nn.Weights = make([]*mat.Dense, nn.layerCount)
|
|
|
- nn.BGradient = make([]interface{}, nn.layerCount)
|
|
|
- nn.WGradient = make([]interface{}, nn.layerCount)
|
|
|
+ nn.LayerCount = len(sizes)
|
|
|
+ nn.Biases = make([]*mat.Dense, nn.LayerCount)
|
|
|
+ nn.Weights = make([]*mat.Dense, nn.LayerCount)
|
|
|
+ nn.BGradient = make([]interface{}, nn.LayerCount)
|
|
|
+ nn.WGradient = make([]interface{}, nn.LayerCount)
|
|
|
|
|
|
nn.gradientDescentInitializer = gradientDescentInitializer
|
|
|
|
|
|
- for l := 1; l < nn.layerCount; l++ {
|
|
|
+ for l := 1; l < nn.LayerCount; l++ {
|
|
|
nn.Biases[l] = generateRandomDense(nn.Sizes[l], 1)
|
|
|
nn.Weights[l] = generateRandomDense(nn.Sizes[l], nn.Sizes[l-1])
|
|
|
nn.BGradient[l] = nn.gradientDescentInitializer(nn, l, BiasGradient)
|
|
@@ -162,7 +162,7 @@ func (nn *NeuralNetwork) Predict(aIn mat.Matrix) (maxIndex int, max float64) {
|
|
|
}
|
|
|
|
|
|
A, _ := nn.forward(aIn)
|
|
|
- result := A[nn.layerCount-1]
|
|
|
+ result := A[nn.LayerCount-1]
|
|
|
r, _ = result.Dims()
|
|
|
max = 0.0
|
|
|
maxIndex = 0
|
|
@@ -180,9 +180,9 @@ func (nn *NeuralNetwork) Train(trainer training.Trainer, epocs int) {
|
|
|
nn.watcher.UpdateState(StateLearning)
|
|
|
defer nn.watcher.UpdateState(StateIdle)
|
|
|
}
|
|
|
- if _, ok := nn.WGradient[nn.layerCount-1].(OnlineGradientDescent); ok {
|
|
|
+ if _, ok := nn.WGradient[nn.LayerCount-1].(OnlineGradientDescent); ok {
|
|
|
nn.TrainOnline(trainer, epocs)
|
|
|
- } else if _, ok := nn.WGradient[nn.layerCount-1].(BatchGradientDescent); ok {
|
|
|
+ } else if _, ok := nn.WGradient[nn.LayerCount-1].(BatchGradientDescent); ok {
|
|
|
nn.TrainBatch(trainer, epocs)
|
|
|
} else {
|
|
|
panic("Invalid gradient descent type")
|
|
@@ -193,7 +193,7 @@ func (nn *NeuralNetwork) TrainOnline(trainer training.Trainer, epocs int) {
|
|
|
for t := 0; t < epocs; t++ {
|
|
|
for trainer.NextData() {
|
|
|
dB, dW := nn.backward(trainer.GetData())
|
|
|
- for l := 1; l < nn.layerCount; l++ {
|
|
|
+ for l := 1; l < nn.LayerCount; l++ {
|
|
|
bGradient, ok := nn.BGradient[l].(OnlineGradientDescent)
|
|
|
if !ok {
|
|
|
panic("bGradient is not a OnlineGradientDescent")
|
|
@@ -218,7 +218,7 @@ func (nn *NeuralNetwork) TrainBatch(trainer training.Trainer, epocs int) {
|
|
|
for t := 0; t < epocs; t++ {
|
|
|
batchWorkers := nn.runBatchWorkers(runtime.NumCPU(), trainer)
|
|
|
|
|
|
- for l := 1; l < nn.layerCount; l++ {
|
|
|
+ for l := 1; l < nn.LayerCount; l++ {
|
|
|
bGradient, ok := nn.BGradient[l].(BatchGradientDescent)
|
|
|
if !ok {
|
|
|
panic("bGradient is not a BatchGradientDescent")
|
|
@@ -264,15 +264,15 @@ func (nn *NeuralNetwork) runBatchWorkers(threadCount int, trainer training.Train
|
|
|
func (nn *NeuralNetwork) SaveState(writer io.Writer) {
|
|
|
//save input array count
|
|
|
bufferSize := make([]byte, 4)
|
|
|
- binary.LittleEndian.PutUint32(bufferSize[0:], uint32(nn.layerCount))
|
|
|
+ binary.LittleEndian.PutUint32(bufferSize[0:], uint32(nn.LayerCount))
|
|
|
_, err := writer.Write(bufferSize)
|
|
|
|
|
|
check(err)
|
|
|
- fmt.Printf("wrote value %d\n", uint32(nn.layerCount))
|
|
|
+ fmt.Printf("wrote value %d\n", uint32(nn.LayerCount))
|
|
|
|
|
|
// save an input array
|
|
|
- buffer := make([]byte, nn.layerCount*4)
|
|
|
- for i := 0; i < nn.layerCount; i++ {
|
|
|
+ buffer := make([]byte, nn.LayerCount*4)
|
|
|
+ for i := 0; i < nn.LayerCount; i++ {
|
|
|
binary.LittleEndian.PutUint32(buffer[i*4:], uint32(nn.Sizes[i]))
|
|
|
}
|
|
|
|
|
@@ -282,26 +282,26 @@ func (nn *NeuralNetwork) SaveState(writer io.Writer) {
|
|
|
|
|
|
//save biases
|
|
|
////////////////////////
|
|
|
- for i := 1; i < nn.layerCount; i++ {
|
|
|
+ for i := 1; i < nn.LayerCount; i++ {
|
|
|
saveDense(writer, nn.Biases[i])
|
|
|
}
|
|
|
|
|
|
//save weights
|
|
|
////////////////////////
|
|
|
- for i := 1; i < nn.layerCount; i++ {
|
|
|
+ for i := 1; i < nn.LayerCount; i++ {
|
|
|
saveDense(writer, nn.Weights[i])
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (nn *NeuralNetwork) LoadState(reader io.Reader) {
|
|
|
// Reade count
|
|
|
- nn.layerCount = readInt(reader)
|
|
|
+ nn.LayerCount = readInt(reader)
|
|
|
|
|
|
// Read an input array
|
|
|
- sizeBuffer := readByteArray(reader, nn.layerCount*4)
|
|
|
- nn.Sizes = make([]int, nn.layerCount)
|
|
|
+ sizeBuffer := readByteArray(reader, nn.LayerCount*4)
|
|
|
+ nn.Sizes = make([]int, nn.LayerCount)
|
|
|
|
|
|
- for i := 0; i < nn.layerCount; i++ {
|
|
|
+ for i := 0; i < nn.LayerCount; i++ {
|
|
|
nn.Sizes[i] = int(binary.LittleEndian.Uint32(sizeBuffer[i*4:]))
|
|
|
// fmt.Printf("LoadState: nn.Sizes[%d] %d \n", i, nn.Sizes[i])
|
|
|
}
|
|
@@ -311,14 +311,14 @@ func (nn *NeuralNetwork) LoadState(reader io.Reader) {
|
|
|
|
|
|
// read Biases
|
|
|
nn.Biases[0] = &mat.Dense{}
|
|
|
- for i := 1; i < nn.layerCount; i++ {
|
|
|
+ for i := 1; i < nn.LayerCount; i++ {
|
|
|
nn.Biases = append(nn.Biases, &mat.Dense{})
|
|
|
nn.Biases[i] = readDense(reader, nn.Biases[i])
|
|
|
}
|
|
|
|
|
|
// read Weights
|
|
|
nn.Weights[0] = &mat.Dense{}
|
|
|
- for i := 1; i < nn.layerCount; i++ {
|
|
|
+ for i := 1; i < nn.LayerCount; i++ {
|
|
|
nn.Weights = append(nn.Weights, &mat.Dense{})
|
|
|
nn.Weights[i] = readDense(reader, nn.Weights[i])
|
|
|
}
|
|
@@ -327,8 +327,8 @@ func (nn *NeuralNetwork) LoadState(reader io.Reader) {
|
|
|
}
|
|
|
|
|
|
func (nn NeuralNetwork) forward(aIn mat.Matrix) (A, Z []*mat.Dense) {
|
|
|
- A = make([]*mat.Dense, nn.layerCount)
|
|
|
- Z = make([]*mat.Dense, nn.layerCount)
|
|
|
+ A = make([]*mat.Dense, nn.LayerCount)
|
|
|
+ Z = make([]*mat.Dense, nn.LayerCount)
|
|
|
|
|
|
A[0] = mat.DenseCopyOf(aIn)
|
|
|
|
|
@@ -336,7 +336,7 @@ func (nn NeuralNetwork) forward(aIn mat.Matrix) (A, Z []*mat.Dense) {
|
|
|
nn.watcher.UpdateActivations(0, A[0])
|
|
|
}
|
|
|
|
|
|
- for l := 1; l < nn.layerCount; l++ {
|
|
|
+ for l := 1; l < nn.LayerCount; l++ {
|
|
|
A[l] = mat.NewDense(nn.Sizes[l], 1, nil)
|
|
|
aSrc := A[l-1]
|
|
|
aDst := A[l]
|
|
@@ -367,9 +367,9 @@ func (nn NeuralNetwork) forward(aIn mat.Matrix) (A, Z []*mat.Dense) {
|
|
|
func (nn NeuralNetwork) backward(aIn, aOut mat.Matrix) (dB, dW []*mat.Dense) {
|
|
|
A, Z := nn.forward(aIn)
|
|
|
|
|
|
- lastLayerNum := nn.layerCount - 1
|
|
|
- dB = make([]*mat.Dense, nn.layerCount)
|
|
|
- dW = make([]*mat.Dense, nn.layerCount)
|
|
|
+ lastLayerNum := nn.LayerCount - 1
|
|
|
+ dB = make([]*mat.Dense, nn.LayerCount)
|
|
|
+ dW = make([]*mat.Dense, nn.LayerCount)
|
|
|
|
|
|
// To calculate new values of weights and biases
|
|
|
// following formulas are used:
|
|
@@ -383,7 +383,7 @@ func (nn NeuralNetwork) backward(aIn, aOut mat.Matrix) (dB, dW []*mat.Dense) {
|
|
|
// error = A[L]-y
|
|
|
// Where y is expected activations set
|
|
|
err := &mat.Dense{}
|
|
|
- err.Sub(A[nn.layerCount-1], aOut)
|
|
|
+ err.Sub(A[nn.LayerCount-1], aOut)
|
|
|
|
|
|
// Calculate sigmoids prime σ'(Z[L]) for last layer L
|
|
|
sigmoidsPrime := &mat.Dense{}
|
|
@@ -412,7 +412,7 @@ func (nn NeuralNetwork) backward(aIn, aOut mat.Matrix) (dB, dW []*mat.Dense) {
|
|
|
// δ[l] = ((Wt[l+1])*δ[l+1])⊙σ'(Z[l])
|
|
|
// Where Wt[l+1] is transposed matrix of actual Weights from
|
|
|
// forward step
|
|
|
- for l := nn.layerCount - 2; l > 0; l-- {
|
|
|
+ for l := nn.LayerCount - 2; l > 0; l-- {
|
|
|
// Calculate sigmoids prime σ'(Z[l]) for last layer l
|
|
|
sigmoidsPrime := &mat.Dense{}
|
|
|
sigmoidsPrime.Apply(applySigmoidPrime, Z[l])
|