python實現多層神經網絡(後向傳送訓練算法),學習異或操作

跟上次一樣,跟着《人工智能》這本書中所說的步驟,一步一步敲出來的
敲完之後,運行起來發現訓練週期竟然達到了50000+。。。我檢查代碼檢查了很多遍,也跟書本上的一次訓練數據作了對比,沒發現什麼問題,並且異或操作的學習最終也學習成功了
之後,我加入要素常數來提高學習速度,沒想到加入之後,訓練週期200+就結束了。。。這學習速度快了幾百倍。。。好誇張,下面上代碼

import math

def sigmoidFunc(x):  #定義sigmoid函數
    return 1 / (1 + math.exp(-x))

def trainning():  #定義訓練函數
    #本次神經網絡的結構
    #  1       3       5
    #  2       4
    #輸入層   隱含層   輸出層

    #初始化權重、學習速度以及閾值
    weights_12 = [[0.5,0.4],[0.9,1.0]] #輸入層和隱含層之間的權重,每個元素代表一個隱含層神經元的所有輸入
    weights_23 = [[-1.2,1.1]]  #隱含層與輸出層之間的權重,每個元素代表一個輸出層的神經元的所有輸入
    thresholds = [[0.8,-0.1],[0.3]] #從隱含層開始纔有閾值
    learning_rate = 0.1

    #設置訓練數據
    trainning_X = [[1,1],[0,0],[0,1],[1,0]]
    trainning_Y = [0,0,1,1]

    #其餘變量設置
    bias = 1 #誤差總和
    p = 1    #記錄週期
    yjlen = len(thresholds[0]) #隱含層神經元個數
    yklen = len(thresholds[1]) #輸出層神經元個數

    while bias > 0.001:
        print("第",p,"個週期")

        bias = 0
        yj = [0,0] #記錄隱含層的輸出
        yk = [0] #記錄輸出層的輸出
        j = 0  #記錄當前訓練數據的第幾組

        for x in trainning_X:
            weights_23_temp = [0, 0]  # 臨時記錄輸出層神經元修改的權重,因爲在隱含層神經元權重時,還要用到上一次迭代中的輸出層神經元的權重
            #通過輸入計算隱含層神經元的輸出並記錄
            for i in range(yjlen):
                Xij = x[0] * weights_12[i][0] + x[1] * weights_12[i][1] - thresholds[0][i]
                # print("xij:", Xij)
                yj[i] = sigmoidFunc(Xij)
                # print("yj:", yj[i])

            #通過隱含層的輸出計算輸出層的輸出並記錄
            for i in range(yklen):
                Xjk = yj[0] * weights_23[i][0] + yj[1] * weights_23[i][1] - thresholds[1][i]
                yk[i] = sigmoidFunc(Xjk)
                # print("yk:",yk[i])

            #調整隱含層與輸出層之間的權重
            ek = trainning_Y[j] - yk[0] #計算誤差e = 期望輸出 - 實際輸出
            bias += (ek*ek)
            es_k = yk[0] * (1-yk[0]) * ek #計算輸出層神經元的誤差斜率,輸出層中的每一個神經元只有一個誤差斜率,供給他所有的輸入修改權重
                                          #因爲本例中輸出層只有一個神經元,所以沒有用數組
            # print("es_k:",es_k)
            for i in range(len(weights_23[0])):
                delta = learning_rate * yj[i] * es_k  # delta = 學習速度 * 第i個輸入 * 誤差斜率
                weights_23_temp[i] = weights_23[0][i] + delta
                # print(weights_23_temp[i])
            #更新輸出層神經元的閾值
            for i in range(yklen):
                thresholds[1][i] += learning_rate * (-1) * es_k
                # print("theta1", i, ":", thresholds[1][i])

            #調整輸入層與隱含層之間的權重
            for i in range(yjlen):
                count = 0
                es_j = 0

                count += es_k * weights_23[0][i]  #count = 跟j神經元有連接的所有k神經元的(es_k*wjk)的和
                # print("count:",count)
                es_j = yj[i] * (1 - yj[i]) * count
                # print("es_j:",es_j)
                #更新神經元j的所有輸入權重
                for l in range(len(weights_12[i])):
                    weights_12[i][l] += learning_rate * x[l] * es_j
                    # print(weights_12[i][l])
                # 更新輸出層神經元的閾值
                thresholds[0][i] += learning_rate * (-1) * es_j
                # print("theta0",i,":",thresholds[0][i])

            #更新輸出層神經元的輸入權重
            for i in range(len(weights_23[0])):
                weights_23[0][i] = weights_23_temp[i]

            #下一組訓練數據
            j = j + 1

            # print("輸入:",x,"實際輸出:",yk[0],"修改後的權重:w13:",weights_12[0][0],"w23:",weights_12[0][1],"w14:",weights_12[1][0],"w24:",weights_12[1][1],"w35:",weights_23[0][0],"w45:",weights_23[0][1])
        print("本次週期誤差總和:",bias)
        p = p + 1

    print("輸入:", x, "實際輸出:", yk[0], "修改後的權重:w13:", weights_12[0][0], "w23:", weights_12[0][1], "w14:", weights_12[1][0],
          "w24:", weights_12[1][1], "w35:", weights_23[0][0], "w45:", weights_23[0][1])
    print("theta3:",thresholds[0][0],"theta4:",thresholds[0][1],"theta5:",thresholds[1][0])
    print("訓練結束")
    return weights_12,weights_23,thresholds


def predict(test_X):
    yj = [0,0]
    for x in test_X:
        for i in range(len(yj)):
            Xij = x[0] * weights_12[i][0] + x[1] * weights_12[i][1] - thresholds[0][i]
            yj[i] = sigmoidFunc(Xij)

        Xjk = yj[0] * weights_23[0][0] + yj[1] * weights_23[0][1] - thresholds[1][0]
        yk = sigmoidFunc(Xjk)
        print("x:",x,"y:",yk)

weights_12,weights_23,thresholds = trainning()
test_X = [[1,0],[0,0],[0,1],[1,1]]
print("測試數據:",test_X)
print("預測如下:")
predict(test_X)

運行結果:
在這裏插入圖片描述
加入要素常數,就是添加和修改一些代碼:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
加入要素常數之後的運行結果:
在這裏插入圖片描述
相當誇張。。。誤差平方和的下降速度快了很多很多

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章