从零开始学人工智能(11)--Python · 神经网络(四*)· 网络

浏览: 1300

作者:射命丸咲    Python 与 机器学习 爱好者

知乎专栏:https://zhuanlan.zhihu.com/carefree0910-pyml 

个人网站:http://www.carefree0910.com 

往期阅读:

从零开始学人工智能(9)--Python · 神经网络(二*)· 层

从零开始学人工智能(10)--Python · 神经网络(三*)· 网络

最终成品的 GitHub 地址:

https://github.com/carefree0910/MachineLearning/tree/master/NN

本章用到的 GitHub 地址:

https://github.com/carefree0910/MachineLearning/blob/master/Zhihu/NN/_extra/one/Networks.py

与 tensorflow 版本类似,我们要先定义一个能把输入变成输出的函数(输出函数)和一个用来训练我们模型的函数(训练函数)、然后定义一些函数评估我们的模型。由于不像 tensorflow 那样把最终损失化为了一个数、所以我们的输出函数(前向传导算法)相比之下形式很简单:

def _get_activations(self, x):
   _activations = [self._layers[0].activate(
       x, self._weights[0], self._bias[0])]
   for i, layer in enumerate(self._layers[1:]):
       _activations.append(layer.activate(
           _activations[-1], self._weights[i + 1], self._bias[i + 1]))
   return _activations

需要指出的是,由于 BP 算法是自己实现的、所以需要把激活值记录下来以减少 BP 算法中的计算量(因为许多激活函数【比如 Sigmoid】的导函数用函数值来算会比用输入算块一些)

训练函数的话就比 tensorflow 版本要复杂了、因为要手动进行梯度下降:

    def fit(self, x=None, y=None, lr=0.01, epoch=10):
       # Initialize
       self._add_cost_layer()
       self._init_optimizers(lr)
       layer_width = len(self._layers)
       # Train
       for counter in range(epoch):
           # 如有必要,更新优化器中的参数
           self._w_optimizer.update(); self._b_optimizer.update()
           # 调用前向传导算法获取各个激活值
           _activations = self._get_activations(x)
           # 调用反向传播算法获得各个局部梯度
           _deltas = [self._layers[-1].bp_first(y, _activations[-1])]
           for i in range(-1, -len(_activations), -1):
               _deltas.append(self._layers[i - 1].bp(
                   _activations[i - 1], self._weights[i], _deltas[-1]
               ))
           # 调用相应方法进行参数的更新
           for i in range(layer_width - 2, 0, -1):
               self._opt(i, _activations[i - 1], _deltas[layer_width-i-1])
           self._opt(0, x, _deltas[-1])

可以看到里面用了大量 Optimizers 相关的东西,若有需要的话可以参见这篇文章(地址:http://www.carefree0910.com/posts/55a23cf0/);这里我们只需知道 self._opt 这个函数能够利用激活值和梯度帮我们更新相应的变量就行

可能会有观众老爷注意到我在定义 _deltas 这个存储梯度的列表时调用的是 bp_first 函数,这是什么意思呢?不知大家还记不记得、在 BP 算法推导过程中、最后一层(亦即 CostLayer)的梯度计算和其余层是不太一样的,这里这个 bp_first 即是 CostLayer 对应的 BP 算法

模型搭好之后就能跑一跑并评估一下了。我写了一个小的可视化函数并生成了一个螺旋线数据来进行测试和评估,效果大概如下:

image.png

模型结构是两层 ReLU 各 24 个神经元,CostLayer 是 Softmax + Log Likelihood,Optimizers 选择的是 Adam。迭代了 1000 次,耗时 1 秒左右。值得一提的是,用 tensorflow 来训练的话要 3 秒左右(GPU 版本),观众老爷可以想想这是为什么 ( σ'ω')σ (事实上,tensorflow 本身不适合用于训练规模太小的模型、不仅限于这一种情况)

以上,一个完整的纯 Numpy 实现的神经网络结构就搭建完了,合共 150 行 Python 代码,比 tensorflow 版本的要长一些


希望观众老爷们能够喜欢~


公众号后台回复关键词学习

回复 人工智能          揭开人工智能的神秘面纱

回复 贝叶斯算法      贝叶斯算法与新闻分类

回复 机器学习          R&Python机器学习

回复 阿里数据          阿里数据系列课程

回复 Python             Python机器学习案例实战

回复 Spark               征服Spark第一季

回复 kaggle             机器学习kaggle案例

回复 大数据             大数据系列视频

回复 数据分析          数据分析人员的转型

回复 数据挖掘          数据挖掘与人工智能

回复 机器学习          R&Python机器学习

回复 阿里数据          阿里数据系列课程

回复 R                      R&Python机器学习入门


推荐 1
本文由 人工智能爱好者社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册