如何用深度学习做“前端”:基于设计模型图片生成HTML和CSS代码(下)

作者:Emil Wallner

编译:Bot

Bootstrap版

这一版我用了pix2code论文提供的Bootstrap web数据集。Bootstrap是twitter推出的基于HTML、CSS、JavaScript的一个热门前端框架,根据官网导引显示,我们可以用它把HTML和CSS代码结合起来,同时缩小词库。

我们这次的目标是让神经网络为之前没见过的网页截图生成标签,因此我会深入介绍如何构建标签和图像的连接。

不同于直接在bootstrap标签上训练,这里我们使用的方法是设置17个经简化的token,然后把它们转成HTML、CSS代码。pix2code数据集包含1500个测试截图和250个验证截图,每个截图平均有65个token,所以我们共有96925个训练样本。

把论文模型做进一步微调后,它的预测准确率提高到了97%(BLEU 4-ngram贪婪搜索,后文有介绍)。

一种端到端的方法

之前,我们在代码中曾提到过用一个预训练的VGG16模型从图像中提取特征,它在图像描述生成模型上跑得不错,但经过几次测试后,我发现pix2code的端到端方法可能会更好用一些。因为预训练的模型并没有在web截图上训练过,而且它的主要用处是分类。

所以在这个版本中,我们用一个轻量级CNN代替预训练图像特征步骤,同时不用最大化池层增加信息密度,而是增加步长来保持前端设计元素的位置和颜色。

要实现上图流程,我们要用到两种核心模型:CNN和RNN。关于CNN的具体内容,之前我已经在“如何着色”一文中有过详细介绍,此处不再详谈。而对于RNN,当前它最流行的一种形式就是LSTM,这也是我在下文中将介绍的重点。

LSTM中的时间步长

LSTM本身不难理解,如果说有什么难点,那么时间步长应该是其中之一。一般来说,我们认为单隐层神经网络共有2个时间步长,输入“Hello”,它输出预测“World”。如果一个网络有多个步长,那它的预测难度会增加。如下图所示,它的输入要经过4个时间步长,每一步生成一个单词。

LSTM就是这样一个允许输入带上时间步长的RNN,也就是说,它会按顺序提取特征信息。下图是我们模型的展开图,可以发现它的权值始终保持不变。LSTM的权值是共享、复用的,你对之前的输出用了这个权值,那么下一个新输入也会继续用这个数字。

加权的输入和输出进入LSTM后,经激活函数组合、过滤,最后成为该时间步长的输出。因为权值被重复使用了,所以它们能从多个输入中提取信息,并以此建立知识序列。

以下是LSTM每个时间步长的简要图示:

为了感受其中的逻辑,我在此建议有需要的读者跟着Andrew Trask的RNN教程试一试,自己构建一个神经网络。

LSTM层中的单元

此外,LSTM的每个单元都有一个被称为单元状态(cell state)的东西,如果把单元想象成神经细胞,那么单元状态就是储存其中的记忆。我们通过权值和激活函数以不同方式改变单元状态,让LSTM层“理解”什么信息是该保留的、什么是该丢弃的。

因此,除了根据输入预测输出,每一个单元的状态也会随时间步长发生改变。如果你想更详细地了解其中的作用机制,我推荐Colah的教程、Jayasiri的Numpy实现以及Karphay的讲座和文章。

测试模型准确率

训练完模型后,我们要找一个合适的方法测试它的准确率,但这其实不太容易。如果我们逐词对比,那么即便只有1个词不合语法,模型的准确率都可能会变成0%;如果模型每预测对一个词我们就把它去掉,那最后的结果可能是99/100。

我在这里引入了一种机器翻译自动评估算法——BLEU。BLEU是IBM于2002年提出的代替人工评分的工具,它能衡量机器翻译、图像字幕和参考文之间的差距,BLEU评分越高,模型性能越好。它的评分方式是比较输入文和参考文中共现的词的个数,以之前的“I can code”为例,它把这个句子分解成4元语法(4 n-gram),如下图所示,“cat”应该是“code”:

现在我们计算它的BLEU评分,已知n-gram概率之和为1,我们先给每个准确率都乘上0.25:(4/5)×0.25 + (2/4)×0.25 + (1/3)×0.25 + (0/2)×0.25 = 0.2 + 0.125 + 0.083 + 0 = 0.408。理论上这个和要经过正则化才是正确的BLEU评分,但因为示例句中没有重复单词,且句长为3,用0.25没问题,所以0.408就是最终值。

你也可以把它分解成更多的元,但在这个例子中,4元语法模型是最贴近人类翻译的模型。你可以用下面这段代码多试几个句子,掌握其中的原理:

输出

上图网站的链接:

Generated website 1 - Original 1

(https://emilwallner.github.io/bootstrap/real_1/)

Generated website 2 - Original 2

(https://emilwallner.github.io/bootstrap/pred_2/)

Generated website 3 - Original 3

(https://emilwallner.github.io/bootstrap/pred_3/)

Generated website 4 - Original 4

(https://emilwallner.github.io/bootstrap/pred_4/)

Generated website 5 - Original 5

(https://emilwallner.github.io/bootstrap/pred_5/)

我得到的经验

了解模型的弱点,而不要测试随机模型。一开始我用了很随机的东西,比如批标准化(batch normalization)、双向网络(bidirectional networks),甚至尝试了注意力机制。但测试结果非常消极,模型预测的颜色和位置都不太准确。后来我意识到这是CNN有缺陷,所以把最大池化层换成了增加步长,之后模型的验证loss一下从0.12降到了0.02,准确率也从85%提高到了97%;

只有在相关的情况下才使用预先训练好的模型。因为数据集比较小,所以我觉得事先训练一个提取图像特征的模型可以提升整体性能。但从我的实验结果来看,端到端的模型虽然训练速度慢,占用内存高,但是精度会比预训练的高30%;

在远程主机上运行模型时,可能会出现意外。我之前用Mac做这个项目时,模型是按字母顺序读取文件的。但把它搬到远程主机上后,它开始随机读取文件了,截图和代码不匹配,虽然最后模型还是收敛的,但它的验证loss比修正后的值差了50%;

确保自己已经熟练掌握库的函数。词库里如果出现空白字符,规则要求是要打空格的,但是我忘了,它就没有token,也始终没能预测到“单一”的标签;

尽量用轻量级神经网络。用GRU代替LSTM可以减少30%的遍历周期,而且还不影响性能。

原文地址:blog.floydhub.com/Turning-design-mockups-into-code-with-deep-learning/

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180124G0R1MU00?refer=cp_1026

同媒体快讯

相关快讯

扫码关注云+社区