文章目录
- 一、前向传播与反向传播
- 二、代码演示
一、前向传播与反向传播
“”"
反向传播算法包含两阶段:
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
2.反向传播:
为了应用反向传播算法,我们的激活函数必须是可微的,
这样我们就可以计算误差对给定权重wi、j、损失(E)、节点输出oj和网络输出netj的偏导数。
“”"
二、代码演示
主函数中 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))