投稿/爆料
厂商入驻

【原创】循环神经网络生成矢量格式“新造”汉字

技术干货|论智|2017-11-09 18:30

前天我们介绍了RNN(循环神经网络)和LSTM(长短期记忆网络)的基本原理,今天我们来看一个实际的例子,基于TensorFlow框架,使用LSTM生成“新造”汉字。

fake-chinese-chars

使用LSTM生成笔迹,有Alex Graves的经典论文《Generating Sequences With Recurrent Neural Networks》

otoro工作室在Graves的基础上,基于TensorFlow框架,使用LSTM和MDN(混合密度神经网络),生成矢量格式的“新造”汉字。

动机

作为一个在英语国家长大的小孩,otoro工作室的创始人hardmaru小时候被父母逼着去上教汉语的周六课程,幼小的心灵受到了深深的伤害。直到成年后还会做噩梦,梦到默写测试的场景。

就hardmaru的个人经验而言,写汉字和读汉字很不一样。曾经习惯手写汉字的人,越来越多地使用基于语音的输入法(如日文的片假名输入法和中文的拼音输入法),然后通过选择屏幕上的候选字进行输入。当人们坐下来写张贺卡的时候,就容易出现提笔忘字的情况。人们可以阅读和辨识会写的字,反之则不然。

机器学习某种程度上与此类似。许多问题可以划分到归类问题。这是一个数字吗?这张图上的是一条狗,还是一座房子?这次交易是否存在欺诈?我们应该借钱给这个申请抵押贷款的人吗?这是男性,还是女性?这个人的年纪?

这些任务非常有用。但是hardmaru认为,更有趣的任务是生成数据,在hardmaru看来,生成数据是归类数据的扩展。相比能够阅读某个汉字,能够书写某个汉字表明我们对这个汉字有更多的了解。同理,生成内容也是理解内容的关键。比起单纯预测某位女士大概有22岁,能够生成一个22岁的妙龄女子的图像,要让人印象深刻得多。

生成艺术最近很流行。最近有项目使用生成对抗网络(GAN)之类的技术伪造以假乱真的位图,比如喵星人、人面、卧室、二次元角色。而hardmaru更感兴趣的是,生成矢量内容。其实更多内容更适合以矢量的形式表达,而不是栅格化的位图。例如,数字化的素描、CAD设计、基于地理位置的标签信息、科学实验数据。当然,笔迹也更适合以矢量的形式表达。

stroke-order

比起位图,字体和笔迹更适合用矢量表示。精心设计的TrueType字体,不管大小,显示出来都很美观。

下面我们将介绍hardmaru如何使用循环神经网络生成“新造”的汉字。汉字以矢量保存(SVG格式)。用于训练的数据是真实的汉字,并且包含笔顺数据。因此,神经网络生成的汉字也会有看起来很合理的笔顺。

背景介绍

hardmaru的模型使用和Graves的论文相似的框架。

state_diagram

在文本生成这个例子中,假设我们已经有一个训练好的模型,我们传入一个初始的随机字符以及一个初始的空状态,模型会使用当前的输入以及状态信息来生成下一个字符的概率分布。随机取样该分布,获取下一个字符的预测信息。取样的字符和当前的内部状态一起作为下一个输入。

符合这个框架的一个简单模型是N-GRAM字符建模方法。我们保留前N个字符的频率记录,将历史频率表作为概率分布,从而生成下一个字符。

循环神经网络也可以表示这个模型。状态为循环LSTM节点的隐藏状态,网络的输出值可以通过应用一个softmax层转化为离散概率分布。为了训练神经网络的权重,我们需要找到比较预测分布和训练数据的实际分布的方法。通常,我们使用的是cross-entropy损失函数。

Karpathy的char-rnn项目实现了Graves的论文中提到的上述网络。char-rnn不仅可以用来生成莎士比亚的剧本,还可以用来生成一些奇怪的文本,包括Linux源代码,LaTex文档,维基百科的xml文档,以及音乐评分。

sketch-rnn

hardmaru本来想实现一个生成喵星人素描的RNN,但是发现很难获得大量的喵星人素描的SVG图片。相反,汉字的SVG文件很容易获得,因此最终hardmaru实现的是一个生成“新造”汉字的网络sketch-rnn

sketch-rnn将每一笔建模为类似笔划的数据,每一步包含横、纵方向的位移,以及笔是否落在纸上,如果笔落在纸上,还包含当前步骤和前一步骤的连线。神经网络会输出下一步的概率分布。对于字符生成而言,每一个可能的字符有一个离散的概率。而sketch-rnn则需要用连续的概率分布统计横、纵方向的位移,以及在下一步笔会提起的可能性(笔划完结概率)。sketch-rnn使用混合高斯分布来估算下一笔的位移。这个用来生成虚假的笔迹的方法叫做混合密度网络(MDN)。

混合2维高斯密度

上面是一个使用混合高斯密度描绘汉字笔划的例子。连接起来的黑点代表笔划,LSTM和MDN算法将不断估算下一个点的位置的混合高斯概率分布。这意味着下一个位置取决于许多不同位置的混合(用不同浓度的红色椭圆表示)。每一个位置本身是一个横纵偏移的2维联合高斯分布,每个偏移则是一个2x2的协方差矩阵。

除了笔划位置的概率分布和笔划完结概率以外,还需要建模写完汉字的概率(字符完结概率,或内容完结概率,eoc概率)。刚开始,hardmaru增加了一个和笔划完结概率类似的变量,但是发现效果不佳。这是因为每个字符完结事件,同时也是一个笔划完结事件,因此其中有一些共享信息被忽略了。

hardmaru花了不少功夫找到了建模上述两个信号(笔划完结概率、字符完结概率)的更好方法,通过神经网络中的softmax层将笔的状态建模为一组离散的状态。笔的状态分为三种:笔划完结,字符完结,落笔。模型会计算每一步三种状态的概率。

处理训练数据

hardmaru使用KanjiVG数据库的数据,该数据库源于开源日语学习工具Tagaini Jisho。KanjiVG包含大约11000汉字的SVG文件,每个SVG文件的路径元素遵循日文汉字的官方笔顺。

sketch-rnnSketchLoader类会读取数据子目录内的所有SVG文件,并将线条和路径元素转化为更小的线条,这些更小的线条更适合训练数据。关于粒度和路径到线条转换的具体细节,请参考代码。

下面是一些训练数据的例子:

汉字训练数据

SketchLoader对象会将从SVG文件中抽取的线条转存为一个由笔划数组构成的数组,并保存为cPickle二进制文件供以后训练使用。同时也会生成minibatch集合供日后训练使用。

梯度提升

初始结果有点让人失望。尽管生成的单笔看上去很真实,但笔会一直“写”下去而不会移动到下一个字符上。在处理log类损失函数的最小化的时候,算法基本上低估了,甚至忽视了字符完结的概率。这可能是因为字符完结事件不常发生,大约100步才发生1次。

Graves的笔迹生成没有出现这个问题。因为英语笔迹训练数据不需要建模完结训练信号,可以让计算机一直“写”下去。但是,生成汉字需要训练算法何时停止书写,以形成完整的汉字。

rambling

一个不知道何时停止的例子

hardmaru设计了一种增加错误的方法,相应地,字符完结信号产生时数据点的梯度也提升了。损失函数也据此修改,以包含这些增加的权重。

生成式模型:

生成式模型1

生成式模型2

生成式模型3

其中,x、y、m表示下一步的横、纵偏移量及笔的状态的随机值。x、y建模为MDN输出的混合2维高斯分布,m建模为softmax的one-hot输出zm。pstay、peos、peoc分别表示落笔、笔划完结、字符完结三个状态。

梯度提升后每一步的损失函数为:

损失函数

损失函数_

w(m)为数据中不太可能发生的事件提升损失函数。

hardmaru为笔划完结选择了10倍权重,为字符完结选择了100倍权重,以补偿这些事件的低概率。hardmaru发现这个方法非常有效,结合下一节提到的取样多样化和乱序技巧,最终结果获得了显著提升。

多样化样本

每次开始训练时,hardmaru对训练数据中的字符进行了乱序处理。笔顺数据库将字符按照相似性分组,而hardmaru希望每一批字符能更有代表性。换句话说,hardmaru希望增加每个mini batch的多样性。否则的话,算法会长时间学习鱼类汉字(魚、鯛、鮪),对世界的感知会因梯度而扭曲,认为所有的东西都是鱼,当学到“鳥”字的时候就会抓狂了。

笔顺数据集的一个局限是只有大约一万个汉字的样本,hardmaru觉得需要制造一些人工的数据用于训练。每个batch随机拉伸到原始大小的+/- 30%。数据的结构(所有东西都是空间的偏移量)使得这个拉伸很容易实施,只需将整个矩阵乘上一个系数。这个扭曲是联机进行的,而没有提前计算额外的样本并储存它们。epoch计数也随之增加。

最后,每个minibatch开始于一个汉字,而不是一个汉字当中,因为hardmaru希望算法能够学习整个结构,而不是从基本模式(口、山、木之类)开始训练。因此下一个batch会直接跳到下一个字符样本的开始。因为跳跃的关系,每个epoch的minibatch数不是完全相同,但都非常接近。

微调

如上所述,实验刚开始很让人沮丧,得到的结果是垃圾,算法不断地“写”啊“写”,像一个疯狂的疯子一样编织了一张由线条组成的大网。花了一些时间才想到使用softmax建模笔划完结和字符完结,摄入了很多咖啡因才想到梯度提升这个主意。

使用包括梯度提升不太可能发生的事件,以及多样化训练样本等技巧后,结果的质量改进了。但是,有时还是会产生一些很糟的结果。hardmaru实现了一个最终过滤算法,丢弃了超出书写区域大小的结果,让它们重新开始,直到结果位于指定区域内。

代码仓库

github.com/hardmaru/sketch-rnn 包含了一个较小的预先训练好的网络,你可以在自己的机器上通过python sample.py运行sketch-rnn

输出样例

样例输出

最终结果还不错。sketch-rnn能够生成一些不存在的汉字,但是这些字的书写方式和真实存在的汉字差不多。很多汉字的偏旁和构件的位置和组合方式符合汉字的间架结构。sketch-rnn就像一个绝望的小孩,妄图通过胡编乱造答案来通过汉字默写测试。

一些有趣的输出

伪造的会意字

有些生成的字可以看成“会意字”。

以后的工作

hardmaru了解过CASIA提供的在线手写数据库。将类似的算法应用到这个数据库上可能可以训练出生成“新造”草书的循环网络。由于草书的连笔和英文笔迹类似,而hardmaru对生成字字分明的汉字更感兴趣,因此没有采用这个数据库。

而且,作为一个设计师,hardmaru不喜欢1956年以来推行的简化汉字。hardmaru觉得中华人民共和国将汉字简化过头了,有点奥威尔新语的味道。

sketch-rnn应用到TU Berlin素描数据应该很有趣。hardmaru感觉效果可能不会很好,因为素描是多种多样的,在统计学上并不具有相似结构。如果我们有一万个房屋素描的样本,笔触数目、复杂度、维度都差不多,那结果可能不错。但是如果我们的数据库里是桌子、兔子、鱼、苹果和建筑物,那模型可能就应付不了了。另外,使用现有的算法将位图转化为SVG格式后再运用sketch-rnn也是一个有趣的主意。

TU Berlin素描数据中的大象

TU Berlin素描数据中的大象

LSTM+MDN基本上是LSTM+Softmax的扩展,hardmaru以后想尝试更强大的方法。变分自编码器生成式矩匹配网络和被夸大了效果的贝叶斯程序学习可能更强大、更富表达力。GAN(生成对抗网络)方法也许能应用到循环网络上,不过估计训练LSTM GAN会非常困难。

hardmaru也考虑过使用更小的网络获得更具生成力的效果。hardmaru希望这些训练过的网络以后能在浏览器里运行,让客户端的JS运行生成Demo,并和用户的手写活动实时交互。这太酷了,不是么?

原文 Recurrent Net Dreams Up Fake Chinese Characters in Vector Format with TensorFlow
本文由原作者hardmaru授权论智编译,未经授权禁止转载。详情见转载须知

本文来自机器人之家,如若转载,请注明出处:https://www.jqr.com/news/008561
爆料投稿,欢迎投递至邮箱:service@jqr.com
机器学习人工智能深度学习 MDN
推荐阅读

最新评论(0

暂无回帖,快来抢沙发吧

评论

游客
robot
发布需求
联系客服联系客服
robot
联系客服