文章目录

  • 一、前向传播与反向传播
  • 二、代码演示


一、前向传播与反向传播

“”"
反向传播算法包含两阶段:
1.前向传播,我们的输入通过网络,得到的输出预测(也称为传播阶段)。
2.反向传播,我们计算网络的最后一层的损失函数的梯度,并使用这个梯度应用链规则来更新我们网络中的权重(也称为权重更新阶段)。

1.前向传播:
    1)初始化网络权重值
    2)计算:每个神经元 输入与权重点积,然后应用激活函数(S型函数 σ=1/(1+e^-x)),输出值
    3)例:计算隐层三个输入:
        σ((0×0.351) + (1×1.076) + (1×1.116)) = 0.899
        σ((0× −0.097) + (1× −0.165) + (1×0.542)) = 0.593
        σ((0×0.457) + (1× −0.165) + (1× −0.331)) = 0.378
        输出层的输入:
        σ((0.899×0.383) + (0.593× −0.327) + (0.378× −0.329)) = 0.506
    4)阶跃函数分类标签
        f(net) = ( 1 if net > 0 0 otherwise)
        所以最后输出为 1

前向传播python代码_python

2.反向传播:
    为了应用反向传播算法,我们的激活函数必须是可微的,
    这样我们就可以计算误差对给定权重wi、j、损失(E)、节点输出oj和网络输出netj的偏导数。

“”"

前向传播python代码_前向传播python代码_02

二、代码演示

主函数中 neuralnetwork.py:

"实现反向传播"
"neuralnetwork.py"
import numpy as np

class NeuralNetwork:
    def __init__(self, layers, alpha=0.1):
        self.W = []  #权重矩阵
        self.layers = layers #图层
        self.alpha = alpha #学习率
        #初始化W
        #从第一层的索引开始循环,到达最后两层之前停止
        for i in np.arange(0,len(layers)-2):
            """
            例:layers[i] = 2,layers[i+1] = 2 为了使2层之间所有节点连接--w:2*2
            但是要加偏置项b: layers[i]+1 = 3,layers[i+1]+1 = 3,---w:3*3
            ----通过除以当前层中节点数的平方根来缩放w,从而对每个神经元的输出进行归一化
            """
            w = np.random.randn(layers[i]+1,layers[i+1]+1)
            self.W.append(w/np.sqrt(layers[i]))
        #最后两层是一种特殊情况,其中输入连接需要一个偏差项,但输出不需要(不太理解)
        w = np.random.randn(layers[-2]+1, layers[-1])
        self.W.append(w/np.sqrt(layers[-2]))

    #调试函数,返回网络结构
    def __repr__(self):
        return "NeuralNetwork:{}".format("-".join(str(l) for l in self.layers))

# nn = NeuralNetwork([2,2,1])
# print(nn)
    #定义激活函数(s型)
    def sigmoid(self,x):
        return 1.0/(1+np.exp(-x))
    #s型函数的导数(反向传播要用)、x已经通过了s型函数
    def sigmoid_deriv(self,x):
        """y=1/(1+np.exp(-x)) dy=y*(1-y)"""
        return x * (1-x)
    #训练网络函数
    def fit(self,X,y,epochs=100, displayUpdate=100):
        #输入插一列,是偏置在W中
        X = np.c_[X,np.ones(X.shape[0])] #X*W
        for epoch in np.arange(0,epochs):
            for (x,target) in zip(X,y):
                self.fit_partial(x, target)
            if epoch == 0 or (epoch+1)%displayUpdate == 0:
                loss = self.calculate_loss(X,y)
                print("[INFO] epoch={},loss={:.7f}".format(epoch+1,loss))

    #反向传播算法,x:单个数据点,y:对应的标签
    def fit_partial(self,x,y):
        A = [np.atleast_2d(x)]
        "前向传播"
        for layer in np.arange(0, len(self.W)):
            net = A[layer].dot(self.W[layer])  #输入*权重
            out = self.sigmoid(net)  #激活函数、 输出
            A.append(out) #A最后一列就是网络的输出(激活列表),即预测(不是很明白)

        "反向传播"
        "1.计算我们的预测(激活列表中的最终输出)与真值之间的差异"
        error = A[-1] - y
        "2.列表D的第一列为输出层的误差*输出值的激活函数的导数、链式法则"
        D = [error*self.sigmoid_deriv(A[-1])]
        #构建列表D,给定网络中最后一层的增量,我们现在可以使用循环向后工作
        for layer in np.arange(len(A)-2, 0 ,-1):  #-2是因为最后一层已计算
            """当前层的增量等于前一层增量,点乘当前层的权重矩阵在乘当前层激活函数的导数,"""
            """不是很理解"""
            delta = D[-1].dot(self.W[layer].T)
            delta = delta*self.sigmoid_deriv(A[layer])
            D.append(delta)

        "3.更新权重矩阵"
        D = D[::-1]
        for layer in np.arange(0,len(self.W)):
            self.W[layer] += -self.alpha*A[layer].T.dot(D[layer])

    #预测
    def predict(self, X,addBias=True):
        #X:所预测标签对应的数据点
        p = np.atleast_2d(X)
        if addBias:
            p = np.c_[p, np.ones(p.shape[0])]
        for layer in np.arange(0,len(self.W)):
            p = self.sigmoid(np.dot(p,self.W[layer]))
        return p

    #计算损失
    def calculate_loss(self,x,targets):
        targets = np.atleast_2d(targets)
        predictions = self.predict(x,addBias=False)
        loss = 0.5*np.sum((predictions-targets)**2)
        return loss

主函数 :Backpropagation.py

import numpy as np
import neuralnetwork

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])

nn = neuralnetwork.NeuralNetwork([2,2,1],alpha=0.5)
nn.fit(X,y,epochs=20000)
for (x, target) in zip(X, y):
    pred = nn.predict(x)[0][0]
    step = 1 if pred > 0.5 else 0
    print("[INFO] data={}, ground-truth={}, pred={:.4f}, step={}".format( x, target[0], pred, step))