为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型


各位看官想必对大名鼎鼎的 “卷积神经网络”(CNN)一定不陌生。在《用Python实现深度学习框架》的第8章中,我们用自己实现的框架 MatrixSlow 搭建卷积神经网络并将其用于实际问题。

在讲到 CNN 的原理时,我们从“可训练的滤波器”这个角度切入讲解 CNN 的动机和能力之源。

本文挑选了本章中一个很有意思的小例子,那就是用计算图的自动求导训练一个Sobel 边缘查找滤波器。下面让我们从一个有趣的问题开始吧!

假设你接到了这样一个图像分类任务:分辨蒙德里安和罗斯科的作品。 

先来介绍一下这两位画家:彼埃·蒙德里安(Piet Cornelies Mondrian,1872—1944),荷兰画家,风格派运动和非具象绘画的创始者之一;马克·罗斯科(Mark Rothko,1903—1970),美国画家,抽象派运动领袖之一。

然后再来看看他们的作品,哪怕是一个艺术外行(比如作者本人),相信在看了若干作品之后,也能准确地分开这两位画家。可是,若要你通过编写程序来分类这两位画家的作品,该怎么办?读者可以自己先想一想。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图1 蒙德里安(左)与罗斯科(右)的作品

下面我们提一个思路,因为经过观察发现,在蒙德里安的作品中,色块之间有清晰明显的边缘,而罗斯科的作品中则缺乏这样的边缘。

因此,如果有一种方法能够识别画面中的边缘,并将其体现在数值上:边缘较多较明显则得到一个较大的数值,边缘较少较模糊则得到一个较小的数值。那么,我们只要将这两类图画在边缘上的显著区别量化为数值,并以此为依据,就可以分开这两位画家的作品了。

用 PhotoShop 打开一幅蒙德里安的作品,在菜单栏中依次找到 “滤镜—>风格化—>查找边缘”。应用之后,其画作中区域之间的边缘以黑色凸显出来,而大面积的单色区域则呈白色,如图2所示。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图2蒙德里安的作品查找边缘后的结果

 

再来试试罗斯科的作品,如下图。我们可以看到,其作品中的边缘相对较少。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图3罗斯科的作品查找边缘后的结果

 

在数字图像中,数值越大代表灰度值越高,越接近白色;反之,数值越小代表灰度值越低,越接近黑色。查找边缘后的图,边缘部分呈黑色,非边缘部分呈白色。

多边缘图和少边缘图的灰度值在统计上是有区分度的,因此可以凭借这个区分开多边缘图和少边缘图,即区分开蒙德里安和罗斯科的作品。但我们首先需要知道查找边缘做了什么。

为了简单起见,我们先只考虑单通道图像,其宽和高分别记作 w 和 h,则单通道图像就是一个矩阵。其灰度值是之间的整数,我们将它除以255,使之归一化到0和1之间。

于是,一幅图像就变成了一个元素值是0到1之间的实数、形状为的矩阵。现在,我们先构造一个小矩阵,形状为,元素值为:

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

 表1 

然后用这个小矩阵对图像做这样的计算:将小矩阵的中心位置对准图像中的某个位置,这时小矩阵的9个位置就分别对应上了图像中该位置及其周围的8个位置。

如果该位置位于图像的边缘,则小矩阵的某些位置就有可能会超出图像边缘,落在图像之外,这时默认它们对着的值是0。

然后,将图像上被小矩阵“盖”住的各位置以小矩阵对应位置的值为权重做加权求和,得到一个值,该过程如图4所示。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图4 加权求和 

接下来,我们从图像的左上角开始按行扫描,依次对图像中的每个位置执行上述计算。

最终,图像有多少元素就可以计算出多少输出值。输出值排列成与原图像形状相同的矩阵,其元素值可能会超出0到1的范围,这种计算称为离散卷积(discrete convolution)或滤波(filtering)。其中,小矩阵称为滤波器(filter)。

用滤波器对原图像进行滤波,会得到一幅输出图像,如图5所示。表1中的小矩阵叫作纵向索贝尔滤波器(sobel filter),除此之外,还有其他的滤波器,它们的形状和元素值不同,功能也不同。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图5滤波

用纵向索贝尔滤波器对蒙德里安的作品做滤波,得到的结果如图6所示。可以看到,画作中非边缘的区域是大面积的灰色,纵向的边缘呈现更浅的白色或更深的黑色,对应着更大或更小的灰度值。换句话说,纵向索贝尔滤波器找到了蒙德里安作品中纵向的边缘。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图6纵向索贝尔滤波器滤波蒙德里安的作品之后的结果

 

我们来解释一下为什么会得到上述结果,观察表1,会发现其中左列值较大:1、2、1,中列值均为0,右列值较小:-1、-2、-1。若滤波器的中心对准的是图像中某个非边缘的位置,则该位置左侧和右侧的灰度值差异很小,左侧三个位置分别乘上1、2、1,右侧三个位置分别乘上-1、-2、-1,两者相加之后会互相抵消,从而得到一个接近于0的结果,这就是图6中大片的灰色像素。

而对于图像中处于纵向边缘上的位置,其左侧和右侧的灰度值差异则较大。当两侧分别乘上互为相反数的两列权值再相加后,就会得到绝对值较大的正值或负值,所以输出图像在该位置上也会得到绝对值较大的正值或负值,这就是图6中较白或较黑的像素。

纵向索贝尔滤波器就这样找到了原图像中的纵向边缘。类似地,还有横向索贝尔滤波器,如表2所示。 

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

表2

 实际上,横向索贝尔滤波器是纵向索贝尔滤波器的转置。基于同样的原理,它能查找出图像中的横向边缘。我们再拓展一下,索贝尔滤波器以较大的绝对值标识边缘。

若将值取平方,则以较大的正值标识边缘。取两种索贝尔滤波器的平方和,则能查找出图像中的全部边缘。横向索贝尔滤波器查找横向边缘的结果如图7所示。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图7横向索贝尔滤波器滤波蒙德里安的作品之后的结果

回到蒙德里安与罗斯科的问题。用两种索贝尔滤波器先对两幅画作滤波,蒙德里安的画边缘清晰且多,输出图像中会有不少较大的绝对值罗斯科的画边缘模糊且少,输出中不会有太多较大的绝对值。

把两种滤波器的输出图像展开并连接成一个向量,这个向量对于两位画家的作品是有区别的。以这个向量作为输入,送给逻辑回归模型或多层全连接神经网络,再经过训练也许能分开两位画家的作品。整个网络的结构如图8所示:

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图8蒙德里安与罗斯科的作品分类网络

 

图8中的网络就是一个简单的卷积神经网络。为什么叫卷积呢?因为滤波器执行的计算在数学上叫离散卷积。

前面对于蒙德里安与罗斯科问题,我们采用的是“人脑建模”,其目的是阐述滤波器在这个模型中的作用。之所以选择索贝尔滤波器,是因为经过观察发现,蒙德里安与罗斯科的画作在是否存在边缘的问题上差别很大。

于是先选用索贝尔滤波器提取边缘,再将滤波输出并展开成向量后提交给传统的分类模型,比如逻辑回归模型。

在这里,索贝尔滤波器起到了从图像中提取特征的作用。但是对于其他的图像分类问题:比如猫与狗、交通工具、手写数字等,仅仅用查找边缘就够了么? 

显然不够,其实除了索贝尔,还有许多其他功能各异的滤波器。我们可以把它们全用上,然后将结果送给分类器。但是且慢,计算图的优势就是可训练。

滤波无非是对图像的一种计算,那么何不将它实现为计算图节点,然后靠训练来帮我们找到一个合适的滤波器呢?我们常听说卷积神经网络能“自动发现”特征,其实就是指将作为特征提取器的滤波器纳入训练,然后由训练自动找到合适的滤波器。

我们在 MatrixSlow 中实现一类卷积节点,请见代码(matrixslow/ops/ops.py)。运用该节点类时,将图像放在一个变量节点中,将滤波器放在另一个变量节点中,然后以它们为父节点构造 Convolve 类节点。

在该节点上调用 forward 方法,节点的 value 属性就是滤波结果。我们来看一个例子,请见代码(example/ch08/sobel.py)。这个小例子计算了输入图像的横向和纵向索贝尔滤波,最后将原图、平方和、纵向索贝尔滤波和横向索贝尔滤波的结果都显示出来,如图9所示。

由该图可见,原图中两侧灰度值差异较大的边缘被明显地勾画了出来,有些边缘不明显是因为其两侧的灰度值差异较小。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图9原图(左上)、索贝尔滤波器及其平方和(右上)、纵向(左下)与横向(右下)

 

滤波器属于计算图中的一个变量节点,变量节点都可以被训练,因此滤波器也可以被训练。

我们接下来尝试训练一个纵向索贝尔滤波器,我们以被训练滤波器的输出与真正索贝尔滤波器的输出的均方误差作为训练的损失,若均方误差越小则表示两个输出越接近。

以均方误差为损失能否把随机初始化的滤波器训练成纵向索贝尔滤波器呢?我们马上来试一试。首先,搭建计算图,如图10所示。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

图10  训练滤波器的计算图

 

这个例子同样也能展现计算图的灵活性,请看代码(example/ch08/sobel_train.py)。

在上述代码中,我们首先读取图像并归一化。然后构造一个变量节点 sobel,不需要初始化也不参加训练。它被赋以表1中的纵向索贝尔滤波器。img 是形状为(w, h)的变量节点,用来保存蒙德里安的画作。

以 img 节点和 sobel 节点为父节点构造 Convolve 类节点 sobel_output,它就是对蒙德里安的作品施加纵向索贝尔滤波器的结果。

filter_train 是一个的变量节点,用来保存被训练的滤波器,需要初始化且参加训练。以 img 节点和 filter_train 节点为父节点构造 Convolve 类节点 filter_output,就是经被训练的滤波器滤波的蒙德里安的作品。

接下来有一些小花招。minus 节点是一个变量节点,不需要初始化且不参加训练,它被赋值为与原图像同形状、所有元素都为-1的矩阵,这是因为 MatrixSlow 框架只有矩阵加法节点,需要这个-1常量矩阵帮助做减法。

n 是的变量节点,不需要初始化且不参加训练,它被赋值为原图的像素数的倒数,求均方误差时要用到它。 

将 filter_output 节点与 minus 节点相乘,再加到 sobel_output 节点上得到 error 节点,就是纵向索贝尔滤波器与被训练滤波器的输出之差。

之后,先将 error 节点展开为行向量,再乘上由它展开成的列向量,结果就是误差向量与其自身的内积(矩阵),即误差平方和,然后将它保存在 square_error 节点,将该节点与n节点相乘得到的 mse 节点,即为均方误差(mean square error)。

以 mse 节点为目标节点构造优化器,学习率为 0.01。训练500个迭代,每个迭代都调用优化器的 one_step 方法执行前向和反向传播;调用 update 方法更新被训练滤波器的值。打印出迭代数和当前损失值,就可以看到损失值的下降。训练结束后,我们看一下 filter_train 节点的值:

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

很明显,被训练的滤波器已经很接近纵向索贝尔滤波器了(注意科学记数法的幂)。滤波器可以训练,因为在计算图中它只是一个变量节点而已。

令图8中的滤波器不再是事先设置好的纵向和横向索贝尔滤波器,而是两个或者更多可训练的滤波器,将它们的输出图像展开并连接在一起,然后送给逻辑回归或多层全连接神经网络,就是卷积神经网络。

卷积神经网络的本质就是对图像使用多个滤波器,这些滤波器根据损失受到训练,从而起到从图像中提取特征的作用。后续的网络则负责依据这些特征做分类或其他任务。

索贝尔滤波器或其他滤波器是人为设计的滤波器,因此人们知道它们具有什么功能,提取图像的什么特征,人们运用它们提取特征并为后续的模型而服务。

而卷积神经网络则是根据问题的本身来训练滤波器,有些时候,人们能够理解这些被训练出来的滤波器的功能(其中有的就是索贝尔),但是在大多数时候人们并不能理解它们的作用和功能,但它们对当前的问题就是(也许)有用。这就是连接主义人工智能的神秘之处。 

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

张觉非,陈震 | 著

本书特色:

  • 大咖推荐:复旦大学计算机学院教授邱锡鹏、一流科技创始人兼CEO袁进辉(@老师木)、格灵深瞳创始人兼CEO赵勇、奇虎360集团副总裁邓亚峰联合推荐

  • 干货满满:从零开始用Python实现自己的深度学习框架,搭建从逻辑回归到卷积神经网络的各类模型和网络,涵盖模型的训练、评估、保存与部署等工程问题

  • 聚焦实战:360智能工程部高级机器学习算法工程师倾力打造

内容简介:

本书带领读者用原生Python语言和Numpy线性代数库实现一个基于计算图的深度学习框架MatrixSlow(类似简易版的PyTorch、TensorFlow或Caffe)。全书分为三个部分。

第一部分是原理篇,实现了MatrixSlow框架的核心基础设施,并基于此讲解了机器学习与深度学习的概念和原理,比如模型、计算图、训练、梯度下降法及其各种变体。

第二部分是模型篇,介绍了多种具有代表性的模型,包括逻辑回归、多层全连接神经网络、因子分解机、Wide & Deep、DeepFM、循环神经网络以及卷积神经网络,这部分除了着重介绍这些模型的原理、结构以及它们之间的联系外,还用MatrixSlow框架搭建并训练它们以解决实际问题。

第三部分是工程篇,讨论了一些与深度学习框架相关的工程问题,内容涉及训练与评估,模型的保存、导入和服务部署,分布式训练,等等。

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型

为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型