一文搞懂反向传播及Python实现

文章目录

  • Model
  • 前向传播
  • 反向传播
    • 计算损失,比如L2损失
    • 求${\theta}^3_{11}$对J的影响
    • 求${\theta}^2_{11}$对J的影响
    • 求${\theta}^1_{11}$对J的影响
    • 误差反传
  • 计算时的注意事项
    • 1.每个权重单独计算 vs 整个权重矩阵一下计算
    • 2.只计算一个样本 vs 计算一个batch
  • PYTHON实现
    • 偏置项怎么加进去?

Model

一文搞懂反向传播及Python实现_第1张图片

前向传播

一文搞懂反向传播及Python实现_第2张图片

反向传播

计算损失,比如L2损失

在这里插入图片描述
然后计算每个权重对J的影响

θ 11 3 {\theta}^3_{11} θ113对J的影响

一文搞懂反向传播及Python实现_第3张图片
一文搞懂反向传播及Python实现_第4张图片

θ 11 2 {\theta}^2_{11} θ112对J的影响

一文搞懂反向传播及Python实现_第5张图片
一文搞懂反向传播及Python实现_第6张图片

θ 11 1 {\theta}^1_{11} θ111对J的影响

一文搞懂反向传播及Python实现_第7张图片

误差反传

一文搞懂反向传播及Python实现_第8张图片
一文搞懂反向传播及Python实现_第9张图片
一文搞懂反向传播及Python实现_第10张图片

每一层的残差都由后一层的残差乘以两层之间的权重矩阵,再乘以当前层的激活函数的导数得到。
权重梯度由前面的激活值和后面的残差乘积得到的

计算时的注意事项

1.每个权重单独计算 vs 整个权重矩阵一下计算

上面都是只计算单个权重的梯度,怎么放到矩阵里,一下计算出来。
首先计算误差反传到每一层:
在这里插入图片描述
一文搞懂反向传播及Python实现_第11张图片

一文搞懂反向传播及Python实现_第12张图片

然后计算每一层和误差的关系:

一文搞懂反向传播及Python实现_第13张图片
一文搞懂反向传播及Python实现_第14张图片
一文搞懂反向传播及Python实现_第15张图片

2.只计算一个样本 vs 计算一个batch

神经元才有batch,权重连接没有
假设输入 X 2 ∗ m X_{2*m} X2m,有m个样本。
则他们的误差反传不受影响,同样梯度计算也不受影响。

PYTHON实现

# -*- coding: utf-8 -*-
"""
python code for neural network implementations
"""
import numpy as np
import matplotlib.pyplot as plt

def sigmoid(z):
        return 1 / (1 + np.exp(-z))

def sigmoid_der(z):
        return sigmoid(z) * (1 - sigmoid(z))
    
class NeuralNetwork:
    def __init__(self, x, y):
        self.input = x
        self.D, self.N = x.shape
        self.y = y
        
        hidden1_units = 10
        hidden2_units = 5
        
        self.weight1 = 2 * np.random.rand(self.D, hidden1_units) - 1
        self.weight2 = 2 * np.random.rand(hidden1_units, hidden2_units) - 1
        self.weight3 = 2 * np.random.rand(hidden2_units, 1) - 1

    def forward(self):
        # layer 1
        self.z1 = np.dot(self.weight1.T, self.input)
        self.a1 = sigmoid(self.z1)
        self.z2 = np.dot(self.weight2.T, self.a1)
        self.a2 = sigmoid(self.z2)
        self.z3 = np.dot(self.weight3.T, self.a2)
        self.a3 = sigmoid(self.z3)
    
    def calc_loss(self):
        # L2 loss
        self.loss = np.sum((self.a3 - self.y) ** 2) / self.N
        print("loss:", self.loss)
    
    def backward(self):
        # calculate error
        self.delta3 = sigmoid_der(self.z3) * 2 * (self.a3 - self.y)
        self.delta2 = sigmoid_der(self.z2) * np.dot(self.weight3, self.delta3)
        self.delta1 = sigmoid_der(self.z1) * np.dot(self.weight2, self.delta2)
        
        # calculate gradients
        self.dw3 = np.dot(self.a2, self.delta3.T)
        self.dw2 = np.dot(self.a1, self.delta2.T)
        self.dw1 = np.dot(self.input, self.delta1.T)
        
        # update w
        self.weight1 -= self.dw1 * 0.3
        self.weight2 -= self.dw2 * 0.3
        self.weight3 -= self.dw3 * 0.3
        


# data1
inputs = np.array([[0, 0, 1, 1],
                   [1, 1, 1, 1], 
                   [1, 0, 1, 1]]).T

outputs = np.array([[0],
                    [1],
                    [1]]).T

nn = NeuralNetwork(inputs, outputs)
nn.forward()
nn.calc_loss()

for i in range(1000):
    nn.backward()
    nn.forward()
    nn.calc_loss()

print("predict results:", nn.a3)

相似的实现:https://github.com/erilyth/Neural-Network-Implementation

偏置项怎么加进去?

参考:
深度学习 — 反向传播(BP)理论推导 - 简书
Backpropagation 算法的推导与直观图解 - 文之 - 博客园

你可能感兴趣的:(深度学习)