一、BP神经网络介绍
BP神经网络是一种按照误差逆向传播算法训练的多层前馈神经网络,是应用最广泛的神经网络模型之一,也是目前深度学习的理论基础。目前深度学习网络的参数优化是基于BP和梯度回归的。我们以一个简单的神经网络为例,简单地介绍一下BP神经网络的结构。
假设数据 , 。其中 为维度为𝑛的向量, 。如果我们使用一个简单的BP神经网络进行预测。那么我们的预测公式为:
以上是一个简单的BP神经网络公式, 和 是参数。其中 的维度是 , 的维度是1×𝑚的向量,𝑦′为预测值,𝑓,𝑔为激活函数(这里我们使用sigmoid函数)。为了让神经网络能够准确地进行预测,我们需要对参数 进行优化。
二、BP神经网络的公式推导
BP神经网络分为前向网络和后向网络,前向网络是计算目标值,后向网络用于梯度计算。
前向计算:
输入:
第一层:
第二层:
输出:
反向传播:
令损失函数为:
第二层梯度计算:
令
第一层梯度计算:
其中 ,令
因为 , ,因此上式也很好推导得到。
由此:
至此,BP神经网络的推导全部完成。为了更加直观地感受,我们接下来对一步进行分解。
1、首先是前向步骤
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
x=np.array([[1,2],[2,3]])
lr=0.01
1:第一层网络
w_1=np.array([[0.3,0.4],[0.5,0.5]])
b_1=0.5
def forward1(x):
a_0=x
a_1=sigmoid(np.dot(w_1,x)+b_1)
return a_1
a_1=forward1(x)
a_1
'''
array([[0.83201839, 0.90887704],
[0.88079708, 0.95257413]])
'''
2:第二层网络
w_2=np.array([2,3])
b_2=0.5
def forward2(x):
a1=x
a_2=sigmoid(np.dot(w_2,x)+b_2)
return a_2
t=forward2(a_1)
print(t)
'''
[0.99188931 0.99437826]
'''
3:计算loss
def cal_cross_loss(y, t):
loss=np.sum(-y * np.log(t)- (1 - y) * np.log(1 - t))/t.shape[0]
return loss
y=np.array([0,1])
loss=cal_cross_loss(y,t)
loss
'''
2.4101046854144412
'''
2、然后就是反向传播
1:输出层梯度计算
def cal_grad(y, t):
grad = t - y
return grad
delta_2=cal_grad(y,t)
delta_2
'''
array([ 0.99188931, -0.00562174])
'''
2:第二层梯度计算
z_1=np.dot(w_1,x)+b_1
def backward2():
global w_2,b_2
grad_w=delta_2*a_1
grad_b=np.sum(delta_2)
w_2=w_2-lr*grad_w
b_2=b_2-lr*grad_b
print(w_2,b_2)
return np.dot(delta_2,w_2)*(1-z_1)*z_1
delta_1=backward2()
delta_1
'''
[[1.9917473 3.00005109]
[1.99126347 3.00005355]] 0.49013732434551505
array([[ -1.88582254, -8.8469707 ],
[ -3.92879696, -17.75311845]])
'''
3:第一层梯度计算
def backward1():
global w_1,b_1
grad_w=delta_1*a_1
grad_b=np.sum(delta_1)
w_1=w_1-lr*grad_w
b_1=b_1-lr*grad_b
return
backward1()
print(w_1,b_1)
'''
[[0.31569039 0.48040809]
[0.53460473 0.66911161]] 0.8241470864784078
'''
三、BP神经网络完整代码
1:输出层
def cal_cross_loss(y, t):
loss = np.sum(-y * np.log(t) - (1 - y) * np.log(1 - t)) / t.shape[0]
return loss
def cal_grad(y, t):
grad = -y / t + (1 - y) / (1 - t)
return grad
class Loss:
def forward(self, y, t):
self.loss = cal_cross_loss(y, t)
self.delta = cal_grad(y, t)
return self.loss
def backward(self):
return self.delta
2:网络层
class FC:
def init(self, in_num, out_num, lr=0.01):
self._in_num = in_num
self._out_num = out_num
self.w = np.random.rand(in_num, out_num) # 生成out行,in列矩阵
self.b = np.zeros(out_num)
self.lr = lr
def _sigmoid(self, in_data):
return 1 / (1 + np.exp(-in_data))
def forward(self, in_data):
self.z = np.dot(in_data, self.w, ) + self.b
self.top_val = self._sigmoid(self.z)
self.bottom_val = in_data
return self.top_val
def backward(self, loss):
residual_z = loss * self.top_val * (1 - self.top_val)
grad_w = np.dot(self.bottom_val.T, residual_z)
grad_b = np.sum(residual_z)
self.w -= self.lr * grad_w
self.b -= self.lr * grad_b
residual_x = np.dot(residual_z,self.w.T)
return residual_x
3:模型训练
class Net:
def __init__(self, input_num=2, hidden_num=4, out_num=1, lr=0.05):
self.fc1 = FC()
self.fc1.init(input_num, hidden_num, lr)
self.fc2 = FC()
self.fc2.init(hidden_num, out_num, lr)
self.loss = Loss()
def trian(self, x, y):
for i in range(1000):
layer1out = self.fc1.forward(x)
layer2out = self.fc2.forward(layer1out)
loss = self.loss.forward(y, layer2out)
delta2 = self.loss.backward()
delta1 = self.fc2.backward(delta2)
saliency = self.fc1.backward(delta1)
layer1out = self.fc1.forward(X)
layer2out = self.fc2.forward(layer1out)
print(X)
print(y)
print(layer2out)
import numpy as np
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y=np.array([[0],[0],[0],[1]])
net=Net()
net.__init__(2,4,1,0.1)
net.trian(X,y)
'''
[[0 0]
[0 1]
[1 0]
[1 1]]
[[0]
[0]
[0]
[1]]
[[0.00227556]
[0.01547024]
[0.01542629]
[0.98041847]]
'''