游戏0x004E:机器眼中的画
最近叶梓涛同学在西安吃香喝辣进行72小时极限游戏开发的准备,并且在努力从一个游戏设计师自我转化为业余的作曲家和业余游戏灵魂艺术家的过程中;加之肖大近来颇有写作欲望,所以今天的推文也由肖大负责(相信也是广大观众希望看到的...);这次的主题是由临摹而发,如果让机器来临摹作品,会发生什么 ...
临摹大佬的作品,是学习画画过程中的一个必经阶段。当把原画和临摹的画作比,虽然画的是同一个东西,其实也能看出一些差异。比如说,叶梓涛今天临摹的CM大大的画:
(以上为CM大大的原画)
(业余艺术家叶梓涛30min临摹作品 5/3000)
由此产生了一个有趣的问题,如果让机器来临摹作画,会是什么样子的呢?也许神经网络适合做这个事情?
在后面的内容中,我们将用 mathematica 语言搭建一个神经网络,然后使用监督学习的方法试图让它学会“临摹”。考虑到有些读者可能尚不清楚这些概念,在介绍之前我会先简单科普一下。磨刀不误砍柴工啦!
预备知识:神经网络 + 监督学习。
1
// 神经网络 //
我们平常所说的神经网络,其全称是人工神经网络(Artificial Neural Network),它是一种模仿生物神经网络的计算模型,用于对函数进行估计和近似。
生物神经网络的基本单元是神经细胞,也称为神经元。它接收由神经末梢传来的外部刺激,转化为电信号,根据刺激的强弱,这个神经会选择激活或者不激活。接着这些激活的神经元又会传导至另一些神经元,无数的神经元构成一个网络(神经中枢),最终做出决策。
在上个世纪六十年代,最早的"人造神经元"模型被提出,称之为"感知机" (perceptron)。
上图便是感知机的基本结构,它接收n个输入(a1, a2, ..., an),每个输入的边都上都有对应的权重(w1, w2, ..., wn),将输入值与权重值对应相乘之后再求和,而后提供一个激活函数再向外输出。
这个激活函数也很简单,就是个简单的判断:如果输入小于0,那么输出0,相当于抑制了信号,如果输入大于0,那么就输出这个值本身。写成函数就是 f(x) = max(0, x),这个函数有个特别的名字,叫做线性整流函数(Rectified Linear Unit, ReLU)
从函数的角度看,这其实就是个线性函数与 ReLU 函数的复合。
如果考虑神经元组成的网络,将这些结构串起来,那么就可以形成如下的多层神经网络结构。
其中每个圈都代表一个感知机模型(接受多个输入再经过激活函数输出的模型),它们彼此相连。每一个竖排代表了一个层(layer),从左到右,分别是输入层、隐藏层1、隐藏层2、输出层。
像这样的网络结构就代表了一个计算模型,给定输入的值,就可以得到输出的值。
(mathematica 中的7层神经网络结构)
在 mathematica 语言中,建立这样的一个多层神经网络很简单,只需要一行代码即可(具体见后文)。其中的 LinearLayer 代表的是线性函数层,而 Ramp 则是线性整流函数 ReLU。
2
// 监督学习 //
监督学习(Supervised Learning),是一个机器学习中的方法。它可以由训练的数据学习到一个模型(函数,learning model),并依照这个模型来对实例进行预测。训练的数据由两个部分组成:1)输入的向量,2)预期的输出结果。
例如,想要学习一个“能区分一张图片是猫还是狗”的模型,那么输入就是组成图片的像素值,预期的输出就是猫和狗的类别(例如,0代表猫1代表狗等),由于输出的类别是离散,所以这个过程也可以叫做分类。
再比如,想要学习一个“判断照片中的人是多少岁”,那么输入就是组成图片的像素值,预期的输出就是这个人的真实年龄,这时输出值是连续的实数,故这个过程可以叫做回归。
所以整个流程就是,给出训练的数据(输入和输出),对模型进行训练,训练的结果这个模型本身。注意在监督学习中,并不会具体要求模型是什么样子的,它只是代表一类方法。
那么有些聪明的读者可能会想到,前面不是说了神经网络是一种计算模型吗,那么它可以用在监督学习里吗?答案自然是可以的,这时的输入的向量就会经历前面所说的那些权重相乘啊、激活函数啊、感知机啊等等的变化操作,这个过程的每一步都是很清晰透明的。
3
// 神经网络临摹方法 //
呼,终于可以说到正题了。虽然前面的介绍有些晦涩难懂,但是,在具备神经网络和监督学习的基础知识以后,你就可以理解文章开头的那些图片是如何制作出来的了。
它的思路是用监督学习的方法学习一个神经网络模型,而监督学习有两个重要的要素,它们分别是:
输入向量:图片像素的 (x, y) 坐标
预期输出:该像素的 (r, g, b) 值
譬如输入的图片大小是600x400,那么就有 600 x 400 = 240,000 个像素,即有240,000个训练样本,训练后会学到一个由坐标映射到像素颜色的神经网络结构。
训练完成后,会进行预测阶段,输入每个 (x, y) 坐标,输入 (r, g, b) 值,然后再把这些颜色一个个的点到一张白纸上,这就形成了“神经网络眼中的图片”。
4
// Mathematica 实现 //
思路已经讲完了,后面的内容就是,这个过程如何在 mathematica 中实现。
Step 1 首先我们读入图片,然后构造从 (x, y) -> (r, g, b) 的数据:
最后的3行是训练数据的前三个,可以看到,这个就是从图片中提取的坐标到rgb值的数据。
Step 2 构造一个多层的神经网络
这时返回的是 mathematica 中内置的一个神经网络结构,它的参数显示是 unintialized。这说明参数是未初始化的,它需要在训练后才能使用。
Step 3 训练过程
这个过程很炫酷有木有!
不仅有进度条表示当前训练的进度,预期剩余的时间,还有看到实时的损失函数下降的曲线。而且还可以利用GPU来加速训练过程。如果感觉不太对劲,也可以提前终止训练过程。整个训练过程只要写一行代码就够了!
5
// 机器眼中的画 //
最后的结果如下:
嗯就是这种抽象的风格。再附上其他几张机器临摹的作品:
(猜猜原画是什么)
(这个原画是花吗?)
参考资料:
[1] 本文的代码参考自Mathematica的官方教程页面(含代码):https://www.wolfram.com/language/11/neural-networks/model-an-image-as-a-function.html?product=mathematica
[2] 对神经网络的介绍参考自维基百科:https://zh.wikipedia.org/wiki/%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C
[3] 对监督学习的介绍参考自维基百科:https://zh.wikipedia.org/wiki/%E7%9B%A3%E7%9D%A3%E5%BC%8F%E5%AD%B8%E7%BF%92
最近叶梓涛失去了语言能力
所以负责配图和美术
20min 速写临摹练习 1/3000
20min 速写临摹练习 9/3000
5min 乱试笔刷而出的作品 5/3000
FUJIMURASAKI
藤紫