2018下半年,虽然基础的深度学习课程已经学完了,但实战甚少。收益也甚少,完全没有达到能够做项目的水准。而这个学期,在经历了短暂的迷茫之后,项目一个个的找上门来——要开始忙碌了。

对于我目前感兴趣的这个领域,我有很多种叫法。最通用的说法是“在搞人工智能”,但是每次我说完肯定是要捂脸的,因为“深度学习”(或者简称 DL)这种技术本身也只不过是一个名头,本质不过是把相同的函数(大多数是一次函数)套在一起算而已。而且做数据也并不是很多人想象的那样,满版的数学公式和图表。相反,第一步往往是所谓的“训练集”。

比方说要训练一个图片分类模型,区分猫和“不是猫”,我首先要做的不是搭建 AI,而是要上网爬几千张猫的图片和不是猫的图片,要是不明所以的人经过我的电脑,一定不会觉得我在做深度学习,而是觉得我是个吸猫狂魔。

就像这样…

Anyway,回到正题,深度学习这条路还是任重道远。总结起来,上个学期的工作有如下的局限:

  • 没有做好数据整理工作
    • 数据集堆在项目的文件夹里,GitHub Push 的过程中还要区别处理
    • 数据整理的工具很惨淡
  • 没有找到适合的工具
    • 模型的迭代基本上都是 Keras
    • PyTorch 等框架基本没有尝试
    • 有一些任务,只需要像 Caffe 这种简易框架就可以搞定了(或者还有更简单的),但是在研究中并没有相关的需求
  • 基本没有分析模型
    • 基本上就是以 Accuracy 作为指标
    • 可视化等等几乎为零
  • 对 AI 领域的需求和实际研究方向没有足够的了解

因此,在开学之前(好吧拖延症又犯了),我决定开展多一个小项目: Shoshin Trainer,搭建好个人的 DL 学习 & 实验环境。同时,这篇文章也算是对我一部分生产力的总结和反思。

深度学习的学习目标和要求

需要有的能力大概是:

  • – 能够掌握实验的方法,并熟练完成模型迭代
    • – 知识要求:综合编程能力;计划能力
    • – 外在要求:框架;硬件
  • – 能够掌握数据的获取和处理方法
    • – 知识要求:爬虫;框架的发掘和运用;计划能力;数据整理意识
    • – 外在要求:一套数据整理规范
  • – 能够按照需求搭建模型

要求:

  • 熟练掌握各种模型的细节、现有的研究/实战用框架,并且能够综合全栈知识
  • 外在要求:
    • 一定要能够清晰向别人陈述问题、请教问题
    • 系统的学习新技术
  • 学会分析训练数据,并用数据评估模型
  • 知识要求
    • 卷积可视化
    • Tensorboard 等分析工具;其它的权值分析方法;等等
  • 有一套规范操作:比如数据处理的时候,获取 – 处理 – 使用 – 存档要有相关的规范性。
  • 能够在迭代的过程,总结经验
  • 能够跟上前沿的技术

数据

数据获取

以图像分类任务为例,获取公开的训练集,或者使用爬虫获取文本和图片。

以 google-images-download 为例,目前的基本基本思路是:

  1. 在服务器上下载数据并打包,放在固定地址
  2. 终端从网站静态地址下载,并解压到训练集的 Raw 目录
  3. 执行数据清洗相关的程序,把处理之后的训练集和测试集压进 NumPy 数组中保存(曾经尝试过 h5 但是并没有达到预期的效果)。
  4. 把数据保存在 npz 文件中,然后转移到 Preprocessed 目录
  5. 等待训练

训练数据和系统分区分开存储。考虑到稳定性, HackOS 不能读取 PM981 上的任何数据,因此在使用自己机器的时候,训练数据主要存储在 Local Data 和 Shared Data 分区;在实验室的时候,数据放在 HDD 中。

数据需要根据是否经过清洗来分类。目前已经写了一个 Python 模块把文件分类并写入训练集。

数据处理

对于图片而言,如下处理会用的比较频繁:

  • Resize & Random Crops
  • “抗逆”调节(随机亮度,对比度,饱和度和 Hue 等)
  • 图片标记的处理

以图像的文本检测和识别为例。对于强标记的图片,我们只需要写一个脚本把数据导入就可以了。但是,对于一些弱标记的图像,并没有很好的办处理它们。我们可能要做很多处理。举例:理想状态下,除了训练集图片之外,还会附带一个数据文件告诉我图上那个位置是哪个字,方便模型“学习看图识字”,但是有些训练集里面,直接就把结果写在了图上。

曾经有过一个设想,就是通过 Neural Style Transfer 或者 GAN 生成手写体,然后再 feed 给识别模型,这样也许能够提高模型的抗逆能力(怎么突然就想起我们的初中英语老师说,她的英语老师为了给学生练听力,专门跑到公路边录音)。生成手写数字和字母已经有现成的解决方案了,[DeepFake] 和[生成二次元角色]的解决方案可以说都成熟了,但是对于很多复杂内容的生成,还是不够哈。

模型

“resnet”的图片搜索结果
(Model Figuare from arXiv.org)

最难的莫过于这一部分。我接触过很多模型,我也尝试过运行这些模型,但是并没有给我很大的惊喜。相反,大部分时间都浪费在了搭建环境上面。但是小小的积累了一些运维经验之后,我跌跌撞撞的还是做了一些东西。

曾经就某一些项目咨询过老师。他们的建议是:先下载别人的模型,然后尝试运行他们的模型,分析一些不足之处然后改进。而且,鉴于现在技术已经非常成熟,模型的结构已经很难有改进的空间——比如图像分类网络 VGG-19,无数的实验者证明了它在拥有19层的时候分类效率最好,如果是18层或者20层,总体的正确率就会总是差一些。所以,我能做的只不过是让别人的模型在自己的任务上跑的尽可能好一些罢了,

训练

训练曾经是一件很令人头疼的事情。我曾经用35000 多张图片(经过数据增强)训练一个 ResNet,希望它能够认出我的手势数字,然而收效甚微。

当然,有一些模型经过了预训练,训练的更快,效果也好很多。这个真的没法比。然而我现在还没用过预训练的模型,也许是时候尝试了吧。

工作流大概如下:

  • 实行排班制度。充分利用手上的计算资源。
    • 如果没有模型可以训练,可以尝试用新的开源模型解决旧的问题
    • 或者持续训练旧的模型
  • 参数调整
    • 按照超参数集调整训练
    • 每一个模型,都要重复训练数十次,每一次经历数十甚至更高次数的 epochs 进行实验
  • 训练结果可视化
    • Tensorboard 集成
    • 训练日志
    • 探索适合 DL 领域的 metrics

由于训练的结果高度不确定,并且一次可能要跑好几个小时甚至好几天,“炼丹”这个名字广泛流传,让深度学习多少了几分神秘色彩(其实什么都没有)和几分暴发户的味道。所谓的“人工智能”,背后其实是成千上万的调参工作者。我不否认新的算法和架构让DL进驻到更多的领域,但是随着 DL 领域的成熟,我们也可以遇见:容易摘取的果实已经被摘尽了。

印象比较深的例子,是用各种方式训练一个最简单的二元分类模型:cat-vs-noncat。

一开始的训练集很简单,只有 200 多张图片,测试集50张。用4层卷积训练了20分钟,就能得到一个正确率98%的模型,而使用复杂的 ResNet50 效果却并不好。更离奇的是,当训练集扩展到3200张图片的时候,ResNet50 的精确度被限制到了 80%以下,而 CNN 则陷入了长期的 Plateau,精确度跟没训练过差不多。当然,这个例子给了我不少思考。

评估

紧接着上面的例子,我就要开始思考:这其中到底发生了什么?

我的想法大致有这么几个:

  • 正负训练集比例问题。这是一个很简单的二元分类问题,按照常理来说,cat 和 non-cat 的训练集数目应该相等。可是,non-cat的图像可能存在很多可能,像老虎、狮子等大猫就不必说了,有时候你还需要在图像中加入一些像风景、图片九宫格这样的东西,来提升抗逆性。那么这个时候,图片还要如何分配呢?
  • 噪音问题。在使用 Sigmoid 作为最终激活函数的情况下,通常预测一只猫的图片时,模型会输出一个 99% 以上的概率代表 cat 的可能。预测一种别的动物时,这个概率会降到 1% 以下。但是,在预测风景照或者人群的照片时,这个概率甚至可以达到 30-40%。这说明模型很容易收到影响,并且判断不了太复杂的照片。
  • 图片尺寸问题。用于训练和测试的图片,都要被压缩成以64px或者128px为边长的方形图片,这本身就对图片集产生了影响。而且吧图片压成 64px真是一个惨不忍睹的决定,看着那个图片,虽然你模模糊糊的知道那是猫,但是你拿给一个不知情的人去看,他说不定会认错。
  • 学习率的选择。这是由于训练集一开始就陷入平原而猜测的结果。

如果我有足够的编程能力和资料搜集能力,那么我在一开始项目的时候大概就会考虑到这些因素。然而这接近于不可能。

并且,有一个很要命的问题就是计算资源。有一些开源的模型,在训练方面的自定义程度有限,如果一次性注入所有的训练集,显存是不够的,但又实在是懒得改代码——what a tragedy。现在计算资源可以说是好一点了,但是很多别的事情并没有想象中的容易。

Why Deep Learning?

我有时候也很疑惑,不知道是什么让我走上了 DL 的不归路(看似)。

然后不知道为什么写文章写到后面,尤其是如果耳边播的是 Spotify 的迷之歌单,再硬核的文章都会越写越软。(我突然间想给《Sol音》那篇博客写第二篇了)

令我记忆深刻的,几年前,我也曾有一次机会选择自己的方向,但是我没有珍惜。记得当时他们问过我想要做什么,我只能含糊着答一个“智能化”,因为从热点新闻中我觉得它很有前景。我记得我看着知乎专栏上的文章在讲神经网络,很是羡慕,很是跃跃欲试,但是总觉得“人工智能”实在是太难了。

我早已原谅了当初的选择。但是同样令我记忆深刻的,2017 年年末的时候,我偶然看到了 Andrew Ng 的视频,尽管那还不是 Coursera,只是 YouTube 上的算法推荐。我当时觉得他讲的课非常 explained,还谈了他对人工智能的一些理解,给了我不小的触动。在当时,我是非常珍重这种感觉的。

度过了漫长的 2018 上半年。6 月份,和父母聊了两个星期,我们敲下了一个非常重要的决定,至此,不管什么迷茫或者无力或者痛苦,我得去了解我想要了解的东西了。那段长长的日子里发生了什么,留下的影子有多少可以回忆,我感觉已经很难讲清楚了,但是我记得有很多天,一个人坐在一个空旷而僻静的咖啡馆里面看 Coursera 的教学视频,然后一个个的肝那些令人头疼的 assignment。And that’s it. The moments the year, the years, no more to talk about I guess.

曾经写过一篇文章,好像叫《AI公论》来着,名字是《IT公论》停播之后念念不忘取的。我当时找了一个案例,是 Cambridge Analytica 当时通过大数据获取公民的信息,然后分析他们的性格、社交属性和各方面的态度,最终的目的却是帮助选举。但从那时开始,我就思考过一种可能:通过深度学习构建出一个心理模型。当然,我现在清楚它几乎不可能在短期实现,但是在理解自己内在动机的时候,这倒是很有意思的一点。

DL 的延续得谈到 18 年的下半年了。我认识了 Simon,认识了 Bernie, Steven, William 等等小伙伴。第一次做实操的项目,写一个小小的数据处理程序,本来是信心满满的,结果在 pickle dump 写入文件的时候,由于优化问题几次压垮了我整整 16 G 的内存。使尽手段跑起来,三分钟之内,填满了 20G 的硬盘空间。那是第一次感受到数据的重量。

经历过通宵编译框架,无功而返。经历过数据集的 building,等的海枯石烂。经历过 2 to 3 的痛,云 GPU 的肉疼,和配置环境的抓狂。我敲键盘的同时,还在想着实验室机器的 CUDA 装好了没。要是装不好,我就只能在可怜的小笔记本 CPU 跑上好几天了。

但是有一个让人难以割舍的事物也挺好。由于种种原因,我是很容易疲惫的,因此我必须珍惜能够令我感到安全,充实,而极少感到空虚和自责的事物。

至于那些宏达的 big picture,都大晚上了,还谈什么呢。明早这锅丹大概就炼好了,be sure to check out 🌞


The article contains the following from external sources:


Leave a comment

Your email address will not be published. Required fields are marked *