《深度学习的数学》(https://www.ituring.com.cn/book/2593)第四章实例“用EXCEL体验神经网络的误差反向传播”——python实现

所使用的的数据连接:https://www.ituring.com.cn/book/download/d16bf588-375b-4176-b319-ec3c3a2d99a1
原书网址
读入EXCEL文件的DATA工作簿中的学习数据
将读入的数据分解成为 12*64 维数组,每一行代表一个待识别的数字(0或者 1)
将正解转换为tuple形式并保存在value列表中。其中(0,1)代表1, (1,0)代表0
这一步比较复杂,要反复尝试。

import pandas, numpy
file = r'D:\ChromeCoreDownloads\【Excel示例文件】深度学习的数学\3-5 NN(求解器).xlsx'
data = pandas.read_excel(file, sheet_name='Data', engine='openpyxl')
df = pandas.DataFrame(data)
# 通过切片,去除部分没有意义的行和列
df1 = df.iloc[2:8, 10:]

file的文件路径要更改为相应的文件路径。

value = []
for i in range(0, 256, 4):
    target_area = df1.iloc[:, i:i+4]
    if int(target_area.iloc[5, 3]) == 0:
        value.append((1, 0))
    elif int(target_area.iloc[5, 3]) == 1:
        value.append((0, 1))
    else:
        print('error', df1.iloc[0, 0])
    target_area = target_area.iloc[1:-1, 0:3]
    # 将4行3列的学习数据转化为1行
    target_area = numpy.array(target_area).flatten()
    target_area = pandas.DataFrame(target_area).transpose()
    if i == 0:
        data_new = target_area
    else:
        # 将学习数据打包为一个Dataframe
        data_new.loc[len(data_new)] = target_area.iloc[0, :]

print(data_new)
print(value)

结果如下图:

      0    1    2    3    4    5    6    7    8    9   10   11
0   1.0  1.0  1.0  1.0  0.0  1.0  1.0  0.0  1.0  1.0  1.0  1.0
1   0.0  1.0  1.0  1.0  0.0  1.0  1.0  0.0  1.0  1.0  1.0  1.0
2   1.0  1.0  0.0  1.0  0.0  1.0  1.0  0.0  1.0  1.0  1.0  1.0
3   1.0  1.0  1.0  1.0  0.0  1.0  1.0  0.0  1.0  1.0  1.0  0.0
4   1.0  1.0  1.0  1.0  0.0  1.0  1.0  0.0  1.0  0.0  1.0  1.0
..  ...  ...  ...  ...  ...  ...  ...  ...  ...  ...  ...  ...
59  0.0  0.0  0.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
60  0.0  0.0  0.0  0.0  1.0  0.0  0.0  1.0  0.0  0.0  1.0  0.0
61  0.0  1.0  0.0  0.0  1.0  0.0  0.0  1.0  0.0  0.0  0.0  0.0
62  0.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0
63  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  0.0  0.0  1.0  0.0

[64 rows x 12 columns]
[(1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1)]

Process finished with exit code 0

以下是三层网络及梯度的计算过程。梯度的计算要按照公式一个一个计算。没有什么捷径。

def add_gradient(l):
    # 将各个图片的平方误差的偏导数相加得到梯度
    total = l[0]
    for i in range(1, len(l)):
        total += l[i]
    return total


def neural_example(data_new, i):
    global b21, b22, b23, w21, w22, w23, w31, w32, b31, b32
    # 通过改变seed来获得不同的代价函数C的值
    # 获取隐藏层的初始值, (w21, w22, w23)对应隐藏层的权重,b21, b22, b23对应隐藏层的偏置。
    numpy.random.seed(i)
    data_new = numpy.array(data_new)
    w21 = numpy.random.randn(3, 12)[0]
    w22 = numpy.random.randn(3, 12)[1]
    w23 = numpy.random.randn(3, 12)[2]
    b21, b22, b23 = numpy.random.randn(3)
    # 获取输出层初始化参数值(权重和偏置)
    w31 = numpy.random.randn(2, 3)[0]
    w32 = numpy.random.randn(2, 3)[1]
    b31, b32 = numpy.random.randn(2)
    # 学习率初始化为 -1
    step = -1
    for x in range(50):
        # 计算隐藏层的各个神经元输入z及输出a。
        z21 = data_new.dot(w21) + b21
        a21 = 1/(numpy.exp(-1*z21)+1)
        z22 = data_new.dot(w22) + b22
        a22 = 1/(numpy.exp(-1*z22)+1)
        z23 = data_new.dot(w23) + b23
        a23 = 1/(numpy.exp(-1*z23)+1)
        # 计算输出层的输入z及输出a
        z31 = numpy.array([a21, a22, a23]).transpose().dot(numpy.array(w31)) + b31
        z32 = numpy.array([a21, a22, a23]).transpose().dot(numpy.array(w32)) + b32
        a31 = 1/(numpy.exp(-1*z31)+1)
        a32 = 1/(numpy.exp(-1*z32)+1)
        # 计算代价函数值c
        c = 0
        for j in range(64):
            c += 1/2 * ((a31[j]-value[j][0])**2 + (a32[j]-value[j][1])**2)
        # 梯度下降法调整参数值
        # 先计算神经单元误差
        value_1 = []
        value_2 = []
        for v in value:
            value_1.append(v[0])
            value_2.append(v[1])
        value_1 = numpy.array(value_1)
        value_2 = numpy.array(value_2)
        # 输出层的神经单元误差 sigma = (a - value) * a * (1 - a) 为 2*64矩阵
        sigma31 = (a31 - value_1) * a31 * (1 - a31)
        sigma32 = (a32 - value_2) * a32 * (1 - a32)
        sigma3 = numpy.array((sigma31, sigma32)).transpose()
        # 隐藏层的神经单元误差 sigma 为3x84矩阵 dfs为输出a对输入的导数
        sigma21 = sigma3.dot(numpy.array((w31, w32))[:, 0]) * (a21*(1-a21))
        sigma22 = sigma3.dot(numpy.array((w31, w32))[:, 1]) * (a22*(1-a22))
        sigma23 = sigma3.dot(numpy.array((w31, w32))[:, 2]) * (a23*(1-a23))
        # print(numpy.array((w31, w32))[:, 0])
        # 计算梯度
        # 输出层
        s_b31 = sigma31
        s_b31 = add_gradient(s_b31) * step
        s_b32 = sigma32
        s_b32 = add_gradient(s_b32) * step
        s_w31 = numpy.array((sigma31 * a21, sigma31 * a22, sigma31 * a23)).transpose()
        s_w31 = add_gradient(s_w31) * step
        s_w32 = numpy.array((sigma32 * a21, sigma32 * a22, sigma32 * a23)).transpose()
        s_w32 = add_gradient(s_w32)
        # 隐藏层
        s_b21, s_b22, s_b23 = sigma21, sigma22, sigma23
        s_b21 = add_gradient(s_b21) * step
        s_b22 = add_gradient(s_b22) * step
        s_b23 = add_gradient(s_b23) * step
        s_w21 = (data_new.transpose() * sigma21).transpose()
        s_w21 = add_gradient(s_w21) * step
        s_w22 = (data_new.transpose() * sigma22).transpose()
        s_w22 = add_gradient(s_w22) * step
        s_w23 = (data_new.transpose() * sigma23).transpose()
        s_w23 = add_gradient(s_w23) * step
        # print(s_w23)
        # 根据梯度调整参数值
        b21 += s_b21
        b22 += s_b22
        b23 += s_b23
        w21 += s_w21
        w22 += s_w22
        w23 += s_w23
        b31 += s_b31
        b32 += s_b32
        w31 += s_w31
        w32 += s_w32
        if c < 1:
            print(c, x)
            step = -0.05
        if c < 0.5:
            break
    return c

用书中的数据进行测试,能够准确的预测。

def check(data_new):
    # 计算结果
    # 计算隐藏层的z及输出a
    data_new = numpy.array(data_new)
    z21 = data_new.dot(w21) + b21
    a21 = 1 / (numpy.exp(-1 * z21)+1)
    z22 = data_new.dot(w22) + b22
    a22 = 1 / (numpy.exp(-1 * z22)+1)
    z23 = data_new.dot(w23) + b23
    a23 = 1 / (numpy.exp(-1 * z23)+1)
    # 计算输出层的z及输出a
    z31 = numpy.array([a21, a22, a23]).transpose().dot(numpy.array(w31)) + b31
    z32 = numpy.array([a21, a22, a23]).transpose().dot(numpy.array(w32)) + b32
    a31 = 1 / (numpy.exp(-1 * z31)+1)
    a32 = 1 / (numpy.exp(-1 * z32)+1)
    if a31 > a32:
        print('结果为', 0)
    elif a31 < a32:
        print('结果为', 1)
    print(a31, a32)
# 用书中的例子测试结果
# data_test = numpy.array((0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0))
# data_test = (0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1)
data_test = (0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0)

c = neural_example(data_new, 0)
print(c)
check(data_test)

计算结果如下:

0.7812709960623921 22
0.34322063461320146 23
0.34322063461320146
结果为 1
0.07197658369715122 0.999977452430708

Process finished with exit code 0

期间还参考了很多博主的文件,一并感谢。
以上只是我的粗陋见解,特别是求最优化参数的方法,应该还有很大的改进空间,希望路过的多多指教。

你可能感兴趣的:(python,python,神经网络)