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