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

浏览: 691

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

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

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

往期阅读:

从零开始学人工智能(8)--Python · 神经网络(七)· CNN

从零开始学人工智能(9)--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 的基础上实现的且相当麻烦、所以我就没在我自己的结构里面实现分形。因此,我自己实现的网络中只有一个类,某种意义上也好看一些

在讲网络的实现之前,需要先提到的是:正如我们在上一章 (二*)最后提到的、Layer 是需要分成主层(Layer)和附加层(SubLayer)两种的。那么 SubLayer 是干嘛的呢?它可以在 Layer 的输出的基础上进行一些变换以得到更好的输出

典型的 SubLayer 有 Dropout 和 Normalize。它们的定义和功效我以后有时间的话会讲,现在我们只需要有这样一个感觉:SubLayer 通常可以优化 Layer 的输出;SubLayer 之间及 SubLayer 和其根 Layer(定义下面会说)之间的关联不应是可更新的关联(因为 SubLayer 更应该是一个“优化器”而不应是一个传统意义上的神经网络中的可更新的层)

那么 SubLayer 和 Layer 之间的结构关系就比较清楚了。具体而言,有:

  • SubLayer 是附加在 Layer 后面的

  • 一个 Layer 和若干 SubLayer 共同组成一个整体 

  • SubLayer 会有一个域记录其附加的对象(爸爸)

  • SubLayer 会有一个域记录其根 Layer(定义为最老的爸爸)(……)

  • Layer 会有一个域记录附加在其后的第一个 SubLayer (孩子)

  • Layer 会有一个域记录其最年轻的孩子,不妨把它称为最后之作(喂!)

这样说可能有点太抽象(是肯!定!太!抽!象!好!吧!),我们画张图来看:

image.png

(嗯。好丑。)

知道 Layer 和 SubLayer 之间的大概关系后、就可以着手实现网络了(目前为止我们的 SubLayer 只有 CostLayer 一种,所以下面代码实现里面没有出现 SubLayer)。思路和 tensorflow 版本的差不多、亦即要先实现两个功能:

  • 加入 Layer 与 Layer 之间的关联

  • 加入 Layer 本身

其中加入关联这一步要比 tensorflow 版本的要简单很多:

def _add_weight(self, shape):
   self._weights.append(np.random.randn(*shape))
   self._bias.append(np.zeros((1, shape[1])))

加入 Layer 本身这一步则几乎一模一样:

def add(self, layer):
   if not self._layers:
       self._layers, self._current_dimension = [layer], layer.shape[1]
       self._add_weight(layer.shape)
   else:
       _next = layer.shape[0]
       layer.shape = (self._current_dimension, _next)
       self._add_layer(layer, self._current_dimension, _next)

唯一的区别在于在加入第二个 Layer 或者之后的 Layer 时,最后调用了一个 _add_layer 方法。这个方法能够协调 Layer 和 SubLayer 之间的关系,是我们搭建网络结构的关键所在:

def _add_layer(self, layer, *args):
   _parent = self._layers[-1]
   _current, _next = args
   self._layers.append(layer)
   if isinstance(layer, CostLayer):
       _parent.child = layer
       self.parent = _parent
       self._add_weight((1, 1))
       self._current_dimension = _next
   else:
       self._add_weight((_current, _next))
       self._current_dimension = _next

这里可能需要进行一些说明:

  • 当 layer 不是 CostLayer 时,做的事(else 块里的东西)和 tensorflow 版本的一样

  • 当 layer 是 CostLayer 时,我们只需在我们存储权重和偏置量的列表中放一个占位符、同时要更新一下父子关系(……)

以上就是与Python · 神经网络(三)· 层对应的、用纯 Numpy 写的结构。虽然代码很简单,不过涉及到的概念、理念可能有些太多,我们来整理一下:

  • 网络中有两种层:Layer 和 SubLayer。其中 Layer 是传统意义的 Layer, BP 算法更新层之间的关联时只会更新 Layer 之间的关联

  • SubLayer 是一种“优化器”,它能优化从 Layer那里得到的输出。它会在前向传导算法中用到、但在 BP 算法中、它会有三种行为:

    • SubLayer 之间的关联以及 SubLayer 和根 Layer 之间的关联不会被更新、因为它们只是占位符

    • SubLayer 作为优化器本身可能会有一些参数,这些参数可能会被 BP 算法更新、但影响域仅在该 SubLayer 内部(Normalize 是一个很好的栗子)

    • Layer 之间的关联的更新是通过更新最后之作和下一层 Layer 之间关联完成的:

      image.png

      (……捂脸)

最常见的两种 SubLayer 就是 Dropout 和 Normalize(Batch Normalization)了,如果想要知道怎么将它们加入我们的网络的话、知道这些理念是必要的。事实上,在这个框架搭建完成后,我们完全可以尝试使用诸如 Dropout + Normalize + Dropout 这样的结构会发生什么(虽然它可能非常不合理、但至少能去尝试)。而由于算法是用 Numpy 写的,我们甚至可以随便自定义 SubLayer 并尝试它和其它 SubLayer 的组合效果。这可能对一部分观众老爷比较有用 ( σ'ω')σ

如果弄懂了 Layer 和 SubLayer 之间的关系、加上已经支持的(比较简单的)自定义激活函数的话,可能就能初步应用它来扩展出属于自己的比较复杂的神经网络模型了。如果再能够理解这篇文章(地址:http://www.carefree0910.com/posts/55a23cf0/)里介绍的 Optimizers 的思想,我们就能自定义梯度下降算法、从而就可以对神经网络进行相当大的变装了

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


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

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

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

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

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

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

回复 Spark               征服Spark第一季

回复 kaggle             机器学习kaggle案例

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

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

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

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

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

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


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

0 个评论

要回复文章请先登录注册