为了更好理解神经网络的反向传播(BP), 本文我们自己推导出一个两层模型的BP的计算公式和并进行实际演算。然后会给出演算后的最终结果及python代码。
提出问题
以下是我们目标公式和输入数据,看我们如何通过反向推导的方式求出w和b:
首先随便初始化各个参数,当然也可以用随机数生成满足正态分布,这里为了计算流程方便,用了指定参数。
W = [3,2,1] ………………………………………. 实际值为[1,2,3]
b = 0 ………………………………………………实际值为1
看一下用这组参数算出来的:
数学公式的推导
我们看看怎么样能够通过调整参数满足条件。我们需要一个个的调整这四个参数。
那么到底调多少呢? 我们假设当期他参数不变的情况下,cost值随w的变化如下:
显然,cost随w变化的幅度越大,则我们应该调整得越多,cost随w变化的幅度越小,我们应该调整得越少,这也符合我们的常识。在微积分领域,我们得出:调整的幅度其实就是cost针对w的微分。也就是:
首先给出我们的数学公式:
由于我们的目标是使:
那么微分方程为:
同理:
因为我们有四个参数, 因此每次不能一下调整到位, 因此, 我们设了一个参数 代表调整的系数
因此调整公式为:
实际演算
所以, 我们按照这个逻辑试着计算一下:
接下来按照相同的input和output调整其他的w和b参数.
按照这一算法,我们演算的各个步骤及结果如下:
其中,每轮变化的参数以红色字体标出,而紫色的数列代表了每轮的误差数值(cost/sum), 可以看到其绝对值是逐渐变小的。
演算1000轮后的结果
w= [1.00038695,1.99995515,2.99970678]
b= 0.999463501861
TotaoLoss= 0.000114250142628
可以看出基本达到了目的,最终各个参数的演变情况如下图(1000回合):
而误差值的变化情况如下:
实际代码
lmbda=0.1
n_input=3
n_output=1
training_epochs=1000
#y = x1+x2*2+x3*3+1
input = [np.array([2, 0, 1]), np.array([4, 5, 3]), np.array([7, 6, 8]), np.array([ 9, 10, 11]), np.array([14, 12, 13])]
output = [6, 24, 44, 63, 78]
def act(z):
return z
def PointMat(a,b):
return np.dot(a,b)
def Learn(Input,Output):
w,b = GenWB()
#准备后续画图的参数
w0a=[]
w1a=[]
w2a=[]
ba=[]
lossa=[]
for i in range(training_epochs):#Train 1000 rounds
losssum = 0
for j in range(len(Input)):#Train each data pairs
for k in range(len(Input[j])): #Adjust each w
sumup = np.float64(PointMat(Input[j],w)+b)
loss = (sumup-Output[j])/sumup
losssum += abs(loss)
delta = 0
if Input[j][k] < 1e-06:
continue
else:
delta = lmbda*act(loss)*Input[j][k]
oldwk = w[k]
w[k] = w[k] - delta
b = b - lmbda*act(loss) #adjust bias
#Try to draw graph
w0a.append(w[0])
w1a.append(w[1])
w2a.append(w[2])
ba.append(b)
lossa.append(losssum)
print("w=",w,"b=",b,",TotaoLoss=",losssum)
#开始画图
xa = np.arange(training_epochs)
plt.plot(xa, w0a, 'r-', label='W0')
plt.plot(xa, w1a, 'g-', label='W1')
plt.plot(xa, w2a, 'b-', label='W2')
plt.plot(xa, ba, 'c-', label='Bias')
plt.legend()
plt.show()
plt.plot(xa, lossa, 'ro', label='loss')
plt.legend()
plt.show()