Mini-patch:从零开始的反向传播(附详细代码)

文章将重点介绍mini-patch逐步实现的反向传播算法。有许多教程和博客详细介绍了反向传播算法,以及演算和代数背后的所有逻辑。因此,我将跳过这一部分,并在数学和使用Python的实现中切入方程式。

Mini-patch:从零开始的反向传播(附详细代码)

关于为什么我们应该从头开始实现一个算法,即使几乎所有框架都已经可以使用它,这也是一个长期存在的普遍问题。显然,在使用某些高级框架时,你甚至都不会注意到反向传播确实发挥了魔力。要完全颠倒地理解它,一次尝试肯定是不够的。反向传播在游戏中也是可以进行实验的。

为什么要使用mini-patch?

mini-patch的原理很简单。通过将数据分成小批处理,并在训练循环的每次迭代中为算法提供一部分数据集,可以节省内存和处理时间。一次馈入10000x10000矩阵不仅会消耗内存,还会花费很长时间才能运行。相反,每次迭代将其降低到50个不仅会减少内存使用量,而且可以跟踪进度。

注意:这与随机方法不同,在随机方法中,我们从每个类别的数据中抽取了分层样本,并在假设模型可以推广的基础上进行训练。

开始实验

这是将用于实验的数据头。

Mini-patch:从零开始的反向传播(附详细代码)

此处的目标变量是占用率,它是类别变量(0/1)。这将是我们将要编码的架构。

Mini-patch:从零开始的反向传播(附详细代码)

算法:

对于i:= 1到i:= m:

执行正向传播或正向传递以计算每一层中神经元的激活值。

Mini-patch:从零开始的反向传播(附详细代码)

反向传播步骤:

  • 使用数据中的标签计算误差项(MSE或LogLoss或您的期望):
Mini-patch:从零开始的反向传播(附详细代码)

  • 隐藏层中的误差项使用以下公式计算:
Mini-patch:从零开始的反向传播(附详细代码)

  • 设置梯度:
    初始化Δ= 0
Mini-patch:从零开始的反向传播(附详细代码)

3.梯度下降和权重更新步骤:

Mini-patch:从零开始的反向传播(附详细代码)

代码展示:

<code>weight_dim = [5,H,1] 
#[number of input features, number of hidden units, number of output units]

print("Initializing using He initialization")
np.random.seed(3)
w1 = np.random.randn(weight_dim[1],weight_dim[0]) * np.sqrt(2/weight_dim[0]) # 0.01
b1 = np.zeros((weight_dim[1],1))
w2 = np.random.randn(weight_dim[2],weight_dim[1]) * np.sqrt(2/weight_dim[1]) # 0.01
b2 = np.zeros((weight_dim[2],1))/<code>

如前所述,这将是一个三层网络。为了使梯度和误差方程更好,更容易地识别,我们保持层的数量简洁。之后,我们将定义一个函数,该函数将用作网络中的转发器。

<code>def forward(X,w1,w2,b1,b2):
    z1 = np.matmul(w1,np.transpose(np.asmatrix(X))) + b1
    a1 = sigmoid(z1)

    z2 = np.matmul(w2, a1) + b2
    a2 = sigmoid(z2)
    
    return z1, a1, z2, a2/<code>

这里要注意的一件事是,已经将Input层视为我的第0层。可能还有其他博客/教程被认为是第一名。因此,绝对要为所需的索引编制索引。

因此,现在,在初始化权重和偏差并定义前向传播函数之后,我们将在size = data-of-setset / N的mini-patch上定义反向传播函数。通过调整N来调整所需的批次大小。

<code>def backprop(w1,b1,w2,b2,X_train,X_test):
    
    for i in range(epoch):
        
        no_of_batches = len(X_train) // N
        
        for j in range(no_of_batches):
            
            # Initilazing gradients
            
            delta1 = np.zeros(w1.shape)   #(5,5)
            delta2 = np.zeros(w2.shape)   #(1,5)
            db1 = 0.0
            db2 = 0.0
            
            
            for row in range(j*N,(j+1)*N):
                
                # Drop the date column and the index column
                X = X_train[row, 2:7]
                Y = X_train[row, 7]
                
                #feed forward
                z1  ,  a1  ,  z2  , a2 = forward(X,w1,w2,b1,b2)
                #(5,1) (5,1) (1,1) (1,1)
                
                h = a2 # (1,1)
                   
                # initializations

                d3 = a2 - Y  #(1,1)
                
                delta2 += d3 * np.transpose(a2)  #(1,1)
                db2 += d3

                d2 = np.multiply((np.transpose(w2) * d3), sigmoid_gradient(z1),dtype=float)  #(5,1)
 
                delta1 += d2 * np.transpose(a1)  #(5,5)

                db1 += d2
                        
            
            # Gradient Descent Step
            #updating weights after every batch by averaging the gradients
            w1 = w1 - lr * 1.0/N * delta1 #taking the average of gradients
            b1 = b1 - lr * 1.0/N * db1
            w2 = w2 - lr * 1.0/N * delta1
            b2 = b2 - lr * 1.0/N * db2
            
            
            
        print("************************************************")
        print("Train error after epoch {} is: ".format(i), np.sum(error(calc_out(X_train[:,2:7],w1,b1,w2,b2),X_train[:,7])) / len(X_train) * 100)    
        print("Test error after epoch {} is: ".format(i), np.sum(error(calc_out(X_test[:,2:7],w1,b1,w2,b2),X_test[:,7])) / len(X_test) * 100)
        print("************************************************")
        print()
    
        train_error[i] = np.sum(error(calc_out(X_train[:,2:7],w1,b1,w2,b2),X_train[:,7])) / len(X_train) * 100
        test_error[i] = np.sum(error(calc_out(X_test[:,2:7],w1,b1,w2,b2),X_test[:,7])) / len(X_test) * 100
        
    return [w1,b1,w2,b2]/<code>

步骤分解

  • 如前所述,Ist循环会遍历您想要使模型遍历数据的次数,只需将其放在神经网络术语“时代”中即可。
  • 第二次循环:指定了批次数量后,此循环针对每个时期“ i”遍历每个微型批次
  • 第三循环遍历该小批量中的每个训练示例,并计算梯度和误差值
  • 最后,对于每个批次,都执行梯度下降步骤,并对权重矩阵进行更改。

这就是mini-patch的反向传播实现。需要注意的是,此实验为网络中的每一层使用了一个矩阵变量,当网络规模扩大时,这是一种不明智的做法,我们这样做是为了了解它的实际工作原理。如果要增加“隐藏层”的数量,可以简单地使用3d矩阵进行误差和梯度计算,其中第3维将保存该层的值。


分享到:


相關文章: