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

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

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

  1. 普通的神经网络,支持各种常见的激活函数如 Sigmoid、Tanh、ReLU 等。
    以下代码定义了一个含单层隐藏层的、含有 400 个神经元的、以 ReLU 为激活函数、以 Cross Entropy 为损失的神经网络:

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

     

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

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

     

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

  4. 普通的 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

  5. 分形的 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], ))
  6. 可扩展性。个人认为在这方面我还是下了比较大功夫的、所以可扩展性应该算不错。目前的话,用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)

      改成

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

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

    3. 可能会有观众老爷说,你这个只是把现有的东西偷偷换了一下,如果我想定义一个属于自己的、名字也是自己随便定的激活函数怎么办?!
      不妨将我们新的激活函数叫做 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 里面呢?嗯,为此你可以这样做:

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

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

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

            是不是很棒???(不)夸我吧!赞我吧!!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 结果的直观理解

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

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

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

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

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

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

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

免责声明:信息仅供参考,不构成投资及交易建议。投资者据此操作,风险自担。
如果觉得文章对你有用,请随意赞赏收藏
相关推荐
相关下载
登录后评论
Copyright © 2019 宽客在线