一、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=xa_1=sigmoid(np.dot(w_1,x)+b_1)return a_1a_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=xa_2=sigmoid(np.dot(w_2,x)+b_2)return a_2t=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 lossy=np.array([0,1])
loss=cal_cross_loss(y,t)
loss'''
2.4101046854144412
'''
2、然后就是反向传播
1:输出层梯度计算
def cal_grad(y, t):grad = t - yreturn 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_2grad_w=delta_2*a_1grad_b=np.sum(delta_2)w_2=w_2-lr*grad_wb_2=b_2-lr*grad_bprint(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_1grad_w=delta_1*a_1grad_b=np.sum(delta_1)w_1=w_1-lr*grad_wb_1=b_1-lr*grad_breturn
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 lossdef cal_grad(y, t):grad = -y / t + (1 - y) / (1 - t)return gradclass Loss:def forward(self, y, t):self.loss = cal_cross_loss(y, t)self.delta = cal_grad(y, t)return self.lossdef backward(self):return self.delta
2:网络层
class FC:def init(self, in_num, out_num, lr=0.01):self._in_num = in_numself._out_num = out_numself.w = np.random.rand(in_num, out_num) # 生成out行,in列矩阵self.b = np.zeros(out_num)self.lr = lrdef _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.bself.top_val = self._sigmoid(self.z)self.bottom_val = in_datareturn self.top_valdef 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_wself.b -= self.lr * grad_bresidual_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]]
'''