跟上次一樣,跟着《人工智能》這本書中所說的步驟,一步一步敲出來的
敲完之後,運行起來發現訓練週期竟然達到了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)
運行結果:
加入要素常數,就是添加和修改一些代碼:
加入要素常數之後的運行結果:
相當誇張。。。誤差平方和的下降速度快了很多很多