跟上次一样,跟着《人工智能》这本书中所说的步骤,一步一步敲出来的
敲完之后,运行起来发现训练周期竟然达到了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)
运行结果:
加入要素常数,就是添加和修改一些代码:
加入要素常数之后的运行结果:
相当夸张。。。误差平方和的下降速度快了很多很多