func (n *Network) Predict(input []float64) []float64 {
	return n.feedforward(input)
}
Predict calculates the output for the given input.
package fonet
import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"log"
	"math/rand"
	"time"
)
func init() {
	rand.Seed(time.Now().UnixNano())
}
var (
	ErrNotEnoughLayers = errors.New("too few layers, minimum of 3 required")
)
type Network struct {
	w [][][]float64
	b [][]float64
	d [][]float64
	z [][]float64
	l int
	ls []int
	activationID ActivationFunction
	aFunc func(z float64) float64
	daFunc func(z float64) float64
}
type jsonNetwork struct {
	W            [][][]float64 `json:"W"`
	B            [][]float64   `json:"B"`
	D            [][]float64   `json:"D"`
	Z            [][]float64   `json:"Z"`
	L            int           `json:"L"`
	LS           []int         `json:"LS"`
	ActivationID int           `json:"ActivationID"`
}
func (n *Network) MarshalJSON() ([]byte, error) {
	var buf bytes.Buffer
	err := json.NewEncoder(&buf).Encode(jsonNetwork{
		W:            n.w,
		B:            n.b,
		D:            n.d,
		Z:            n.z,
		L:            n.l,
		LS:           n.ls,
		ActivationID: int(n.activationID),
	})
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (n *Network) UnmarshalJSON(data []byte) error {
	var en jsonNetwork
	if err := json.Unmarshal(data, &en); err != nil {
		return err
	}
	n.w = en.W
	n.b = en.B
	n.d = en.D
	n.z = en.Z
	n.l = en.L
	n.ls = en.LS
	n.activationID = ActivationFunction(en.ActivationID)
	n.aFunc = functionPairs[n.activationID][0]
	n.daFunc = functionPairs[n.activationID][1]
	return nil
}
func NewNetwork(ls []int, activationFunc ActivationFunction) (*Network, error) {
	if len(ls) < 3 {
		return nil, ErrNotEnoughLayers
	}
	n := Network{
		l:            len(ls) - 1,
		ls:           ls[1:],
		activationID: activationFunc,
		aFunc:        functionPairs[activationFunc][0],
		daFunc:       functionPairs[activationFunc][1],
	}
	n.w = make([][][]float64, n.l)
	n.w[0] = make([][]float64, ls[0])
	for i := 0; i < ls[0]; i++ {
		n.w[0][i] = make([]float64, n.ls[0])
		for j := 0; j < n.ls[0]; j++ {
			n.w[0][i][j] = rand.Float64()
		}
	}
	for l := 1; l < n.l; l++ {
		n.w[l] = make([][]float64, n.ls[l-1])
		for i := 0; i < n.ls[l-1]; i++ {
			n.w[l][i] = make([]float64, n.ls[l])
			for j := 0; j < n.ls[l]; j++ {
				n.w[l][i][j] = rand.Float64()
			}
		}
	}
	n.b = make([][]float64, n.l)
	n.d = make([][]float64, n.l)
	n.z = make([][]float64, n.l)
	for l := 0; l < n.l; l++ {
		n.b[l] = make([]float64, n.ls[l])
		for i := 0; i < n.ls[l]; i++ {
			n.b[l][i] = rand.Float64()
		}
		n.d[l] = make([]float64, n.ls[l])
		n.z[l] = make([]float64, n.ls[l])
	}
	return &n, nil
}
func (n *Network) dw(l, i, j int, eta float64) float64 {
	return -eta * n.d[l][j] * n.a(l-1, i)
}
func (n *Network) a(l, j int) float64 {
	return n.aFunc(n.z[l][j])
}
func (n *Network) Train(trainingData [][][]float64, epochs int, lrate float64, debug bool) {
	for e := 0; e < epochs; e++ {
		for _, xy := range trainingData {
			n.backpropagate(xy, lrate)
		}
		if debug {
			log.Println("Epoch:", e+1, "/", epochs)
		}
	}
}
func (n *Network) backpropagate(xy [][]float64, eta float64) {
	x := xy[0]
	y := xy[1]
	_ = n.feedforward(x)
	for j := 0; j < len(n.d[len(n.d)-1]); j++ {
		n.d[len(n.d)-1][j] = (n.a(len(n.d)-1, j) - y[j]) * n.daFunc(n.z[len(n.d)-1][j])
	}
	for l := len(n.d) - 2; l >= 0; l-- {
		for j := 0; j < len(n.d[l]); j++ {
			n.d[l][j] = n.delta(l, j)
		}
	}
	for i := 0; i < len(n.w[0]); i++ {
		for j := 0; j < len(n.w[0][i]); j++ {
			n.w[0][i][j] += -eta * n.d[0][j] * x[i]
		}
	}
	for l := 1; l < len(n.w); l++ {
		for i := 0; i < len(n.w[l]); i++ {
			for j := 0; j < len(n.w[l][i]); j++ {
				n.w[l][i][j] += n.dw(l, i, j, eta)
			}
		}
	}
	for l := 0; l < len(n.b); l++ {
		for j := 0; j < len(n.b[l]); j++ {
			n.b[l][j] += -eta * n.d[l][j]
		}
	}
}
func (n *Network) delta(l, j int) float64 {
	var d float64
	for k := 0; k < n.ls[l+1]; k++ {
		d += n.d[l+1][k] * n.w[l+1][j][k] * n.daFunc(n.z[l][j])
	}
	return d
}
func (n *Network) feedforward(a []float64) []float64 {
	for l := 0; l < n.l; l++ {
		atemp := make([]float64, n.ls[l])
		for j := 0; j < n.ls[l]; j++ {
			n.z[l][j] = 0
			for i := 0; i < len(a); i++ {
				n.z[l][j] += n.w[l][i][j] * a[i]
			}
			n.z[l][j] += n.b[l][j]
			atemp[j] = n.aFunc(n.z[l][j])
		}
		a = atemp
	}
	return a
}