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)

运行结果:
在这里插入图片描述
加入要素常数,就是添加和修改一些代码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
加入要素常数之后的运行结果:
在这里插入图片描述
相当夸张。。。误差平方和的下降速度快了很多很多

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