Generative Adversarial Networks

生成对抗网络(Generative Adversarial Networks)越来越火,最开始是用于MLP的生成对抗网络,就是Ian J. Goodfellow论文中提出的。后来出现了CNN架构的,效果确实提高了。现在还有SeqGAN,我不敢做评论。既然是Simplified DeepLearning系列的,自然尝试最简单的。


Generative Adversarial Networks原理

GAN的原理其实很简单。首先我们要学习的是生成器G关于数据x的分布p_g,问题从哪生成呢,这就需要我们定义一个噪声先验p_z(z),如一个均匀分布。那么生成的样本就是G(z)。然后我们需要一个判别器D(y),判断y是来自G还是x,也就是D要判断出输入是伪造的还是真实的。这就是一个对抗学习的过程:G尽量生成逼近真实的数据,使D不能分辨真伪。D要足够厉害,能够分辨真伪。形象的图如下:

gan
图自slideshare

形式的代价函数如下:

    \[\underset{G}{\min}~ \underset{D}{\max} ~V(D,G) = \mathbb{E}_{x \sim p_{data}(x)}[\log D(x)] +\mathbb{E}_{z \sim p_{z}(z)}[\log(1 - D(G(z)))]\]

理解这个很重要,可以看看这个。这里其实是将两个loss拼起来了,而且省去了一部分。有了目标函数,训练则是交替的训练,论文中有详细描述。简单的说,就是一步固定G,训练D,然后固定D,训练G。作者提到,为了防止”the Helvetica scenario”,要训练D多步,然后训练G一步。


一维高斯分布

看一个简单的例子,也是论文中的例子,我觉得很多人没理解论文中那个用均匀分布生成高斯分布的例子。为了深刻理解,保证自己没有理解错误,我必须再现一下。网络结构很简单,没几行如下。

然后就是训练,具体见github。怎么知道我是对的呢。可以看以下训练过程。

init
初始状态
m1
训练好的判别器
m2
交替训练几步之后
m2
最后结果

 

我还能说什么,完全符合理论D^*(y) = \frac{p_{data}(y)}{p_{data}(y) + p_{g}(y)}以及最后D(y) = \frac{1}{2}。在强调一下,这是一维的情况,也就是从真实数据给出一个数字和从G中生成一个数字如4,判别器无法判断4来自真实数据还是伪造的,因为这两个分布产生这个数字的概率是一样的,如最后一张图。如果真实数据产生4的概率大一点,判别器就能稍微判断一下,如最后第二张图。


MNIST测试

又得用到果蝇MNIST了,上面的例子太简单,可能不能令人信服。代码其实差不多,稍微加了个dropout,见github。训练中间结果如下,注意这是一张只循环一次的gif,你可能要刷新一下。

mnist gan
mnist gan (gif)

可能注意到怎么只生成两个数字,这就是所谓的”the Helvetica scenario”,我还不知道哪里出了问题。反正能生成数字了,够了。


实践出真知,show me the code!

国庆终于把坑填完了,DOTA还拿了暴走,完成了千年辅助的梦想!3天没出宿舍楼,欢度国庆,开心!


链接

神经网络近似函数

神经网络的强大在于其能在有限区间内近似任意函数,更精确的说是MLP(多层感知机)是万能的函数近似机,证明由Cybenko给出。注意是在有限区间内,论文中也是在单位超立方体(the unit hypercube)内讨论。如果不是有限区间,可能得靠RNN,比如某些具有周期性质的函数,就能使用RNN近似。


MLP近似爱心函数

看到微博上推的使用MLP来近似函数的博文,我觉得少点东西,做点补充。第一步就挑一个有趣点的函数吧,随便挑个心形函数x^2+(y-\sqrt[3]{x^2})^2。然后用keras很快就能搭个MLP,具体见github

训练之后就能得到对这个函数的近似,画成图如下:

heart
近似爱心函数

还有个哥们居然搞了个penis的函数,无法直视,有兴趣的可以尝试。


RNN近似周期函数

超出训练的范围,MLP的近似就无效了,想想也知道,泛化能力不可能那么强。而RNN在一定程度上可以弥补一下,最好是有点周期性的函数。为了简单起见,就先用\sin(x)测试好了。同样用keras快速搭个RNN,具体见github

关键是训练数据如何构造,也就是输入输出是怎样的。跟MLP不同,这里用函数值预测函数值,而不是输入x。因为在如时间序列预测的情况下,输入x是未知的,只能使用之前已知的函数值。我用相邻 feature_length个点组成一步的输入,总共 seq_length 步,其中每个点间隔 interval 。那预测就是后面的点,也可以只预测一个,我测试是预测 feature_length个,其中一半重合。比如0到32个点预测16到48个点(这样的做法似乎也能使用在MLP预测时间序列中,Quantitative Finance论文)。说不清楚看下图或者看代码。

rnn predict
RNN输入和输出

之后就是训练了,\sin(x)可以说是完美近似,后面因为累积误差导致不能近似的很好也是正常的。我又测试了\sin(x) * \sqrt[10]{x},有一个递增项,效果就没有\sin(x)好了,但短期内效果还是好的。注意我画得图的区间不在测试区间内,也就是网络没看到过的数据,正因为RNN具有一定泛化能力才能有如此表现。

sinx
sin(x)
sinxx
sin(x)*x^0.1

累积误差比较蛋疼,如下的情况,就算是测试数据的范围内也会有问题。可以用beamsearch,或者其他目标函数做,比如Q-learning。比较复杂,这里只讨论最简单的情况。

误差
累积误差

总结

MLP还是很厉害的,只要参数足够多,就能在一定区间内近似任意函数。而RNN相当于图灵机,之前也写过使用RNN做时间序列预测的博文,由于数据不能放出,所以也没有把代码放出。这次的代码与上次是类似的,改改也能试试做时间序列预测,就我的经验来看,没有传统方法好。

 

Android监控服务器进程

相信很多同学遇到过在服务器上跑的程序被掐了或者莫名奇妙挂了的情况,特别是长时间运行的程序,如deep learning的训练,白白浪费一天可不好玩。因此我想了各种姿势监控我的程序,比如进程一旦消失就发邮件通知等等,感觉姿势不够美妙,于是最近鼓捣了一下,发现了神器。


Termux

Termux简直太吊了,简直就是一个五脏俱全的debian,你敢信他有apt?也就是可以安装ssh、python、git…..,所有的包可以看github。帅爆了,当时我就把那个弱鸡QPython删了。既然有了python,那能做的事就多了去了。当然也可以使用pip,只是像numpy的库依赖C库的包装不了。一言不合我就在安卓上装了个Flask。来看个Termux跑在Nexus 5上的截图,依次是当计算器的Python,跑了Flask的Python和Flask的网页。

termux flask flask2

 

帅的不能自理。是不是觉得配色有点难看,没事,可以付2.49刀买个Termux:Style,虽然我觉得改个配色应该很简单。这个开发者太有节操了,要钱的都是无关紧要的,不要钱的像Termux,Termux:API都很要紧,为了表示感谢,我买了个Termux:Widget(当然后面也能用到)。ssh就用 apt install openssh 就行了,然后跟普通Linux操作一样设置无密码登录就行了。Easy!备份手机能就变得很方便了,使用神器rsync,就一句命令如 rsync -aXvh --delete -P /sdcard/ "ssh -p port" user@ip:backup ,而且由于是增量备份,只有第一次备份可能需要花一点时间。总之,Termux真是相见恨晚。


定时SSH执行远程命令

回到正事,我要监控服务器,必须能跟服务器通信啊。我不想开个端口,比如HTTP比较容易,但增加一个端口就增加了风险,因此选择SSH来执行远程命令是坠吼的。我经常用的Serverauditor好是好,但是不能命令行运行啊,那不是坑爹吗。或者用CyanogenMod(2016/12/24 网站关闭卧槽!),更像Linux一点,直接内置ssh,但我还是想用原生android的。另外更重要的是要定时啊,类似cron的功能,这个得借助另一个神器Tasker完成。Tasker就强大了,有JuiceSSH的Tasker插件,tm的,太贵了。还可以用connectbot,然后让tasker发起intent,参考此处彼处。我觉得还是Termux靠谱,这时Termux:Widget就派上用场了,通过Tasker调用Secure Settings来执行Termux:Widget中的脚本。好像有点复杂,可以看看作者怎么说(关于发送短信到电脑)。整个Tasker流程如下,关键是执行Shell脚本那步,我是设定每60分钟执行一次,错误就发送通知,还播放雷姆声音提示哦!

tasker

还有很多tasker能做的事情,比如用雷姆声音提醒喝水,记录自己的轨迹(wifi信息),转发短信,自动回复微信等,非常帅!花点钱是值得的。如果你有一个女朋友,可以发送短信给她让她提醒你,用termux-api就能从命令行发送短信了,详见termux-api

 

 

最近高产似母猪啊,要把之前没更的全补回来。