BP神經網絡反向傳播之計算過程分解(詳細版)


  摘要:本文先從梯度下降法的理論推導開始,說明梯度下降法為什么能夠求得函數的局部極小值。通過兩個小例子,說明梯度下降法求解極限值實現過程。在通過分解BP神經網絡,詳細說明梯度下降法在神經網絡的運算過程,並詳細寫出每一步的計算結果。該過程通俗易懂,有基本的高數和線代基礎即可理解明白。最后通過tensorflow實現一個簡單的線性回歸,對照理解梯度下降法在神經網絡中的應用。碼字不易,轉載請標明出處。該文中部分內容是研究生課堂論文內容,為避免課程論文被誤解為抄襲,所用截圖特意添加水印。

  一.梯度下降法的理論推導:

 

 

 

 

 

 

二.求解一個簡單的一元函數極小值

例:求函數y=(x+1)^2-1的極小值:

實現環境:python3.6

相關模塊:numpy 、 matplotlib

import numpy as np
from matplotlib import pyplot as plt
def function_1d(x):
    '''
    目標函數:求目標函數的極小值
    x:自變量,標量
    返回:因變量,標量
    '''
    return (x+1)**2-1
##2.定義梯度函數
def grad_1d(x):
    '''
    :param x: 自變量,標量
    :return: 因變量,標量
    '''
    return 2*(x+1)
##3.定義迭代過程
def gradient_descent_1d(grad,current_x,learning_rate=0.0001,precision=0.0001,max_iters=10000):
    '''
    一維問題的梯度下降法
    :param grad: 目標函數的梯度
    :param current_x: 當前x值
    :param learning_rate: 學習率=η
    :param precision: 收斂精度
    :param max_iters: 最大迭代次數
    :return: 極小值
    '''
    ##創建一個空列表用於接收每次移動后的current_x
    cur_x_list = []
    cur_x_list.append(current_x)
    for i in range(max_iters):
        grad_current = grad(current_x)
        if abs(grad_current)<precision:
            break            ##梯度小於收斂精度時,視為收斂
        current_x = current_x-grad_current*learning_rate
        cur_x_list.append(current_x)
        print('第%s次迭代:x=%s'%(i,current_x))
    print('極小值點(%s,%s)'%(current_x,function_1d(current_x)))
    return cur_x_list
##4.運行返回極小值和x移動軌跡
if __name__ == '__main__':
    cur_x_list = gradient_descent_1d(grad_1d,learning_rate=0.9,current_x=13)  ##開始梯度下降,並且返回每次變化后的x,學習率=η=0.9

    cur_x_array = np.array(cur_x_list)
    cur_y_array = function_1d(cur_x_array)
    ##繪制曲線圖
    plt.figure(figsize=(6,4))
    plt.subplot()
    x = cur_x_array
    y = function_1d(x)
    plt.plot(x, y, color='b', linewidth=1)
    ##繪制函數圖
    x1 = np.arange(-15,15,1)
    y1 = np.array(function_1d(x1))
    plt.plot(x1, y1, color='y', linewidth=1)
    ##散點圖
    plt.scatter(cur_x_array,cur_y_array,s=20,c="#ff1212",marker='o')
    plt.xlabel('梯度下降示例(汽車優化設計)',fontproperties = 'SimHei',fontsize = 10)
    plt.ylabel('y=(x+1)**2 -1',fontproperties = 'SimHei',fontsize = 10)
    plt.show()


###輸出結果
第0次迭代:x=-12.2
第1次迭代:x=7.960000000000001
第2次迭代:x=-8.168000000000003
第3次迭代:x=4.734400000000003
第4次迭代:x=-5.587520000000003
第5次迭代:x=2.670016000000002
第6次迭代:x=-3.936012800000002
第7次迭代:x=1.3488102400000015
第8次迭代:x=-2.8790481920000017
第9次迭代:x=0.5032385536000015
第10次迭代:x=-2.202590842880001
第11次迭代:x=-0.03792732569599888
第12次迭代:x=-1.769658139443201
第13次迭代:x=-0.3842734884454393
第14次迭代:x=-1.4925812092436486
第15次迭代:x=-0.6059350326050811
第16次迭代:x=-1.3152519739159352
第17次迭代:x=-0.7477984208672518
第18次迭代:x=-1.2017612633061985
第19次迭代:x=-0.8385909893550412
第20次迭代:x=-1.1291272085159672
第21次迭代:x=-0.8966982331872263
第22次迭代:x=-1.082641413450219
第23次迭代:x=-0.9338868692398249
第24次迭代:x=-1.05289050460814
第25次迭代:x=-0.957687596313488
第26次迭代:x=-1.0338499229492095
第27次迭代:x=-0.9729200616406324
第28次迭代:x=-1.021663950687494
第29次迭代:x=-0.9826688394500047
第30次迭代:x=-1.0138649284399963
第31次迭代:x=-0.9889080572480029
第32次迭代:x=-1.0088735542015976
第33次迭代:x=-0.9929011566387219
第34次迭代:x=-1.0056790746890225
第35次迭代:x=-0.995456740248782
第36次迭代:x=-1.0036346078009744
第37次迭代:x=-0.9970923137592205
第38次迭代:x=-1.0023261489926236
第39次迭代:x=-0.9981390808059011
第40次迭代:x=-1.001488735355279
第41次迭代:x=-0.9988090117157767
第42次迭代:x=-1.0009527906273785
第43次迭代:x=-0.9992377674980972
第44次迭代:x=-1.0006097860015222
第45次迭代:x=-0.9995121711987822
第46次迭代:x=-1.0003902630409742
第47次迭代:x=-0.9996877895672206
第48次迭代:x=-1.0002497683462235
第49次迭代:x=-0.9998001853230212
第50次迭代:x=-1.000159851741583
第51次迭代:x=-0.9998721186067335
第52次迭代:x=-1.0001023051146132
第53次迭代:x=-0.9999181559083095
第54次迭代:x=-1.0000654752733524
第55次迭代:x=-0.9999476197813181
第56次迭代:x=-1.0000419041749455
極小值點(-1.0000419041749455,-0.9999999982440401)

Process finished with exit code 0
一元函數梯度下降法求解極小值

三.求解一個簡單的二元函數的極小值

import numpy as np
from tqdm import tqdm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import  Axes3D
def plot_3d():
    fig = plt.figure(figsize=(12,8))
    ax = Axes3D(fig)
    x = np.arange(-3,3,0.1)
    y = np.arange(-3,3,0.1)
    ##對x,y數據執行網格化
    x,y = np.meshgrid(x,y)
    z = -(z1-2*z2)*0.1
    ax.plot_surface(x,y,z,
                    rstride=1,##retride(row)指定行的跨度
                    cstride=1,##retride(column)指定列的跨度
                    cmap='rainbow')  ##設置顏色映射
    ##設置z軸范圍
    ax.set_zlim(-2,2)
    ##設置標題
    plt.title('汽車優化設計之梯度下降--目標函數',fontproperties = 'SimHei',fontsize = 20)
    plt.show()
# plot_3d()


'''二維梯度下降法'''
def func_2d_single(x,y):
    '''
    目標函數傳入x,y
    :param x,y: 自變量,一維向量
    :return: 因變量,標量
    '''
    z1 = np.exp(-x**2-y**2)
    z2 = np.exp(-(x-1)**2-(y-1)**2)
    z = -(z1-2*z2)*0.5
    return z
def plot_3d():
    fig = plt.figure(figsize=(12,8))
    ax = Axes3D(fig)
    x = np.arange(-3,3,0.1)
    y = np.arange(-3,3,0.1)
    ##對x,y數據執行網格化
    x,y = np.meshgrid(x,y)
    z = func_2d_single(x,y)
    ax.plot_surface(x,y,z,
                    rstride=1,##retride(row)指定行的跨度
                    cstride=1,##retride(column)指定列的跨度
                    cmap='rainbow')  ##設置顏色映射
    ##設置z軸范圍
    ax.set_zlim(-2,2)
    ##設置標題
    plt.title('汽車優化設計之梯度下降--目標函數3維圖',fontproperties = 'SimHei',fontsize = 20)
    plt.show()
plot_3d()

def func_2d(xy):
    '''
    目標函數傳入xy組成的數組,如[x1,y1]
    :param xy: 自變量,二維向量  (x,y)
    :return: 因變量,標量
    '''
    z1 = np.exp(-xy[0]**2-xy[1]**2)
    z2 = np.exp(-(xy[0]-1)**2-(xy[1]-1)**2)
    z = -(z1-2*z2)*0.5
    return z
def grad_2d(xy):
    '''
    目標函數的梯度
    :param xy: 自變量,二維向量
    :return: 因變量,二維向量  (分別求偏導數,組成數組返回)
    '''
    grad_x = 2*xy[0]*(np.exp(-(xy[0]**2+xy[1]**2)))
    grad_y = 2*xy[1]*(np.exp(-(xy[0]**2+xy[1]**2)))
    return np.array([grad_x,grad_y])
def gradient_descent_2d(grad, cur_xy=np.array([1, 1]), learning_rate=0.001, precision=0.001, max_iters=100000000):
    '''
    二維目標函數的梯度下降法
    :param grad: 目標函數的梯度
    :param cur_xy: 當前的x和y值
    :param learning_rate: 學習率
    :param precision: 收斂精度
    :param max_iters: 最大迭代次數
    :return: 返回極小值
    '''
    print(f"{cur_xy} 作為初始值開始的迭代......")
    x_cur_list = []
    y_cur_list = []
    for i in tqdm(range(max_iters)):
        grad_cur = grad(cur_xy)
        ##創建兩個列表,用於接收變化的x,y
        x_cur_list.append(cur_xy[0])
        y_cur_list.append(cur_xy[1])
        if np.linalg.norm(grad_cur,ord=2)<precision:  ##求范數,ord=2 平方和開根
            break    ###當梯度接近於0時,視為收斂
        cur_xy = cur_xy-grad_cur*learning_rate
        x_cur_list.append(cur_xy[0])
        y_cur_list.append(cur_xy[1])
        print('第%s次迭代:x,y = %s'%(i,cur_xy))
    print('極小值 x,y = %s '%cur_xy)
    return (x_cur_list,y_cur_list)
if __name__=="__main__":
    current_xy_list = gradient_descent_2d(grad_2d)
    fig = plt.figure(figsize=(12,8))
    ax = Axes3D(fig)
    a = np.array(current_xy_list[0])
    b = np.array(current_xy_list[1])
    c = func_2d_single(a,b)
    ax.scatter(a,b,c,c='Black',s=10,alpha=1,marker='o')
    x = np.arange(-2,2,0.05)
    y = np.arange(-2,2,0.05)
    ##對x,y數據執行網格化
    x,y = np.meshgrid(x,y)
    z = func_2d_single(x,y)
    ax.plot_surface(x,y,z,
                    rstride=1,##retride(row)指定行的跨度
                    cstride=1,##retride(column)指定列的跨度
                    cmap='rainbow',
                    alpha=0.3
                    )  ##設置顏色映射
    # ax.plot_wireframe(x,y,z,)
    ##設置z軸范圍
    ax.set_zlim(-2,2)
    ##設置標題
    plt.title('汽車優化設計之梯度下降--二元函數',fontproperties = 'SimHei',fontsize = 20)
    plt.xlabel('x',fontproperties = 'SimHei',fontsize = 20)
    plt.ylabel('y', fontproperties='SimHei', fontsize=20)
    plt.show()
二元函數梯度下降法求極小值

 

 

 四.梯度下降法在BP神經網絡中的實現過程(手動+Excel處理)

BP神經網絡中的正向傳播和反向傳播過程。反向傳播中的權重更新,就是通過梯度下降法實現的,損失函數最小化,實質也是一個最優化問題的求解。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 以上就是BP神經網絡的實現過程,手動+excel碼字只是為了深刻理解神經網絡,但這個並沒有太大的實質性意義,因為這個已經是成熟的算法。

五.Tensorflow中實現簡單的線性回歸

深度學習大致分為四個步驟:

1.數據准備

2.模型搭建

3.迭代訓練

4.使用模型

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

'''
說明:本實例來源於李金洪的《深度學習之Tensorflow入門、原理與進階實戰》機械工業出版社
'''
##一.數據准備
train_x = np.linspace(-1,1,100)
train_y = 2*train_x+np.random.randn(*train_x.shape)*0.3  ###y=2*x 但是加入了噪聲
##顯示模擬數據
plt.plot(train_x,train_y,'ro',label='original_data')
plt.legend()
plt.show()
5.1數據准備

通過函數y≈2x模擬輸入數據。簡單來說就是通過y=2x+隨機數

 

 

5.2模型搭建

#占位符,狀態變量
X= tf.placeholder('float')
Y = tf.placeholder('float')
##模型參數,權重和偏置
W= tf.Variable(tf.random_normal([1]),name='weight')
b = tf.Variable(tf.zeros([1]),name='bias')
##前向傳播結構
z = tf.multiply(X,W)+b
5.2.1前向傳播

 

 

 

##2.2 反向傳播

cost =  tf.reduce_mean(tf.square(Y-z))   ##總誤差,生成值與真實值的平方差
learning = 0.01                          ##學習率
optimizer = tf.train.GradientDescentOptimizer(learning).minimize(cost)  ##總誤差最小化(封裝好的梯度下降法)
5.2.2反向傳播
##2.3訓練模型
#2.3.1初始化所有變量
init = tf.global_variables_initializer()     ###權重和偏置等需要給原始值

#2.3.2定義參數
training_epochs = 20
display_step = 2
##2.3.3啟動Session
with tf.Session() as sess:
    sess.run(init)
    plotdata={'batchsize':[],'loss':[]}   ##存放批次值和損失值
    ##向模型輸入數據
    for epoch in range(training_epochs):
        for (x,y) in zip(train_x,train_y):
            sess.run(optimizer,feed_dict={X:x,Y:y})
        #顯示訓練的詳細信息
        if epoch % display_step ==0:
            loss = sess.run(cost,feed_dict={X:train_x,Y:train_y})
            print("Epoch",epoch+1,'cost=',loss,'W=',sess.run(W),'b=',sess.run(b))
            if not (loss =="NA"):
                plotdata["batchsize"].append(epoch)
                plotdata["loss"].append(loss)
    print('Finished!')
    print("cost=",sess.run(cost,feed_dict={X:train_x,Y:train_y}),"W=",sess.run(W),"b=",sess.run(b))
    
###輸出結果
'''
Epoch 1 cost= 1.9869132 W= [-0.0750566] b= [0.6703366]
Epoch 3 cost= 0.2619767 W= [1.4768808] b= [0.26081827]
Epoch 5 cost= 0.12644665 W= [1.8984009] b= [0.10219257]
Epoch 7 cost= 0.119223535 W= [2.0077329] b= [0.06028967]
Epoch 9 cost= 0.11925003 W= [2.0360081] b= [0.04944004]
Epoch 11 cost= 0.119383685 W= [2.0433202] b= [0.04663405]
Epoch 13 cost= 0.11942672 W= [2.0452104] b= [0.04590876]
Epoch 15 cost= 0.1194384 W= [2.045699] b= [0.04572121]
Epoch 17 cost= 0.11944149 W= [2.045826] b= [0.04567254]
Epoch 19 cost= 0.119442314 W= [2.0458593] b= [0.04565972]
Finished!
cost= 0.11944243 W= [2.045865] b= [0.04565755]
'''
5.2.3開啟會話,進行訓練
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

'''
說明:本實例來源於李金洪的《深度學習之Tensorflow入門、原理與進階實戰》機械工業出版社
'''
plotdata = {"batchsize":[],"loss":[]}
def moving_average(a,w=10):
    if len(a)<w:
        return a[:]
    return [val if idx<w else sum(a[(idx-w):idx])/w for idx,val in enumerate(a)]
##一.數據准備
train_x = np.linspace(-1,1,100)
train_y = 2*train_x+np.random.randn(*train_x.shape)*0.3  ###y=2*x 但是加入了噪聲
##顯示模擬數據
plt.plot(train_x,train_y,'ro',label='original_data')
plt.legend()
plt.show()

##二.模型搭建
##2.1正向傳播

#占位符,狀態變量
X= tf.placeholder('float')
Y = tf.placeholder('float')
##模型參數,權重和偏置
W= tf.Variable(tf.random_normal([1]),name='weight')
b = tf.Variable(tf.zeros([1]),name='bias')
##前向傳播結構
z = tf.multiply(X,W)+b

##2.2 反向傳播

cost =  tf.reduce_mean(tf.square(Y-z))   ##總誤差,生成值與真實值的平方差
learning = 0.01                          ##學習率
optimizer = tf.train.GradientDescentOptimizer(learning).minimize(cost)  ##總誤差最小化(封裝好的梯度下降法)

##2.3訓練模型
#2.3.1初始化所有變量
init = tf.global_variables_initializer()     ###權重和偏置等需要給原始值

#2.3.2定義參數
training_epochs = 20
display_step = 2
##2.3.3啟動Session
with tf.Session() as sess:
    sess.run(init)
    plotdata={'batchsize':[],'loss':[]}   ##存放批次值和損失值
    ##向模型輸入數據
    for epoch in range(training_epochs):
        for (x,y) in zip(train_x,train_y):
            sess.run(optimizer,feed_dict={X:x,Y:y})
        #顯示訓練的詳細信息
        if epoch % display_step ==0:
            loss = sess.run(cost,feed_dict={X:train_x,Y:train_y})
            print("Epoch",epoch+1,'cost=',loss,'W=',sess.run(W),'b=',sess.run(b))
            if not (loss =="NA"):
                plotdata["batchsize"].append(epoch)
                plotdata["loss"].append(loss)
    print('Finished!')
    print("cost=",sess.run(cost,feed_dict={X:train_x,Y:train_y}),"W=",sess.run(W),"b=",sess.run(b))

    ###輸出結果
    '''
    Epoch 1 cost= 1.9869132 W= [-0.0750566] b= [0.6703366]
    Epoch 3 cost= 0.2619767 W= [1.4768808] b= [0.26081827]
    Epoch 5 cost= 0.12644665 W= [1.8984009] b= [0.10219257]
    Epoch 7 cost= 0.119223535 W= [2.0077329] b= [0.06028967]
    Epoch 9 cost= 0.11925003 W= [2.0360081] b= [0.04944004]
    Epoch 11 cost= 0.119383685 W= [2.0433202] b= [0.04663405]
    Epoch 13 cost= 0.11942672 W= [2.0452104] b= [0.04590876]
    Epoch 15 cost= 0.1194384 W= [2.045699] b= [0.04572121]
    Epoch 17 cost= 0.11944149 W= [2.045826] b= [0.04567254]
    Epoch 19 cost= 0.119442314 W= [2.0458593] b= [0.04565972]
    Finished!
    cost= 0.11944243 W= [2.045865] b= [0.04565755]
    '''


    ##2.3.4訓練模型可視化
    plt.plot(train_x,train_y,'ro',label='orignal_data')
    plt.plot(train_x,sess.run(W)*train_x+sess.run(b),label='Fittedline')
    plt.legend()
    plt.show()

    plotdata["avgloss"] = moving_average(plotdata["loss"])
    plt.figure(1)
    plt.subplot(211)
    plt.plot(plotdata["batchsize"],plotdata["avgloss"],'b--')
    plt.xlabel('Minibathc_number')
    plt.ylabel('Loss')
    plt.title('Minibarch run as vs.Training loss')
    plt.show()
5.2.4可視化訓練過程(完整代碼)
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

'''
說明:本實例來源於李金洪的《深度學習之Tensorflow入門、原理與進階實戰》機械工業出版社
'''
plotdata = {"batchsize":[],"loss":[]}
def moving_average(a,w=10):
    if len(a)<w:
        return a[:]
    return [val if idx<w else sum(a[(idx-w):idx])/w for idx,val in enumerate(a)]
##一.數據准備
train_x = np.linspace(-1,1,100)
train_y = 2*train_x+np.random.randn(*train_x.shape)*0.3  ###y=2*x 但是加入了噪聲
##顯示模擬數據
plt.plot(train_x,train_y,'ro',label='original_data')
plt.legend()
plt.show()

##二.模型搭建
##2.1正向傳播

#占位符,狀態變量
X= tf.placeholder('float')
Y = tf.placeholder('float')
##模型參數,權重和偏置
W= tf.Variable(tf.random_normal([1]),name='weight')
b = tf.Variable(tf.zeros([1]),name='bias')
##前向傳播結構
z = tf.multiply(X,W)+b

##2.2 反向傳播

cost =  tf.reduce_mean(tf.square(Y-z))   ##總誤差,生成值與真實值的平方差
learning = 0.01                          ##學習率
optimizer = tf.train.GradientDescentOptimizer(learning).minimize(cost)  ##總誤差最小化(封裝好的梯度下降法)

##2.3訓練模型
#2.3.1初始化所有變量
init = tf.global_variables_initializer()     ###權重和偏置等需要給原始值

#2.3.2定義參數
training_epochs = 20
display_step = 2
##2.3.3啟動Session
with tf.Session() as sess:
    sess.run(init)
    plotdata={'batchsize':[],'loss':[]}   ##存放批次值和損失值
    ##向模型輸入數據
    for epoch in range(training_epochs):
        for (x,y) in zip(train_x,train_y):
            sess.run(optimizer,feed_dict={X:x,Y:y})
        #顯示訓練的詳細信息
        if epoch % display_step ==0:
            loss = sess.run(cost,feed_dict={X:train_x,Y:train_y})
            print("Epoch",epoch+1,'cost=',loss,'W=',sess.run(W),'b=',sess.run(b))
            if not (loss =="NA"):
                plotdata["batchsize"].append(epoch)
                plotdata["loss"].append(loss)
    print('Finished!')
    print("cost=",sess.run(cost,feed_dict={X:train_x,Y:train_y}),"W=",sess.run(W),"b=",sess.run(b))

    ###輸出結果
    '''
    Epoch 1 cost= 1.9869132 W= [-0.0750566] b= [0.6703366]
    Epoch 3 cost= 0.2619767 W= [1.4768808] b= [0.26081827]
    Epoch 5 cost= 0.12644665 W= [1.8984009] b= [0.10219257]
    Epoch 7 cost= 0.119223535 W= [2.0077329] b= [0.06028967]
    Epoch 9 cost= 0.11925003 W= [2.0360081] b= [0.04944004]
    Epoch 11 cost= 0.119383685 W= [2.0433202] b= [0.04663405]
    Epoch 13 cost= 0.11942672 W= [2.0452104] b= [0.04590876]
    Epoch 15 cost= 0.1194384 W= [2.045699] b= [0.04572121]
    Epoch 17 cost= 0.11944149 W= [2.045826] b= [0.04567254]
    Epoch 19 cost= 0.119442314 W= [2.0458593] b= [0.04565972]
    Finished!
    cost= 0.11944243 W= [2.045865] b= [0.04565755]
    '''


    ##2.3.4訓練模型可視化
    plt.plot(train_x,train_y,'ro',label='orignal_data')
    plt.plot(train_x,sess.run(W)*train_x+sess.run(b),label='Fittedline')
    plt.legend()
    plt.show()

    plotdata["avgloss"] = moving_average(plotdata["loss"])
    plt.figure(1)
    plt.subplot(211)
    plt.plot(plotdata["batchsize"],plotdata["avgloss"],'b--')
    plt.xlabel('Minibathc_number')
    plt.ylabel('Loss')
    plt.title('Minibarch run as vs.Training loss')
    plt.show()


    ##3.運用訓練好的模型預測
    print("x = 0.2,z=",sess.run(z,feed_dict={X:0.2}))
    print("x = 2,z=", sess.run(z, feed_dict={X: 2}))
    '''
    預測結果:
    x = 0.2,z= [0.4100724]
    x = 2,z= [4.0627713]
    '''
5.3運用訓練好的模型預測

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM