gru神经网络有记忆性吗 go 神经网络_感知器


介绍

在本教程中,我们将在Golang中从头开始构建一个简单的神经网络(单层感知器)。我们还将根据样本数据对其进行培训并进行预测。从头开始创建自己的神经网络将帮助您更好地了解神经网络内部发生的事情以及学习算法的工作。

什么是感知器?

感知器——由Frank Rosenblatt于1958年发明,是最简单的神经网络,由n个输入、1个神经元和1个输出组成,其中n是我们数据集的特征数。

因此,我们的单层感知器由以下组件组成:

  • 输入层(x)
  • 输出层(ŷ)
  • 这两层之间的一组权重(w)和一个偏差(b)
  • 输出层的激活函数(σ)。在本教程中,我们将使用sigmoid激活函数。

我们的神经网络被称为单层感知器(SLP),因为神经网络只有一层神经元。具有一层以上神经元的神经网络称为多层感知器(MLP)。

(注:epoch是指整个训练数据集的一个周期)

type Perceptron struct {input        [][]float64actualOutput []float64weights      []float64bias         float64epochs       int}

开始之前

我们将为以下数学运算构建自己的函数-向量加法、向量点积和标量矩阵乘法。

func dotProduct(v1, v2 []float64) float64 { //Dot Product of Two Vectors of same sizedot := 0.0for i := 0; i < len(v1); i++ {dot += v1[i] * v2[i]}return dot}func vecAdd(v1, v2 []float64) []float64 { //Addition of Two Vectors of same sizeadd := make([]float64, len(v1))for i := 0; i < len(v1); i++ {add[i] = v1[i] + v2[i]}return add}func scalarMatMul(s float64, mat []float64) []float64 { //Multiplication of a Vector & Matrixresult := make([]float64, len(mat))for i := 0; i < len(mat); i++ {result[i] += s * mat[i]}return result}

最初,神经网络的权值设置为0到1之间的随机浮点数,而偏差设置为0。

func (a *Perceptron) initialize() { //Random Initializationrand.Seed(time.Now().UnixNano())a.bias = 0.0a.weights = make([]float64, len(a.input[0]))for i := 0; i < len(a.input[0]); i++ {a.weights[i] = rand.Float64()}}

正向传播

通过神经网络传递数据的过程称为前向传播或前向传递。感知器的输出是:


gru神经网络有记忆性吗 go 神经网络_r语言初学者指南_02


简而言之,权向量(w)和输入向量(x)的点积加上偏压(b),求和通过激活函数。乙状结肠激活函数的输出将为0和1。

func (a *Perceptron) sigmoid(x float64) float64 { //Sigmoid Activationreturn 1.0 / (1.0 + math.Exp(-x))}func (a *Perceptron) forwardPass(x []float64) (sum float64) { //Forward Propagationreturn a.sigmoid(dotProduct(a.weights, x) + a.bias)}

学习算法

学习算法由反向传播和优化两部分组成。

反向传播,简称误差反向传播,是指计算损失函数相对于权重的梯度的算法。然而,这个术语经常被用来指代整个学习算法。

损失函数用来估计我们离期望解有多远。一般来说,回归问题的损失函数是均方误差,分类问题的损失函数是交叉熵。为了简单起见,我们将使用均方误差作为损失函数。另外,我们不会计算MSE,而是直接计算它的梯度。


gru神经网络有记忆性吗 go 神经网络_感知器_03


用链式法则计算损失函数的梯度,损失函数相对于权重和偏差的梯度计算如下。


gru神经网络有记忆性吗 go 神经网络_神经网络_04


优化就是选择感知器的最佳权值和偏差,以达到预期的效果。我们选择梯度下降作为优化算法。权值和偏差更新如下,直到收敛。


gru神经网络有记忆性吗 go 神经网络_神经网络_05


学习率(α)是一个超参数,用来控制权重和偏差的变化量。但是,我们不会在本教程中使用学习率。

func (a *Perceptron) gradW(x []float64, y float64) []float64 { //Calculate Gradients of Weightspred := a.forwardPass(x)return  scalarMatMul(-(pred-y)*pred*(1-pred), x)}func (a *Perceptron) gradB(x []float64, y float64) float64 { //Calculate Gradients of Biaspred := a.forwardPass(x)return -(pred - y) * pred * (1 - pred)}func (a *Perceptron) train() { //Train the Perceptron for n epochsfor i := 0; i < a.epochs; i++ {dw := make([]float64, len(a.input[0]))db := 0.0for length, val := range a.input {dw = vecAdd(dw, a.gradW(val, a.actualOutput[length]))db += a.gradB(val, a.actualOutput[length])}dw = scalarMatMul(2 / float64(len(a.actualOutput)), dw)a.weights = vecAdd(a.weights, dw)a.bias += db * 2 / float64(len(a.actualOutput))}}

装配零件

现在让我们用神经网络对以下数据进行训练和预测。数据有三个输入,只有一个输出属于两个类(0和1)。因此,数据可以在我们的单层感知器上训练。


gru神经网络有记忆性吗 go 神经网络_感知器_06


如你所见,输出Y仅依赖于输入X1。现在我们将在上面的数据上训练我们的神经网络,并检查它在1000个时代之后的表现。为了进行预测,我们只需要用测试输入做一个正向传播。

func main() {goPerceptron := Perceptron{input:        [][]float64{{0, 0, 1}, {1, 1, 1}, {1, 0, 1}, {0, 1, 0}}, //Input DataactualOutput: []float64{0, 1, 1, 0},                                   //Actual Outputepochs:       1000,                                                     //Number of Epoch}goPerceptron.initialize()goPerceptron.train()print(goPerceptron.forwardPass([]float64{0, 1, 0}), "") //Make Predictionsprint(goPerceptron.forwardPass([]float64{1, 0, 1}), "")}


gru神经网络有记忆性吗 go 神经网络_感知器_07


当我们将预测值与实际值进行比较时,我们可以看到我们训练的单层感知器表现良好。我们已经成功地建立了一个神经网络,并对其进行训练,以产生理想的结果。

接下来是什么?

现在你已经完全从头开始创建了自己的神经网络。下面有几件事你应该试试。

  • 测试自己的数据
  • 尝试除乙状结肠功能外的其他激活功能
  • 计算每个历元后的MSE
  • 尝试除MSE以外的其他错误函数
  • 尝试创建多层感知器

--END--