8.神经网络和深度学习

8.1神经网络的术语
节点、感知器或神经元:神经网络的基本组成部分。每个节点或神经元接收输入数据并对数据执行操作。
执行完操作后,该节点或神经元可能会或不会传递操作到下一个节点/神经元
激活:与操作节点相关的输出或者值
激活函数:将节点输入转换成输出或激活操作的函数
权重或偏差:这些值定义了激活函数中输入和输出数据之间的关系
输入层:神经网络的输入层包含一系列节点,用于接收神经网络模型的初始化输入。
输出层:神经网路的输出层包含一些列的节点,用于将信息传递到神经网络内部,并将其转换为最终的输出。
隐藏层:介于输入与输出层之间
前馈或正向传输:将数据输入到神经网络的输入层,并正向传输到输出层
反向传播:训练神经网络模型的一种说法,将误差的更改传回到网络中去
架构:神经元是如何在神经网络中连接在一起的整体架构。

8.2构建一个简单的神经网络

go语言提供神经网络架构的包见图

GGNN神经网络 go 神经网络_GGNN神经网络

8.2.1网络中的节点
	网络中的节点本身具有相对简单的功能,接收一个或者多个值的输入,根据一个激活函数组合这些值,然后输出。
	线性组合就是通过权重与相关值得乘积再加一个偏差,非线性则是使用sigmoid函数,可以用逻辑函数,双曲线正切函数,softmax或整流线型函数

	隐藏层的节点越多,训练数据的效果越号,会造成过拟合

8.2.3训练神经网络
	使用反向传播的方法训练神经网络
		通过神经网络前馈训练数据用以计算输出
		计算输出中的误差
		使用梯度下降法或其他方法来确定如何根据误差来更改权重和偏差
		将权重和偏差的变化反向传播到网络中去

	新的版本在进行mat.NewDense(r,c,data)的时候 不允许r和c是0,所以需要把异常注释掉

8.4深度学习 
	当下的深度学习还是用Tensflow
	go语言的深度学习包github.com/chewxy/gorgonia

搭建神经网络的代码

import (    "encoding/csv"    "errors"    "fmt"    "log"    "math"    "math/rand"    "os"    "strconv"    "time"
    "gonum.org/v1/gonum/floats"
    "gonum.org/v1/gonum/mat")
// 定义神经网络的结构体,包含网络架构的参数type nerualNetConfig struct {    inputNeurons  int    outputNeurons int    hidenNeurons  int    numEpoch      int    learningRate  float64}
//受训神经网络结构体type neuralNet struct {    config nerualNetConfig    whiden *mat.Dense //隐藏层的权重    bhiden *mat.Dense //隐藏层的偏差    wOUt   *mat.Dense //输出的权重    bOut   *mat.Dense //输出的偏差}
// 神经网络初始化func newNetWork(config nerualNetConfig) *neuralNet {    return &neuralNet{config: config}}
// 训练函数// 1.完成反向传播的方法// 2.将训练产生的权重和偏差放入接收器func (nn *neuralNet) train(x, y *mat.Dense) error {    // 初始化权重和偏差    randSource := rand.NewSource(time.Now().UnixNano())    randGen := rand.New(randSource)
    wHidenRaw := make([]float64, nn.config.hidenNeurons*nn.config.inputNeurons)    bFidenRaw := make([]float64, nn.config.hidenNeurons)    wOutRaw := make([]float64, nn.config.outputNeurons*nn.config.hidenNeurons)    bOutRaw := make([]float64, nn.config.outputNeurons)
    for _, param := range [][]float64{wHidenRaw, bFidenRaw, wOutRaw, bOutRaw} {
        for i := range param {            param[i] = randGen.Float64()        }    }
    wHiden := mat.NewDense(nn.config.inputNeurons, nn.config.hidenNeurons, wHidenRaw)    bHiden := mat.NewDense(1, nn.config.hidenNeurons, bFidenRaw)
    wOUt := mat.NewDense(nn.config.hidenNeurons, nn.config.outputNeurons, wOutRaw)    bout := mat.NewDense(1, nn.config.outputNeurons, bOutRaw)
    // 定义反向传播的过程    output := mat.NewDense(0, 0, nil)
    // 遍历每个阶段完成反向传播    for i := 0; i < nn.config.numEpoch; i++ {        //前馈的完成        hidenLayerInput := mat.NewDense(0, 0, nil)        hidenLayerInput.Mul(x, wHiden)        addBHinden := func(_, col int, v float64) float64 { return v + bHiden.At(0, col) }
        hidenLayerInput.Apply(addBHinden, hidenLayerInput)
        hidenLayerActions := mat.NewDense(0, 0, nil)        applySigmoid := func(_, _ int, v float64) float64 { return sigmoid(v) }
        hidenLayerActions.Apply(applySigmoid, hidenLayerInput)
        ouputLayerInput := mat.NewDense(0, 0, nil)        ouputLayerInput.Mul(hidenLayerActions, wOUt)        addBout := func(_, col int, v float64) float64 { return v + bout.At(0, col) }
        ouputLayerInput.Apply(addBout, ouputLayerInput)        output.Apply(applySigmoid, ouputLayerInput)
        //计算隐藏层和输出层的增量用以反向传播        netWorkError := mat.NewDense(0, 0, nil)        netWorkError.Sub(y, output)
        slopeOutputLayer := mat.NewDense(0, 0, nil)        applySigmoidPrime := func(_, _ int, v float64) float64 { return sigmoidPrime(v) }        slopeOutputLayer.Apply(applySigmoidPrime, output)
        slopeHidenLayer := mat.NewDense(0, 0, nil)        slopeHidenLayer.Apply(applySigmoidPrime, hidenLayerActions)
        dOutput := mat.NewDense(0, 0, nil)        dOutput.MulElem(netWorkError, slopeOutputLayer)        errorArHidenLayer := mat.NewDense(0, 0, nil)        errorArHidenLayer.Mul(dOutput, wOUt.T())
        dHidenLayer := mat.NewDense(0, 0, nil)        dHidenLayer.MulElem(errorArHidenLayer, slopeHidenLayer)
        // 参数调整        wOUtAdj := mat.NewDense(0, 0, nil)        wOUtAdj.Mul(hidenLayerActions.T(), dOutput)        wOUtAdj.Scale(nn.config.learningRate, wOUtAdj)        wOUt.Add(wOUt, wOUtAdj)
        bOutAdj, err := sumAlongAxis(0, dOutput)        if err != nil {            log.Fatal(err)        }        bOutAdj.Scale(nn.config.learningRate, bOutAdj)        bout.Add(bout, bOutAdj)
        wHidenAdj := mat.NewDense(0, 0, nil)        wHidenAdj.Mul(x.T(), dHidenLayer)        wHidenAdj.Scale(nn.config.learningRate, wHidenAdj)        wHiden.Add(wHiden, wHidenAdj)
        bHidenAdj, err := sumAlongAxis(0, dHidenLayer)        if err != nil {            log.Fatal(err)        }        bHidenAdj.Scale(nn.config.learningRate, bHidenAdj)        bHiden.Add(bHiden, bHidenAdj)    }
    nn.whiden = wHiden    nn.bhiden = bHiden    nn.wOUt = wOUt    nn.bOut = bout    return nil}
// 定义个反馈函数// 1.接收新的输入进行网络反馈// 2.向前反馈预测并产生新的输入预测输出func (nn *neuralNet) predict(x *mat.Dense) (*mat.Dense, error) {    // 反馈训练模型    if nn.whiden == nil || nn.bOut == nil || nn.bhiden == nil || nn.wOUt == nil {        return nil, errors.New(" 权重与偏差为空")    }    output := mat.NewDense(0, 0, nil)    hidenLayerInput := mat.NewDense(0, 0, nil)    hidenLayerInput.Mul(x, nn.whiden)    addBhinde := func(_, col int, v float64) float64 { return v + nn.bhiden.At(0, col) }    hidenLayerInput.Apply(addBhinde, hidenLayerInput)
    hidenLayerActions := mat.NewDense(0, 0, nil)    applySigmoid := func(_, _ int, v float64) float64 { return sigmoid(v) }
    hidenLayerActions.Apply(applySigmoid, hidenLayerInput)
    ouputLayerInput := mat.NewDense(0, 0, nil)    ouputLayerInput.Mul(hidenLayerActions, nn.wOUt)    addBout := func(_, col int, v float64) float64 { return v + nn.bOut.At(0, col) }
    ouputLayerInput.Apply(addBout, ouputLayerInput)    output.Apply(applySigmoid, ouputLayerInput)
    return output, nil
}
// 以逻辑函数作为激活函数func sigmoid(x float64) float64 {
    return 1.0 / (1.0 + math.Exp(-x))}
// 激活函数得倒数func sigmoidPrime(x float64) float64 {    return x * (1.0 - x)}
//沿着某一维度对矩阵求和func sumAlongAxis(axis int, m *mat.Dense) (*mat.Dense, error) {    numRows, numCols := m.Dims()    var output *mat.Dense    switch axis {    case 0:        data := make([]float64, numCols)        for i := 0; i < numCols; i++ {            col := mat.Col(nil, i, m)            data[i] = floats.Sum(col)        }        output = mat.NewDense(1, numCols, data)    case 1:        data := make([]float64, numRows)        for i := 0; i < numRows; i++ {            row := mat.Row(nil, i, m)            data[i] = floats.Sum(row)        }        output = mat.NewDense(1, numRows, data)    default:        return nil, errors.New("无效坐标轴,必须是1或0")    }    return output, nil
}