从零开始学人工智能(1)--Python · 神经网络(零)· 简介

浏览: 1992

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

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

最终成品的 GitHub 地址:

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

由于神经网络听上去最厉害(?),所以打算先讲一讲这部分

封面图算是最终结果中 CNN 的一个比较简易的呈现;可能有些童鞋还不知道是什么意思,可能有些大神已经看出了一些端倪。总之,我个人的习惯是先说明最终能干什么、然后再来说怎么实现,这样也能避免一些不必要的信息筛选。所以,这一部分主要用于让已经知道一定的基础知识的童鞋知道最后能走多远,如果是想从头开始学的话可以无视这一章直接看第一章。

图文并茂是个不错的选择(废话

1、普通的神经网络,支持各种常见的激活函数如 Sigmoid、Tanh、ReLU 等。

以下代码定义了一个含单层隐藏层的、含有 400 个神经元的、以 ReLU 为激活函数、以 Cross Entropy 为损失的神经网络:

nn.add("ReLU", (x.shape[1], 400))nn.add("CrossEntropy", (y.shape[1], ))

实际应用中可用来训练著名的手写字体数据集 Mnist,10 次迭代后正确率有 98%
如果想更简单粗暴点的话:

nn.build([x.shape[1], 24, 24, y.shape[1]])

这定义了一个含两个隐藏层的、每层有 24 个神经元的、以 Sigmoid 为激活函数、以 Cross Entropy 为损失的神经网络

2、普通的 CNN,只要在 1. 中支持的激活函数、这里都会支持

题图就是一个例子;当然题图那种结构不怎么用于实际(其实也可以用但更多是觉得好玩才定义了诸如 (3, 1) 和 (1, 3) 这样的 Filter……)(但其实这种 Filter 有时很厉害的,这里按下不表)。有如下三个功能是值得一提的:

  1. padding 即可以自己定义(对应 tensorflow 中的 VALID)也可以直接用 SAME(默认是 SAME)

  2. 支持两种附加层 Dropout 和 Normalize;不仅是在普通神经网络中支持(参见下面的栗子),在 CNN 中也支持(参见下面分形 CNN 中的栗子) 

  3. 可以用循环体来堆重复的结构,比如:

nn.add("ConvReLU", (x.shape[1:], (32, 3, 3)))for _ in range(100):
   nn.add("ConvReLU", ((32, 3, 3), ))nn.add("ReLU", (512, ))nn.add("ReLU", (64, ))nn.add("Normalize")nn.add("Dropout")nn.add("CrossEntropy", (y.shape[1], ))

当然了,我相信上面这个 103 层的玩意儿不宜使用……但它没 bug(科科)

3、分形的 CNN,典型例子就是 GooLeNet,下面放出一个长得比较像的实现

    1. 用函数体把每一块分形封装起来:

      def add_layers(_nn):
         _nn.add("Pipe", 3)
         _nn.add_pipe_layer(0, "ConvReLU", ((32, 1, 3), ))
         _nn.add_pipe_layer(0, "ConvReLU", ((32, 3, 1), ))
         _nn.add_pipe_layer(1, "ConvReLU", ((32, 2, 3), ))
         _nn.add_pipe_layer(1, "ConvReLU", ((32, 3, 2), ))
         _nn.add_pipe_layer(2, "ConvReLU", ((32, 1, 1), ))
         _nn.add_pipe_layer(2, "Pipe", 2)
         _pipe = nn.get_current_pipe(2)
         _pipe.add_pipe_layer(0, "ConvReLU", ((16, 1, 3), ))
         _pipe.add_pipe_layer(1, "ConvReLU", ((16, 3, 1), ))
    2. 堆!!!

      nn.add("ConvReLU", (x.shape[1:], (32, 3, 3)))nn.add("ConvReLU", ((32, 3, 3), ))nn.add("MaxPool", ((3, 3), ), 2)nn.add("ConvNorm")add_layers(nn)nn.add("MaxPool", ((3, 3), ), 2)nn.add("ConvNorm")add_layers(nn)nn.add("AvgPool", ((3, 3), ), 2)nn.add("ConvNorm")add_layers(nn)nn.add("ReLU", (512, ))nn.add("ReLU", (64, ))nn.add("Normalize")nn.add("CrossEntropy", (y.shape[1], ))

4、可扩展性。

       个人认为在这方面我还是下了比较大功夫的、所以可扩展性应该算不错。目前的话,用tensorflow 的话支持自定义激活函数,如果用我自己写的 Numpy 算法(大概这东西叫做一个新的 nn 轮子?不太懂相关定义……)的话就还支持自定义 Optimizer。由于使用我自己写的算法来进行扩展的话,虽然自由度更高、但需要更多相关的基础知识,我打算把它放在一个额外的章节来讲,这里就只说怎么在使用 tensorflow 的情况下自定义激活函数吧;经评论区的童鞋提醒,我打算讲两种自定义方式:

    1. 在原有的激活函数上修改。比如我觉得 ReLU 在处理输入很大时的方法太豪放了想让它安分一点、给激活后的输出一个上界 6 的话(返回 min(max(x, 0), 6)) (这东西好像叫 ReLU6 ?),我可以这样把原来的 ReLU 类

      class ReLU(Layer):
         def _activate(self, x, predict):
             return tf.nn.relu(x)

      改成

      class ReLU(Layer):
         def _activate(self, x, predict):
             return tf.minimum(tf.maximum(x, 0), 6)

      就行了,同时该激活函数会自动被 ConvReLU、也就是 CNN 中使用的 ReLU 继承
      是不是相当方便呢 ( σ'ω')σ

    2. 可能会有观众老爷说,你这个只是把现有的东西偷偷换了一下,如果我想定义一个属于自己的、名字也是自己随便定的激活函数怎么办?!
      不妨将我们新的激活函数叫做 CF0910,它返回的值同样是 min(max(x, 0), 6) :

      1. 定义 CF0910 类并继承 Layer 类,同时定义其激活函数:

        class CF0910(Layer):
           def _activate(self, x, predict):
               return tf.minimum(tf.maximum(x, 0), 6)
      2. 在下面的“工厂”里面“注册”一下这个层的信息:

        class LayerFactory:
           available_root_layers = {
               "CF0910": CF0910,
               ...
      3. 完了。

是的没错,这就完了!!崭新的激活函数出现了!!拿着它去玩吧观众老爷们!!各种发 Paper 拿大奖不是梦!!(不

有些细心的观众老爷可能会发现:咦你这不是只定义了普通的神经网络层吗?那如果我想把这个激活函数应用到 CNN 里面呢?

嗯,为此你可以这样做:

    1. 定义一个继承了各种乱七八糟的东西的类(重点:顺序不能错!)(重点2:继承的第二个类就是刚刚定义的那个类!):

      class ConvCF0910(ConvLayer, CF0910, metaclass=ConvLayerMeta):
         pass
    2. 再去工厂注册一下:

      class LayerFactory:
         available_root_layers = {
             "CF0910": CF0910,
             "ConvCF0910": ConvCF0910,
             ...
    3. 完了。

是不是很棒???(不

夸我吧!赞我吧!!GitHub 上面 star 我吧!!!(喂

那么怎么应用呢?方法是一样一样的:

nn.add("ConvCF0910", (x.shape[1:], (32, 3, 3)))for _ in range(100):
   nn.add("ConvCF0910", ((32, 3, 3), ))nn.add("ReLU", (512, ))nn.add("ReLU", (64, ))nn.add("Normalize")nn.add("Dropout")nn.add("CrossEntropy", (y.shape[1], ))

Again,建议不要真的去跑这个结构……

如果想要了解我自己造的那个自由度很高的轮子的话,欢迎私信或者等我以后的附加章节~

此外,1. 和 2. 的结构是可以保存下来的(3. 的还没写因为感觉好麻烦)(喂):

nn.save()

读取也很方便:

nn.load()

然后可视化也做了一定的工作、包括但不限于:

  1. 预览结构

  2. 进度条

  3. 耗时统计

  4. CNN 结果的直观理解

  5. 以及其它……要说的话我还用 cv2 弄了一个动态的可视化(类似 TensorFlow Playground 那种的),有兴趣可以戳这个最终成品的 GitHub 地址看看~

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

========== 分割线的说 ==========

以上就是一个大概的功能呈现,感觉还是不错的(骄傲脸)(被打飞)

下一章开始就是从零起步了,具体而言会分为三种:

  1. Python 的基础,这一部分文章的标题形如 “Python · ***”

  2. 实现的思想、原理及代码,这一部分的标题就和这一章的类似,随介绍的算法不同而不同

  3. 数学的基础,这一部分的标题也与这一章类似,只不过前缀改为 “数学 · *** · ***”

  4. 额外的章节,这些章节的标题形如“Python · 神经网络(二*) · 层”、也就是说章节数的右上角会带一个星号。在这些的章节中,我会介绍我自己写的、只用到 Numpy 的算法,主要目的是服务想了解算法细节的观众老爷们 ( σ'ω')σ

自然,1. 的知识是各机器学习算法实现都共享的,2. 3. 的内容有一定相关性但分开来看不会有什么问题(大概)(喂

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

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

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

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

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

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

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

回复 Spark               征服Spark第一季

回复 kaggle             机器学习kaggle案例

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

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

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

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

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

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

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

0 个评论

要回复文章请先登录注册