反向传播算法实战

本文仅仅是反向传播算法的实现,不涉及公式推导,如果对反向传播算法公式推导不熟悉,强烈建议查看另一篇文章神经网络之反向传播算法(BP)公式推导(超详细)

我们将实现一个 4 层的全连接网络,来完成二分类任务。网络输入节点数为 2,隐藏 层的节点数设计为:25、5025,输出层两个节点,分别表示属于类别 1 的概率和类别 2 的概率,如下图所示。这里并没有采用 Softmax 函数将网络输出概率值之和进行约束, 而是直接利用均方误差函数计算与 One-hot 编码的真实标签之间的误差,所有的网络激活 函数全部采用 Sigmoid 函数,这些设计都是为了能直接利用我们的梯度传播公式。

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from sklearn import datasets
  4. from sklearn.model_selection import train_test_split

1. 准备数据

  1. X, y = datasets.make_moons(n_samples=1000, noise=0.2, random_state=100)
  2. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
  3. print(X.shape, y.shape)
  1. (1000, 2) (1000,)
  1. def make_plot(X, y, plot_name):
  2. plt.figure(figsize=(12, 8))
  3. plt.title(plot_name, fontsize=30)
  4. plt.scatter(X[y==0, 0], X[y==0, 1])
  5. plt.scatter(X[y==1, 0], X[y==1, 1])
  1. make_plot(X, y, "Classification Dataset Visualization ")

2. 网络层

  • 通过新建类 Layer 实现一个网络层,需要传入网络层的输入节点数、输出节点数、激 活函数类型等参数
  • 权值 weights 和偏置张量 bias 在初始化时根据输入、输出节点数自动 生成并初始化
  1. class Layer:
  2. # 全链接网络层
  3. def __init__(self, n_input, n_output, activation=None, weights=None, bias=None):
  4. """
  5. :param int n_input: 输入节点数
  6. :param int n_output: 输出节点数
  7. :param str activation: 激活函数类型
  8. :param weights: 权值张量,默认类内部生成
  9. :param bias: 偏置,默认类内部生成
  10. """
  11. self.weights = weights if weights is not None else np.random.randn(n_input, n_output) * np.sqrt(1 / n_output)
  12. self.bias = bias if bias is not None else np.random.rand(n_output) * 0.1
  13. self.activation = activation # 激活函数类型,如’sigmoid’
  14. self.activation_output = None # 激活函数的输出值 o
  15. self.error = None # 用于计算当前层的 delta 变量的中间变量
  16. self.delta = None # 记录当前层的 delta 变量,用于计算梯度
  17. def activate(self, X):
  18. # 前向计算函数
  19. r = np.dot(X, self.weights) + self.bias # X@W + b
  20. # 通过激活函数,得到全连接层的输出 o (activation_output)
  21. self.activation_output = self._apply_activation(r)
  22. return self.activation_output
  23. def _apply_activation(self, r): # 计算激活函数的输出
  24. if self.activation is None:
  25. return r # 无激活函数,直接返回
  26. elif self.activation == 'relu':
  27. return np.maximum(r, 0)
  28. elif self.activation == 'tanh':
  29. return np.tanh(r)
  30. elif self.activation == 'sigmoid':
  31. return 1 / (1 + np.exp(-r))
  32. return r
  33. def apply_activation_derivative(self, r):
  34. # 计算激活函数的导数
  35. # 无激活函数, 导数为 1
  36. if self.activation is None:
  37. return np.ones_like(r)
  38. # ReLU 函数的导数
  39. elif self.activation == 'relu':
  40. grad = np.array(r, copy=True)
  41. grad[r > 0] = 1.
  42. grad[r <= 0] = 0.
  43. return grad
  44. # tanh 函数的导数实现
  45. elif self.activation == 'tanh':
  46. return 1 - r ** 2
  47. # Sigmoid 函数的导数实现
  48. elif self.activation == 'sigmoid':
  49. return r * (1 - r)
  50. return r

3. 网络模型

  • 创建单层网络类后,我们实现网络模型的 NeuralNetwork
  • 它内部维护各层的网络 层 Layer 类对象,可以通过 add_layer 函数追加网络层,
  • 实现创建不同结构的网络模型目 的。
  1. y_test.flatten().shape
  1. (300,)
  1. class NeuralNetwork:
  2. def __init__(self):
  3. self._layers = [] # 网络层对象列表
  4. def add_layer(self, layer):
  5. self._layers.append(layer)
  6. def feed_forward(self, X):
  7. # 前向传播(求导)
  8. for layer in self._layers:
  9. X = layer.activate(X)
  10. return X
  11. def backpropagation(self, X, y, learning_rate):
  12. # 反向传播算法实现
  13. # 向前计算,得到最终输出值
  14. output = self.feed_forward(X)
  15. for i in reversed(range(len(self._layers))): # 反向循环
  16. layer = self._layers[i]
  17. if layer == self._layers[-1]: # 如果是输出层
  18. layer.error = y - output
  19. # 计算最后一层的 delta,参考输出层的梯度公式
  20. layer.delta = layer.error * layer.apply_activation_derivative(output)
  21. else: # 如果是隐藏层
  22. next_layer = self._layers[i + 1]
  23. layer.error = np.dot(next_layer.weights, next_layer.delta)
  24. layer.delta = layer.error*layer.apply_activation_derivative(layer.activation_output)
  25. # 循环更新权值
  26. for i in range(len(self._layers)):
  27. layer = self._layers[i]
  28. # o_i 为上一网络层的输出
  29. o_i = np.atleast_2d(X if i == 0 else self._layers[i - 1].activation_output)
  30. # 梯度下降算法,delta 是公式中的负数,故这里用加号
  31. layer.weights += layer.delta * o_i.T * learning_rate
  32. def train(self, X_train, X_test, y_train, y_test, learning_rate, max_epochs):
  33. # 网络训练函数
  34. # one-hot 编码
  35. y_onehot = np.zeros((y_train.shape[0], 2))
  36. y_onehot[np.arange(y_train.shape[0]), y_train] = 1
  37. mses = []
  38. for i in range(max_epochs): # 训练 100 个 epoch
  39. for j in range(len(X_train)): # 一次训练一个样本
  40. self.backpropagation(X_train[j], y_onehot[j], learning_rate)
  41. if i % 10 == 0:
  42. # 打印出 MSE Loss
  43. mse = np.mean(np.square(y_onehot - self.feed_forward(X_train)))
  44. mses.append(mse)
  45. print('Epoch: #%s, MSE: %f, Accuracy: %.2f%%' %
  46. (i, float(mse), self.accuracy(self.predict(X_test), y_test.flatten()) * 100))
  47. return mses
  48. def accuracy(self, y_predict, y_test): # 计算准确度
  49. return np.sum(y_predict == y_test) / len(y_test)
  50. def predict(self, X_predict):
  51. y_predict = self.feed_forward(X_predict) # 此时的 y_predict 形状是 [600 * 2],第二个维度表示两个输出的概率
  52. y_predict = np.argmax(y_predict, axis=1)
  53. return y_predict

4. 网络训练

  1. nn = NeuralNetwork() # 实例化网络类
  2. nn.add_layer(Layer(2, 25, 'sigmoid')) # 隐藏层 1, 2=>25
  3. nn.add_layer(Layer(25, 50, 'sigmoid')) # 隐藏层 2, 25=>50
  4. nn.add_layer(Layer(50, 25, 'sigmoid')) # 隐藏层 3, 50=>25
  5. nn.add_layer(Layer(25, 2, 'sigmoid')) # 输出层, 25=>2
  1. # nn.train(X_train, X_test, y_train, y_test, learning_rate=0.01, max_epochs=50)
  1. def plot_decision_boundary(model, axis):
  2. x0, x1 = np.meshgrid(
  3. np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape(1, -1),
  4. np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape(-1, 1)
  5. )
  6. X_new = np.c_[x0.ravel(), x1.ravel()]
  7. y_predic = model.predict(X_new)
  8. zz = y_predic.reshape(x0.shape)
  9. from matplotlib.colors import ListedColormap
  10. custom_cmap = ListedColormap(['#EF9A9A', '#FFF590', '#90CAF9'])
  11. plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
  1. plt.figure(figsize=(12, 8))
  2. plot_decision_boundary(nn, [-2, 2.5, -1, 2])
  3. plt.scatter(X[y==0, 0], X[y==0, 1])
  4. plt.scatter(X[y==1, 0], X[y==1, 1])
  1. <matplotlib.collections.PathCollection at 0x29018d6dfd0>

  1. y_predict = nn.predict(X_test)
  1. y_predict[:10]
  1. array([1, 1, 0, 1, 0, 0, 0, 1, 1, 1], dtype=int64)
  1. y_test[:10]
  1. array([1, 1, 0, 1, 0, 0, 0, 1, 1, 1], dtype=int64)
  1. nn.accuracy(y_predict, y_test.flatten())
  1. 0.86

深度学习之反向传播算法(BP)代码实现的更多相关文章

  1. 深度神经网络(DNN)反向传播算法(BP)

    在深度神经网络(DNN)模型与前向传播算法中,我们对DNN的模型和前向传播算法做了总结,这里我们更进一步,对DNN的反向传播算法(Back Propagation,BP)做一个总结. 1. DNN反向 ...

  2. 神经网络与机器学习 笔记—反向传播算法(BP)

    先看下面信号流图,L=2和M0=M1=M2=M3=3的情况,上面是前向通过,下面部分是反向通过. 1.初始化.假设没有先验知识可用,可以以一个一致分布来随机的挑选突触权值和阈值,这个分布选择为均值等于 ...

  3. 【机器学习】反向传播算法 BP

    知识回顾 1:首先引入一些便于稍后讨论的新标记方法: 假设神经网络的训练样本有m个,每个包含一组输入x和一组输出信号y,L表示神经网络的层数,S表示每层输入的神经元的个数,SL代表最后一层中处理的单元 ...

  4. 深度学习——前向传播算法和反向传播算法(BP算法)及其推导

    1 BP算法的推导 图1 一个简单的三层神经网络 图1所示是一个简单的三层(两个隐藏层,一个输出层)神经网络结构,假设我们使用这个神经网络来解决二分类问题,我们给这个网络一个输入样本,通过前向运算得到 ...

  5. PyTorch深度学习实践——反向传播

    反向传播 课程来源:PyTorch深度学习实践--河北工业大学 <PyTorch深度学习实践>完结合集_哔哩哔哩_bilibili 目录 反向传播 笔记 作业 笔记 在之前课程中介绍的线性 ...

  6. 深度学习梯度反向传播出现Nan值的原因归类

    症状:前向计算一切正常.梯度反向传播的时候就出现异常,梯度从某一层开始出现Nan值(Nan: Not a number缩写,在numpy中,np.nan != np.nan,是唯一个不等于自身的数). ...

  7. 100天搞定机器学习|day37 无公式理解反向传播算法之精髓

     100天搞定机器学习(Day1-34) 100天搞定机器学习|Day35 深度学习之神经网络的结构 100天搞定机器学习|Day36 深度学习之梯度下降算法 本篇为100天搞定机器学习之第37天,亦 ...

  8. 卷积神经网络(CNN)反向传播算法

    在卷积神经网络(CNN)前向传播算法中,我们对CNN的前向传播算法做了总结,基于CNN前向传播算法的基础,我们下面就对CNN的反向传播算法做一个总结.在阅读本文前,建议先研究DNN的反向传播算法:深度 ...

  9. 100天搞定机器学习|day38 反向传播算法推导

    往期回顾 100天搞定机器学习|(Day1-36) 100天搞定机器学习|Day37无公式理解反向传播算法之精髓 上集我们学习了反向传播算法的原理,今天我们深入讲解其中的微积分理论,展示在机器学习中, ...

随机推荐

  1. SpringMVC处理中文乱码

    SpringMVC自带过滤器 添加至web.xml文件 <filter> <filter-name>encoding</filter-name> <filte ...

  2. mysql5.6创建账户不能本地登录

    1.通过xshell连接linux,命令登录mysql 2.创建一个新的库(其实创建不创建都可以) 3.创建账号权限 创建账号luffy 密码luffy 针对库luffy所有权限,允许任何人远程登录 ...

  3. python算术

    ''' 1.对每个数进行平方, 2.求和 ''' print(sum(x ** 2 for x in range(4)))

  4. B - 青蛙的约会

    两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面. 它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止. 可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方 ...

  5. 银行贷款利率低到“令人发指”,很多人还坚持借高利贷,why?

    编辑 | 于斌 出品 | 于见(mpyujian) 网络上,每隔一段时间,就会出现因为借了高利贷,家破人亡的新闻. 这种现象,层出不求,但其实,我们每次看了这些新闻,只是为其感到惋惜,并没有进一步去发 ...

  6. JAVA 注解教程(一)简单介绍

    相关网址 https://blog.csdn.net/briblue/article/details/73824058 --- 已经整理成笔记 https://blog.csdn.net/bao199 ...

  7. python collections 模块 常用集合

    1.nametulpe # tuple 可以表示不变集合 列如坐标 point = (1,1) # 缺点是 只可以通过下标方式访问 #namedtuple是一个函数,它用来创建一个自定义的tuple对 ...

  8. 通过恢复目录(Catalogue)进行PDB级别的PITR恢复

    数据库版本:Oracle 12.2.0.1 本篇为<执行PDB的PITR恢复失败的说明 (文档 ID 2435452.1)>的证明篇,通过当前控制文件,无法在PDB级别进行PITR(Poi ...

  9. git 卡住推不上去

    luoxu@lenovo:~/testGit/.git$ env | grep -i proxy 查看有没有设置代理 ALL_PROXY=socks://127.0.0.1:1080/ no_prox ...

  10. jmeter 登陆--查询存在否-->新建客户-->查询存在否 + 压测

    1.登陆 正则表达式提取器和json提取器,都是后置处理器提取token(都可以在响应中以regexp tester 和 json path tester查看提取的对不对) beanshell 后置处 ...