鄙人本科从数学系毕业后,转入了人工智能领域进行硕士阶段的学习,众所周知,目前该领域最炙手可热的模型便是神经网络(Neural Network),生活中到处都是关于它的例子,例如随处可见的人脸识别系统、使得各国人民间能够愉快交流的翻译软件、手机输入法上的语音转文字系统等,可以说神经网络已经充分渗入到了大众的生活中。

甚至,基于神经网络广泛的应用环境,除了我们这个算是科班的研究领域,其在各种其他的领域也大放异彩,我了解到许多其他专业的同学,都能娴熟地调用各种深度学习库进行一些关于自身领域模型的训练,全民深度学习时代的到来意味着我们科班出身的研究者不能甘心于成为别人口中的调包侠、调参侠,我们在调包、调参的时候有必要去深入了解其背后的细节原理,从而掌握对模型自身结构的认识,在调参的时候更有方向感(bushi,怎么说了半天还是调参侠)可以对神经网络这个暗箱的行为更加熟悉和敏感,从而在自己搭建新的模型时做到事半功倍的效果。

而深入理解神经网络原理的唯一方法,就是自己手撸一个出来。这样达到的效果远比你看数十篇诸如《一分钟看懂神经网络》、《神经网络原理深度剖析》这样的博客要好得多。基于此,如果你正在看我这个系列的文章,并且也有深入理解神经网络原理的想法,我强烈建议你不要只看不做,在这个领域,多动手才是正道。同时,此系列文章将默认你已经看了各种上述博客,自认为对神经网络的基本原理有了明确的认识,熟知一些术语,如果对基本的概念尚不是很清楚,建议出门右拐。

不过我决定手撸一个神经网络完全是因为研一的深度学习课上,老师提了一嘴:“有兴趣的同学可以去自己手写一个玩玩”。

说干就干,第二天我就开始准备手撸神经网络,先从编程语言的选择开始,关于这点,我觉得既然只要验证神经网络原理,不需要在代码上追求过高的运行效率和空间利用率,那么易于开发的语言当然是最好的,因此我选择使用Python,主要调用其著名的科学运算库Numpy来封装自己的神经网络(我不会告诉你其实是因为我当时除了Python啥也不会)。

在半个月左右以后,一个主要基于Numpy,能实现几乎所有的常见矩阵运算、线性全连接层、一维二维卷积池化及BN操作、多种激活函数和损失函数的神经网络“库”就封装的差不多了,后面又修修补补了一些内容,代码在此仓库,代码写的非常的垃圾,但理解神经网络的初衷达到了。项目里主要用mnist数据集进行了验证(模型比较简单,准确率99%左右),后面还训练了一个孪生神经网络用以人脸验证,在预处理好的LFW测试集上达到了100%的准确率(当时自己都被震惊到)。

在项目结束十个月后,偶然又回过头看了下之前的代码,发现以前的思路也是忘的比较干净,代码只有上帝能看懂了,但突然想来写一个系列,把之前的思路捡起来,总结几篇blog,方便后人学习,更便于以后的我再次回顾。

这个系列将结合我自己在该项目上的学习经验,简单讲解一下个人认为最容易理解的神经网络的手撸方法,另外,网络上也有不少神经网络的手撸教程,但大多是教你撸最简单的多层感知器(MLP),你也一定看到过不少基于递推式的MLP反向传播代码,但这种写法个人并不推荐,因为过于注重递推式会导致容易忽略掉其核心原理。可能由于我比较菜,我一开始入门的时候,也是轻松就把MLP的反传递推公式推出来了,但在写代码的过程中,一堆字母,比如常见的$x$(线性变换前), $z$(线性变换后),$a$(激活后)以及乱七八糟的下标(不同的博客表示方式还不一样),着实把我绕晕了,结果导致我80%的时间都在纠结字母对应关系和下标加减1的问题。递推式的存在也让这种手撸神经网络的写法耦合度过高,稍微换一下网络的结构,原来的递推式就废了,新的递推式你很可能又要花大量时间去推导,如果数学能力差一点,你很有可能到头来只会推那一套递推式,所以个人不推荐这种写法。但如果你就想单纯搭个MLP,不想有更深层次的理解,那可以试试,至少工作量比较小。

这篇文章净讲废话了,硬核内容从下一篇文章开始更新。这个系列会很长,写完以后才感觉,其实15篇都不够我写的,各位若有兴趣,烦请耐心看完。