[Deep Learning]学习记录1-Python实现神经网络BP算法

资料:

http://blog.csdn.net/stdcoutzyx/article/details/41596663
http://blog.csdn.net/zouxy09/article/details/8775488

BP算法:

http://blog.csdn.net/marvin521/article/details/9886643
numpy的float64的精度比不上python自带的float类型,所以结果比不上原文中的实现。

  1. # coding: utf-8  
  2.   
  3. import numpy as np  
  4. import math  
  5. import random  
  6.   
  7. np.random.seed(0)  
  8. random.seed(0)  
  9.   
  10. # calculate a random number where:  a <= rand < b  
  11. def rand(a, b):  
  12.     return (b-a)*random.random() + a  
  13.   
  14. def sigmoid(x):  
  15.     # f(z) = (e ^ z - e ^ (-z)) / (e ^ z + e ^ (-z))  
  16.     # http://ufldl.stanford.edu/wiki/index.php/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C  
  17.     return math.tanh(x)  
  18.   
  19.   
  20. def dsigmoid(y):  
  21.     # 导数为:f'(z) = 1 - f(z) ^ 2  
  22.     return 1.0 - y ** 2  
  23.   
  24.   
  25. class NN(object):  
  26.     def __init__(self, ni, nh, no):  
  27.         # 结点数  
  28.         self.ni = ni + 1  
  29.         self.nh = nh  
  30.         self.no = no  
  31.   
  32.         # 值  
  33.         self.ai = np.ones((self.ni,))  
  34.         self.ah = np.ones((self.nh,))  
  35.         self.ao = np.ones((self.no,))  
  36.   
  37.         # 权重  
  38.         # self.wi = np.random.uniform(-0.2, 0.2, self.ni * self.nh).reshape(self.ni, self.nh)  
  39.         # self.wo = np.random.uniform(2., -2., self.nh * self.no).reshape(self.nh, self.no)  
  40.         self.wi = np.zeros((self.ni, self.nh))  
  41.         self.wo = np.zeros((self.nh, self.no))  
  42.   
  43.         for i in range(self.ni):  
  44.             for j in range(self.nh):  
  45.                 self.wi[i][j] = rand(-0.20.2)  
  46.                 # print(self.wi[i][j].dtype)  
  47.   
  48.         for i in range(self.nh):  
  49.             for j in range(self.no):  
  50.                 self.wo[i][j] = rand(-2.02.0)  
  51.   
  52.         # 旧的weight  
  53.         self.ci = np.zeros((self.ni, self.nh))  
  54.         self.co = np.zeros((self.nh, self.no))  
  55.   
  56.     def update(self, inputs):  
  57.         assert(len(inputs) == self.ni - 1)  
  58.         for i in range(self.ni - 1):  
  59.             self.ai[i] = inputs[i]  
  60.   
  61.         for i in range(self.nh):  
  62.             s = 0  
  63.             for j in range(self.ni):  
  64.                 s += self.ai[j] * self.wi[j][i]  
  65.             self.ah[i] = sigmoid(s)  
  66.   
  67.         for i in range(self.no):  
  68.             s = 0  
  69.             for j in range(self.nh):  
  70.                 s += self.ah[j] * self.wo[j][i]  
  71.             self.ao[i] = sigmoid(s)  
  72.   
  73.     def back_propagate(self, targets, N, M):  
  74.         assert(len(targets) == self.no)  
  75.   
  76.         # y = sigmoid(a2 + b), J = 0.5 * (y - t) ** 2, delta_J = (y - t) * y ' * h  
  77.         # output_delta = (y - t) * y'  
  78.         output_deltas = np.zeros(self.no)  
  79.         for i in range(self.no):  
  80.             err = targets[i] - self.ao[i]  
  81.             output_deltas[i] = dsigmoid(self.ao[i]) * err  
  82.   
  83.         # 这里取两次的delta来逐步改变  
  84.         # delta_j = (y - t) * y' * ah  
  85.         # W_new = W_old + r1 * delta_J + r2 * delta_J_old  
  86.         for i in range(self.nh):  
  87.             for j in range(self.no):  
  88.                 change = output_deltas[j] * self.ah[i]  
  89.                 self.wo[i][j] += N * change + M * self.co[i][j]  
  90.                 self.co[i][j] = change  
  91.   
  92.         # hidden_delta = (y - t) * y' * Wo * h'  
  93.         # delta_J = (y - t) * y' * Wo * h' * ai  
  94.         hidden_deltas = np.zeros((self.nh,))  
  95.         for i in range(self.nh):  
  96.             err = 0  
  97.             for j in range(self.no):  
  98.                 err += output_deltas[j] * self.wo[i][j]  
  99.             hidden_deltas[i] = dsigmoid(self.ah[i]) * err  
  100.   
  101.         # 更新input weight  
  102.         for i in range(self.ni):  
  103.             for j in range(self.nh):  
  104.                 change = hidden_deltas[j] * self.ai[i]  
  105.                 self.wi[i][j] += N * change + M * self.ci[i][j]  
  106.                 self.ci[i][j] = change  
  107.   
  108.         # 计算错误率  
  109.         err = 0.  
  110.         for i in range(len(targets)):  
  111.             err += 0.5 * (targets[i] - self.ao[i]) ** 2  
  112.         return err  
  113.   
  114.     def train(self, patterns, iterations=1000, N=0.5, M=0.1):  
  115.         for i in range(iterations):  
  116.             err = 0.  
  117.             for p in patterns:  
  118.                 inputs = p[0]  
  119.                 targets = p[1]  
  120.                 self.update(inputs)  
  121.                 err += self.back_propagate(targets, N, M)  
  122.             if i % 100 == 0:  
  123.                 self.weights()  
  124.                 print('error %-.5f' % err)  
  125.   
  126.     def weights(self):  
  127.         print("\nInput weights:")  
  128.         for i in range(self.ni):  
  129.             print(self.wi[i])  
  130.         print("\nOutput weights")  
  131.         for i in range(self.nh):  
  132.             print(self.wo[i])  
  133.   
  134.   
  135.   
  136. def main():  
  137.     pat = np.array([  
  138.         [[0,0], [0]],  
  139.         [[0,1], [1]],  
  140.         [[1,0], [1]],  
  141.         [[1,1], [0]]  
  142.     ])  
  143.     nn = NN(221)  
  144.     nn.train(pat)  
  145.   
  146. if __name__ == "__main__":  
  147.     main()  

注意:
python dict的*操作只是浅拷贝:
  1. t = [0] * 3  
  2. h = [t] * 5  
  3. h[0][0] = 1  
  4. print(h)  
  5. # [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]  
[[0]],dict里面的对象只是引用,并没有copy。

检查了好多遍之后,发现上面不是由于误差引起的。而是计算delta的顺序错了,梯度下降是需要协调改变的,所以需要先算完两个delta值,再更新W。
  1. # coding: utf-8  
  2.   
  3. import numpy as np  
  4. import math  
  5. import random  
  6.   
  7. np.random.seed(0)  
  8. # random.seed(0)  
  9.   
  10. # calculate a random number where:  a <= rand < b  
  11. def rand(a, b):  
  12.     return (b-a)*random.random() + a  
  13.   
  14. # Make a matrix (we could use NumPy to speed this up)  
  15. def makeMatrix(I, J, fill=0.0):  
  16.     m = []  
  17.     for i in range(I):  
  18.         m.append([fill]*J)  
  19.     return m  
  20.   
  21.   
  22. def sigmoid(x):  
  23.     # f(z) = (e ^ z - e ^ (-z)) / (e ^ z + e ^ (-z))  
  24.     # http://ufldl.stanford.edu/wiki/index.php/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C  
  25.     return math.tanh(x)  
  26.   
  27.   
  28. def dsigmoid(y):  
  29.     # 导数为:f'(z) = 1 - f(z) ^ 2  
  30.     return 1.0 - y ** 2  
  31.   
  32.   
  33. class NN(object):  
  34.     def __init__(self, ni, nh, no):  
  35.         # 结点数  
  36.         self.ni = ni + 1  
  37.         self.nh = nh  
  38.         self.no = no  
  39.   
  40.         # 值  
  41.         self.ai = np.ones((self.ni,))  
  42.         self.ah = np.ones((self.nh,))  
  43.         self.ao = np.ones((self.no,))  
  44.         # self.ai = [1.] * self.ni  
  45.         # self.ah = [1.] * self.nh  
  46.         # self.ao = [1.] * self.no  
  47.   
  48.         # 权重  
  49.         self.wi = np.random.uniform(-0.20.2self.ni * self.nh).reshape(self.ni, self.nh)  
  50.         self.wo = np.random.uniform(2., -2.self.nh * self.no).reshape(self.nh, self.no)  
  51.         # self.wi = np.zeros((self.ni, self.nh))  
  52.         # self.wo = np.zeros((self.nh, self.no))  
  53.         # self.wi = makeMatrix(self.ni, self.nh)  
  54.         # self.wo = makeMatrix(self.nh, self.no)  
  55.         #  
  56.         # for i in range(self.ni):  
  57.         #     for j in range(self.nh):  
  58.         #         self.wi[i][j] = rand(-0.2, 0.2)  
  59.         #         # print(type(self.wi[i][j]))  
  60.         #  
  61.         # for i in range(self.nh):  
  62.         #     for j in range(self.no):  
  63.         #         self.wo[i][j] = rand(-2.0, 2.0)  
  64.   
  65.         # 旧的weight  
  66.         self.ci = np.zeros((self.ni, self.nh))  
  67.         self.co = np.zeros((self.nh, self.no))  
  68.         # self.ci = makeMatrix(self.ni, self.nh)  
  69.         # self.co = makeMatrix(self.nh, self.no)  
  70.   
  71.     def update(self, inputs):  
  72.         assert(len(inputs) == self.ni - 1)  
  73.         for i in range(self.ni - 1):  
  74.             self.ai[i] = inputs[i]  
  75.   
  76.         for i in range(self.nh):  
  77.             s = 0.  
  78.             for j in range(self.ni):  
  79.                 s += self.ai[j] * self.wi[j][i]  
  80.             self.ah[i] = sigmoid(s)  
  81.   
  82.         for i in range(self.no):  
  83.             s = 0.  
  84.             for j in range(self.nh):  
  85.                 s += self.ah[j] * self.wo[j][i]  
  86.             self.ao[i] = sigmoid(s)  
  87.   
  88.     def back_propagate(self, targets, N, M):  
  89.         assert(len(targets) == self.no)  
  90.   
  91.         # y = sigmoid(a2 + b), J = 0.5 * (y - t) ** 2, delta_J = (y - t) * y ' * h  
  92.         # output_delta = (y - t) * y'  
  93.         output_deltas = np.zeros(self.no)  
  94.         # output_deltas = [0.] * self.no  
  95.         # print(output_deltas)  
  96.         for i in range(self.no):  
  97.             err = targets[i] - self.ao[i]  
  98.             output_deltas[i] = dsigmoid(self.ao[i]) * err  
  99.   
  100.         # hidden_delta = (y - t) * y' * Wo * h'  
  101.         # delta_J = (y - t) * y' * Wo * h' * ai  
  102.         hidden_deltas = np.zeros(self.nh)  
  103.         # hidden_deltas = [0.] * self.nh  
  104.         # print(hidden_deltas)  
  105.         for i in range(self.nh):  
  106.             err = 0.  
  107.             for j in range(self.no):  
  108.                 err += output_deltas[j] * self.wo[i][j]  
  109.             hidden_deltas[i] = dsigmoid(self.ah[i]) * err  
  110.   
  111.         # 这里取两次的delta来逐步改变  
  112.         # delta_j = (y - t) * y' * ah  
  113.         # W_new = W_old + r1 * delta_J + r2 * delta_J_old  
  114.         for i in range(self.nh):  
  115.             for j in range(self.no):  
  116.                 change = output_deltas[j] * self.ah[i]  
  117.                 self.wo[i][j] += N * change + M * self.co[i][j]  
  118.                 self.co[i][j] = change  
  119.   
  120.         # 更新input weight  
  121.         for i in range(self.ni):  
  122.             for j in range(self.nh):  
  123.                 change = hidden_deltas[j] * self.ai[i]  
  124.                 self.wi[i][j] += N * change + M * self.ci[i][j]  
  125.                 self.ci[i][j] = change  
  126.   
  127.         # 计算错误率  
  128.         err = 0.  
  129.         for i in range(len(targets)):  
  130.             err += 0.5 * (targets[i] - self.ao[i]) ** 2  
  131.         return err  
  132.   
  133.     def train(self, patterns, iterations=1000, N=0.5, M=0.1):  
  134.         for i in range(iterations):  
  135.             err = 0.  
  136.             for p in patterns:  
  137.                 inputs = p[0]  
  138.                 targets = p[1]  
  139.                 self.update(inputs)  
  140.                 err += self.back_propagate(targets, N, M)  
  141.             if i % 100 == 0:  
  142.                 # self.weights()  
  143.                 print('error %-.5f' % err)  
  144.   
  145.     def weights(self):  
  146.         print("\nInput weights:")  
  147.         for i in range(self.ni):  
  148.             print(self.wi[i])  
  149.         print("\nOutput weights:")  
  150.         for i in range(self.nh):  
  151.             print(self.wo[i])  
  152.   
  153.   
  154.   
  155. def main():  
  156.     pat = np.array([  
  157.         [[0,0], [0]],  
  158.         [[0,1], [1]],  
  159.         [[1,0], [1]],  
  160.         [[1,1], [0]]  
  161.     ])  
  162.     nn = NN(221)  
  163.     # nn.weights()  
  164.     nn.train(pat)  
  165.   
  166. if __name__ == "__main__":  
  167.     main()  
numpy的float64精确度还是不够,最后结果有0.1的误差


转载来自:http://blog.csdn.net/naruto2011sasuke/article/details/46399519


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值