《深度学习的数学》神经网络的python实现

《深度学习的数学》神经网络的python实现
《深度学习的数学》4-4节使用了excel实现了一个小的0-1识别器。自己写了一个python版的实现。
需要指出的是:
1 大部分涉及到的矩阵都是行代表样本(64个),列代表神经元;权重矩阵的话列代表本层神经元,行代表上层神经元。这样权重矩阵可能会根excel表中的正好反着。后面算偏导数的时候通过矩阵乘法直接算出来最后的结果,不用向excel里面一样还得把64个样本计算出来的偏导数加起来。
2 计算z之前我把训练集和隐藏层a在前面多加了一个1(例如训练集里面一个图片是12列,我在最前头又加了一列1),把权重中的b也直接放进权重矩阵里,这样直接权重矩阵和输入矩阵相乘就直接算出来z了。原书是把b单独相加的。
3 我这里尝试使用交叉熵计算误差函数,效果和用最小二乘差不多。当然最小二乘的代码也在里面(只不过注释掉了)
4 所有的数都和excel表中的一样。那个flatten函数只不过是把raw_training_set这个直接从excel表中拷贝的训练集转换成numpy矩阵罢了

import numpy as np
import re


# 获取训练集
raw_training_set = '''
1	1	1		0	1	1		1	1	0		1	1	1		1	1	1		0	0	0		0	0	0		0	0	0		0	0	0		0	0	0		1	1	1		0	1	1		1	1	0		1	1	1		1	1	1		1	0	1		1	1	1		1	1	1		1	1	1		1	1	1		1	1	1		0	0	1		0	1	1		0	1	1		0	1	1		0	1	1		0	1	1		1	1	0		1	1	0		1	1	0		1	1	0		1	1	0		0	1	0		1	1	0		0	1	0		0	1	0		0	1	0		1	1	0		1	1	0		1	1	0		0	1	0		0	1	0		1	1	0		1	1	0		0	1	0		0	1	0		0	1	0		1	1	0		1	1	0		0	1	1		1	1	0		1	1	0		1	1	0		1	1	0		0	1	0		1	0	0		1	0	0		0	1	0		0	1	0		0	0	0		0	0	0		0	1	0		0	1	0		0	1	0
1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	1	1		0	1	1		1	1	0		1	1	1		1	1	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	0		1	0	1		1	0	1		1	0	1		0	0	1		1	0	1		1	0	0		1	0	1		1	0	1		1	0	1		0	0	1		1	0	0		1	0	1		1	0	1		1	0	1		0	0	1		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		0	1	0		0	1	1		0	1	0		0	1	1		1	1	0		0	1	0		1	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	0	0		0	1	0		0	1	0		0	1	0		0	1	0		0	0	1		1	0	0
1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	0	1		1	1	1		1	1	1		1	1	1		1	1	0		0	1	1		1	0	1		1	0	1		1	0	0		1	0	1		0	0	1		1	0	1		1	0	1		1	0	1		1	0	0		1	0	1		0	0	1		1	0	1		1	0	1		1	0	0		1	0	1		0	0	1		1	0	1		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		0	1	1		0	1	0		1	1	0		1	1	0		0	0	0		0	1	0		0	1	0		0	1	0		0	1	0		0	0	0		0	1	0		0	1	0		0	1	0		0	0	1		1	0	0
1	1	1		1	1	1		1	1	1		1	1	0		0	1	1		1	1	1		1	1	1		1	1	1		1	1	0		0	1	1		0	0	0		0	0	0		0	0	0		0	0	0		0	0	0		1	1	1		1	1	1		1	1	1		1	0	1		1	1	1		1	1	1		1	1	1		1	1	1		1	1	1		1	0	1		1	1	1		1	1	1		1	1	1		1	1	1		1	0	1		1	1	1		1	1	1		0	1	0		0	1	0		0	1	0		1	1	0		0	1	1		1	1	0		0	1	1		1	1	1		0	1	0		0	1	0		0	1	0		0	1	0		1	1	0		1	1	0		1	1	1		0	1	1		0	1	0		0	1	1		0	1	0		0	1	0		1	1	0		0	1	0		1	0	0		0	1	0		0	0	1		1	1	0		1	1	0		1	1	0		0	1	0		0	0	0		0	1	0		0	1	0
'''
# 获取训练集的标签,行代表样本,第一列代表是否为0,第二列代表是否为1
training_label = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
                           ).T


def flatten(matches):  # 把字符串转换成阵列
    flag1 = 0  # 行标记
    flag2 = 0  # 列标记
    done_line = 0
    i = 0
    return_array = np.zeros((64, 12))
    while(done_line < 12/3):
        return_array[flag1, flag2] = int(matches[i])
        i += 1
        flag2 += 1
        if (flag2 % 3 == 0):
            flag2 = done_line*3
            flag1 += 1
            if (flag1 % 64 == 0):
                done_line += 1
                flag1 = 0
                flag2 = done_line*3
    return return_array


def sigmod(i):  # 返回矩阵个元素的sigmod
    return 1 / (1 + np.exp(-i))


batch = 1  # 训练次数
eta = 0.2  # η,学习率
C_old = 100  # 上次训练前的误差值
matches = re.findall(r'[10]', raw_training_set, re.MULTILINE)
training_set = flatten(matches)
training_set = np.insert(training_set, 0, np.ones(
    64), axis=1) # 多加一列,待会直接乘权重矩阵时就不用单独加偏置了
# 最终获取了每个样本一行,64列的样本矩阵.样本矩阵的第一列是bias

# 隐藏层权重矩阵,i行j列代表上一层i神经元输入到本层j神经元.第一行是b,正好和训练集中添加的那一行相乘,方便计算.
wei_hid = np.array([[-0.185, 0.526, -1.169],
                    [0.49, 0.442, 0.654],
                    [0.348, -0.537, -1.389],
                    [0.073, 1.008, 1.246],
                    [0.837, 1.072, 0.057],
                    [-0.071, -0.733, -0.183],
                    [-3.617, 0.823, -0.743],
                    [-0.536, -0.453, -0.461],
                    [-0.023, -0.014, 0.331],
                    [-1.717, -0.027, 0.449],
                    [-1.456, -0.427, -1.296],
                    [-0.556, 1.876, 1.569],
                    [0.852, -2.305, -0.471]])

# 表示层矩阵,i行j列代表上一层i神经元输入到本层j神经元.第一行是b,正好和训练集中添加的那一行相乘,方便计算.
wei_out = np.array([[-1.438, -1.379],
                    [0.388, 0.025],
                    [0.803, -0.790],
                    [0.029, 1.553]])

# 开始训练
while True:
    print("开始第" + str(batch) + "轮训练")

    z_hid = training_set @ wei_hid  # 获取隐藏层z,z是输入量的加权平均,行代表每个样本,列代表每个神经元
    a_hid = sigmod(z_hid)  # 获取隐藏层的a,a是sigmod(z),行代表每个样本,列代表每个神经元
    a_dri_z_hid = a_hid * (1 - a_hid)  # a'(隐藏层的z),行代表每个样本,列代表每个神经元

    a_hid = np.insert(a_hid, 0, np.ones(64), axis=1)  # 给隐藏层的a添加上bias列

    z_out = a_hid @ wei_out
    a_out = sigmod(z_out)
    a_dri_z_out = a_out * (1 - a_out)  # a'(输出层的z),行代表每个样本,列代表每个神经元

    #C = a_out - training_label
    #C = (C[:, 0] ** 2 + C[:, 1] ** 2) / 2  # 计算每一个样本对应的误差函数C的值
    C = -1/training_set.shape[0]*(training_label * np.log(a_out) + (1 - training_label) * np.log(1 - a_out))  # 使用交叉熵计算每一个样本对应的误差函数C的值
    print("该轮训练前的误差是"+str(C.sum()))
    if abs(C.sum() - C_old) <= 0.00001:
        print("训练结束\n")
        break
    C_old = C.sum()

    partial_C_div_partial_a_out = 1 / \
        training_set.shape[0]*(a_out - training_label)
    delta_out = partial_C_div_partial_a_out * \
        a_dri_z_out  # 计算在每一个样本下的输出层神经元的δ,行代表样本,列代表神经元

    # 计算隐藏层的神经元的δ,行代表样本,列代表神经元.wei_out需要先截取后三行然后转置(第一行用来处理bias)
    delta_hid = (delta_out @ wei_out[1:, :].T) * a_dri_z_hid

    # 计算反向传播之后误差函数C与输出层权重的偏导数(梯度分量),通过矩阵乘法把所有样本对应的偏导数直接相加了
    partial_C_div_partial_w_out = a_hid.T @ delta_out
    # 计算反向传播之后误差函数C与隐藏层权重的偏导数(梯度分量),通过矩阵乘法把所有样本对应的偏导数直接相加了
    partial_C_div_partial_w_hid = training_set.T @ delta_hid
    # 更新权重
    wei_hid = wei_hid - eta * partial_C_div_partial_w_hid
    wei_out = wei_out - eta * partial_C_div_partial_w_out

    print("结束第"+str(batch)+"轮训练")
    batch += 1

# 构建测试集
test_set = np.array(
    [[0, 1, 1,
      1, 0, 1,
      1, 0, 1,
      1, 0, 1],

     [0, 1, 1,
      0, 1, 0,
      0, 1, 0,
      0, 1, 0]])
print(test_set.reshape(2, 4, 3))
print("")
test_set = np.insert(test_set, 0, np.ones(
    test_set.shape[0]), axis=1)

# 对测试集进行推理
test_label = np.rint(sigmod(np.insert(sigmod(test_set @ wei_hid),
                                      0, np.ones((test_set @ wei_hid).shape[0]), axis=1) @ wei_out))
# 输出推理结果
print(test_label)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值