如何用深度學習將前端設計模型自動轉換爲代碼?

做者 | Emil Wallner
譯者 | 易文英
編輯 | Emily
AI 前線導讀:在將來的 3 年內,深度學習將改變前端開發,一方面會加快建立原型的速度,另外一方面會下降軟件開發的難度。

從去年 Tony Beltramelli 發表 pix2code 論文和 Airbnb 推出 sketch2code 後,這一領域纔開始嶄露頭角。

更多幹貨內容請關注微信公衆號「AI 前線」,(ID:ai-front)

目前,自動化前端開發的最大障礙是計算能力。不過,咱們可使用當前的深度學習算法和人造的訓練數據來探索人工前端自動化。前端

在這篇文章中,咱們將教會一個神經網絡如何基於一張設計原型圖片來編寫基本的 HTML 和 CSS 代碼。如下是該過程的簡要概述:git

1)爲神經網絡提供的設計圖github

2)神經網絡將圖片轉化成 HTML 代碼算法

3)渲染輸出編程

咱們將經過三次迭代來構建神經網絡。bootstrap

第一次迭代獲得的是最基礎的版本,先了解圖樣中的活動部件。第二次迭代獲得的是 HTML 代碼,將着重於自動化全部步驟,並解釋神經網絡層。最後一次迭代獲得的是 bootstrap 版本,咱們將建立一個模型可用於泛化和探索 LSTM 層。後端

全部的代碼都放在了 Github 和 FloydHub 上。服務器

這些模型是基於 Beltramelli 的 pix2code 論文和 Jason Brownlee 的圖像天然語言描述教程而構建的,代碼使用 Python 和 Keras(一個基於 Tensorflow 的框架)編寫。微信

若是你是剛接觸深度學習的新手,建議你先大概瞭解下 Python,反向傳播和卷積神經網絡。網絡

核心邏輯

讓咱們再簡明扼要地複述下咱們的目標。咱們想構建一個神經網絡,生成與屏幕截圖對應的 HTML/CSS 代碼。

在訓練神經網絡時,你能夠給它幾個截圖和與之對應的 HTML 代碼。

在學習過程當中,它會逐一預測全部匹配的 HTML 標籤。在預測下一個標籤時,它會接收到屏幕截圖以及在那一個點上全部匹配的標籤。

這個 Google Sheet 包含了一個簡單的訓練數據樣本。

建立一個可以逐字預測的模型是如今最多見的方式,也是咱們在這個教程中將會使用的方式,雖然還有其餘的方式。

請注意,對於每次預測,神經網絡獲得的都是相同的截圖。也就是說,若是要預測 20 個單詞的話,它將會收到相同的圖樣 20 次。在如今這個階段,請不要擔憂神經網絡的工做原理,而是着重關注神經網絡的輸入輸出。

讓咱們看下以前的標籤。假設咱們要訓練網絡來預測「I can code」這句話。當它收到「I」的時候,它能預測到「can」。下一次,它將收到「I can」,而且預測到「code」。每次它會收到以前全部的單詞,而且只需預測接下來的一個單詞。

神經網絡從數據中建立出不一樣的特徵,用於鏈接輸入和輸出數據,建立模型,以便理解每張截圖中所包含的內容和 HTML 語法,這就獲得了預測下一個標籤所須要的知識。

在將訓練過的模型用在現實當中時,狀況跟訓練模型時差很少。每次使用相同的屏幕截圖逐一輩子成文本。不一樣的是,如今它不會直接收到正確的 HTML 標籤,而是會收到它迄今爲止已經生成的標籤,而後去預測下一個標籤。整個預測的過程會從「起始標籤」開始,在預測到「結束標籤」或達到最大限度時終止。

Hello World

讓咱們開始構建一個 Hello World 的版本。咱們將爲神經網絡提供一個顯示有「Hello World!」的網頁截圖,而且訓練它生成對應的標籤。

首先,神經網絡將圖樣映射成一組像素值列表。每一個像素點有 RGB 三個通道,每一個通道的值都在 0-255 之間。

爲了讓神經網絡理解這些標記,我使用了獨熱編碼(one hot encoding)。所以「I can code」這一句就能夠映射成:

上圖中包含了開始和結束標籤。這些標籤控制着神經網絡預測的開始和結束時間。

對於輸入數據,咱們將用不一樣的句子,從第一個單詞開始,而後逐步添加每一個單詞。輸出的數據老是一個單詞。

句子遵循與單詞相同的邏輯。它們也須要相同的輸入長度,可是在這裏咱們限制的是句子最大的長度,而不是單詞的數量。若是句子比最大長度短,則用空詞填充它,空詞徹底由零組成。

正如所看到的,單詞都是從右向左打印出來的。這樣的話,每次訓練都會迫使每一個單詞改變本身的位置,這樣模型就能夠記住單詞順序而不是每一個單詞的位置。

在下圖中有四次預測,每一行表示一次預測。從左邊起,是以 RGB 通道表示的圖像:紅色、綠色和藍色,還有以前提到過的單詞。括號以外,是一個接一個的預測,最後以紅色方塊結束。

在 Hello World 版本中,咱們用了三個記號:「start」、「Hello World!」和「end」。記號能夠是任何東西,它能夠是一個字符、單詞或句子。雖然使用字符記號須要更少的詞彙量,但會限制神經網絡。單詞記號每每有最好的表現。

這裏咱們作出了預測:

輸出

  • 10 epochs:start start start

  • 100 epochs: start <HTML><center><H1>Hello World!</H1></center></HTML> <HTML><center><H1>Hello World!</H1></center></HTML>

  • 300 epochs: start <HTML><center><H1>Hello World!</H1></center></HTML> end

    我掉過的坑:
    • 在收集數據以前構建了第一個版本。 在這個項目的早期,我想辦法從 Geocities 網站得到了一箇舊的存檔副本,其中包含 3800 萬多個網站。不過,當時我被數據衝昏了頭腦,卻忽視了縮減 100K 詞彙所須要的巨大工做量。

    • 處理 TB 級的數據須要很好的硬件或者極大的耐心。 在用個人 Mac 電腦運行出現了幾回問題之後,最後選擇了功能強大的遠程服務器。爲了保持工做的順暢,預計我將會租用包含 8 核 CPU 和一個 1GPS 網絡鏈接的遠程測試機組。

    • 在我明白輸入和輸出以前,不少東西都說不通。 輸入 X 是屏幕截圖和以前已經預測的標籤,輸出 Y 是下一個要預測標籤。當我明白這個之後,理解它們之間的關係就更容易了,並且構建不一樣的構架也更容易了。

    • 當心兔子洞陷阱。 由於這個項目跟深度學習的不少領域都有交叉,在研究的過程當中我好屢次都陷入對其餘領域的研究中。我花了一週的時間從頭開始編寫 RNN,過分着迷於向量空間,又被其餘的實現所迷惑。

    • 圖片到編碼網絡其實就是 Image Caption 模型。 但即便我已經意識到了這點,我仍然忽略了不少有關 Image Caption 的論文,只是由於以爲它們沒有那麼酷。當我發現到這點後,我加快了對問題的瞭解。

    在 Floydhub 平臺上運行代碼

    Floydhub 是一個深度學習訓練平臺。在我剛開始接觸深度學習時,才知道有這個平臺。從那之後,我都在用它來訓練和管理深度學習試驗。你能夠在 10 分鐘內安裝它而且運行你的第一個模型。這是在雲端 GPU 上訓練模型的最佳選擇。

    若是你是剛接觸 Floydhub,推薦你去看下他們的 2 分鐘安裝教程和個人 5 分鐘概覽教程。

    複製倉庫:


    登陸並啓動 FloydHub 命令行工具:


    在 FloydHub 的雲 GPU 機器上運行 Jupyter notebook:


    全部的 notebook 都在 FloydHub 目錄中準備好了。運行起來以後,你能夠在這裏找到第一個 notebook:floydhub/Helloworld/helloworld.ipynb。

    若是想要更多詳細的指導和標記說明,請參閱我早期寫的文章。

    HTML 版本

    在這個版本中,咱們將會自動化 Hello world 中的不少步驟。這一章節將主要關注如何建立一個可伸縮的實現和神經網絡中的動態部分。

    雖然這個版本還沒法基於隨機網站來預測 HTML,但它仍然很適合用於對問題的動態部分進行探索。


    概覽

    下圖所示的是構架組件展開後的樣子。

    主要有兩個部分,編碼器和解碼器。編碼器用於建立圖像特徵和標籤特徵。特徵是由網絡建立用來鏈接圖樣和標籤的基本構建塊。在編碼的最後階段,咱們將圖像特徵和前一個標籤中的單詞關聯起來。

    而後解碼器經過圖樣和標籤特徵的組合來建立下一個標籤特徵,而這個特徵則會經過全鏈接神經網絡來預測下一個標籤。

    圖樣的特徵

    由於咱們須要爲每個單詞插入一個截圖,這就成了咱們訓練網絡時的一個瓶頸(例子)。所以,咱們沒有直接使用圖片,而是將生成標籤所須要的信息提取出來。

    以後,咱們用一個預先在 ImageNet 上預先訓練的卷積神經網絡,將這些提取出來的信息編碼到圖片特徵中。

    在最終分類以前,咱們將特徵從層中提取出來。


    最終,咱們獲得了 1536 張 8×8 像素的圖像做爲特徵圖。儘管這些特徵很難被人理解,可是神經網絡能夠從這些特徵中抽取出對象和元素的位置。

    標籤特徵

    在 Hello World 的版本中,咱們使用了獨熱編碼來表明標籤。而在這個版本中,咱們將在輸入中使用詞向量(word embedding),並繼續使用獨熱編碼表示輸出。

    在保持每一個句子的構造方式不變的狀況下,改變映射記號的方法。獨熱編碼將每一個單詞視爲一個獨立的單元。但在這裏,咱們將輸入數據中的每一個單詞轉換爲數值列表。這些數值表明了不一樣標籤之間的關係。


    詞向量的維度是 8,但受詞彙量大小的影響,維度常常會在 50 到 500 之間變化。

    每一個單詞的 8 個數字相似於通常神經網絡中的權重,用於映射不一樣單詞之間的關係。

    神經網絡能夠用這些特徵來鏈接輸入數據與輸出數據。如今,先不要關心它們是什麼,咱們將在下一節深刻探討這個問題。

    編碼器

    咱們把詞向量送到 LSTM 中運行,以後會返回一系列的標籤特徵。這些標籤特徵而後會被送到 TimeDistributed 密集層運行。

    在處理詞向量的同時,還會進行另外一個處理。圖像特徵首先會被扁平化,全部的數值會被轉換成一個數字列表。而後咱們在這個層上應用一個密集層來抽取高級特徵,隨後這些圖像特徵會被鏈接到標籤特徵。

    這可能有點難以理解,因此讓咱們把處理的過程拆開來看。

    標籤特徵

    咱們先將詞向量送到 LSTM 層中運行。以下圖所示,全部的句子都會被填充到三個記號的最大長度。


    爲了混合信號並找到更高級別的模式,咱們會用 TimeDistributed 密集層應用在標籤特徵上。TimeDistributed 密集層與通常的密集層相同,只不過具備多個輸入和輸出。

    圖像特徵

    與此同時,咱們會準備圖像。咱們整理了全部迷你圖像特徵,而後將它們轉換成一組列表。其中的信息沒有變,只是組織方式變了。


    跟以前提過的同樣,爲了混合信號和提取更高級的概念,咱們應用了一個密集層。 並且因爲咱們只須要處理一個輸入值,因此咱們能夠用一個常規密集層。其後,爲了將圖像特徵鏈接到標籤特徵,咱們複製了圖像特徵。

    在這種狀況下,咱們就有三個標籤特徵。所以,咱們獲得了相同數量的圖像特徵和標籤特徵。

    鏈接圖像特徵和標籤特徵

    全部的句子都通過填充,以便建立三個標籤特徵。因爲咱們已經預處理過了圖像特徵,如今咱們能夠爲每一個標籤特徵添加一個圖像特徵。


    在將每一個圖像特徵添加到對應的標籤特徵以後,咱們最終獲得了三組圖像標籤特徵組合。以後,咱們將它們做爲解碼器的輸入。

    解碼器

    這裏,咱們使用圖像標籤特徵組合來預測下一個標籤。


    在下面的例子中,咱們使用三個圖像標籤特徵組合來輸出下一個標籤特徵。

    請注意,這裏 LSTM 層的 sequence 被設置爲 false。由此,LSTM 層返回的是一個預測的特徵,而不是輸入序列的長度。在咱們的例子中,這將是下一個標籤的特徵,包含了最終預測所需的信息。


    最終的預測

    密集層像傳統前饋神經網絡那樣,將下一個標籤特徵中的 512 個值與 4 個最終預測鏈接起來。假設咱們的詞彙表中有四個詞:start、hello、world 和 end。

    詞彙預測能夠是 [0.1,0.1,0.1,0.7]。密集層中的 softmax 激活函數分佈機率是 0 到 1,全部預測的總和等於 1。在這種狀況下,它預測第 4 個單詞會是下一個標籤。 而後,將獨熱編碼 [0,0,0,1] 轉換爲映射值,好比「end」。


    輸出


    這裏有原始網站供參考。

    我掉過的坑:

    對我來講,LSTM 比 CNN 更難理解。當我展開全部的 LSTM 後,它們變得更容易理解。Fast.ai 在 RNN 上的視頻很是有用。另外,在嘗試瞭解特徵的原理以前,請先關注輸入特徵和輸出特徵自己。從頭開始構建詞彙表比縮減巨大的詞彙表要容易的多。包括字體、div 標籤大小、hex 顏色值、變量名稱和普通的單詞。大多數庫被建立來解析文本文件而不是代碼。在文檔中,全部內容都由空格分隔,但在代碼中,則須要使用自定義的解析方式。可使用在 ImageNet 上訓練的模型來提取特徵。這可能看起來違反直覺,由於 ImageNet 幾乎沒有 Web 圖像。然而,與從頭開始訓練的 pix2code 模型相比,這樣作的損失要高出 30%。固然,我也對使用基於網頁截圖的預訓練的 inception-resnet 類型的模型很感興趣。

    Bootstrap 版本

    在咱們的最終版本中,咱們將使用 pix2code 論文中生成的 Bootstrap 網站的一個數據集。經過使用 Twitter 的 Bootstrap,咱們能夠將 HTML 和 CSS 相結合,而且縮減詞彙表的大小。

    咱們將確保它可以爲以前沒有看過的截圖生成標籤,還將深刻研究它是如何創建對屏幕截圖和標籤的認知的。

    咱們將使用 17 個簡化過的記號,而後將這些記號轉成 HTML 和 CSS,而不是在 Bootstrap 標籤上進行訓練。這個數據集包括 1500 個測試截圖和 250 幅驗證圖像。每一個截圖平均有 65 個記號,總共將生成 96925 個訓練樣本。

    經過對 pix2code 論文中的模型作了一些調整,該模型能夠以 97%的準確度預測網頁組件(BLEU 4-ngram 貪心搜索,稍後會介紹更多)。


    一種端到端的方法

    在 Image Caption 模型中,從預訓練好的模型中提取特徵的效果很好。但通過幾回實驗後,我發現 pix2code 的端到端方法的效果更好。預訓練的模型還沒有用網頁數據訓練過,只是用在分類上。

    在這個模型中,咱們用輕量級的卷積神經網絡替換了預訓練好的圖像特徵。可是咱們沒有使用 max-pooling 來增長信息密度,而是增長了步幅,用以維護元素的位置和顏色。


    這裏可使用卷積神經網絡(CNN)和遞歸神經網絡(RNN)這兩種核心模型。最多見的 RNN 是長短時間記憶(LSTM)網絡,也是我將要講的。

    我在以前的文章中已經介紹過不少很棒的 CNN 教程了,因此這裏我就只重點介紹下 LSTM。

    理解 LSTM 中的時間步

    LSTM 的難點之一是時間步的概念。原始神經網絡能夠被認爲有兩個時間步。若是你給它「hello」,它會預測到「world」。可是,想要預測更多的時間步是很困難的。在下面的例子中,輸入四個時間步,每一個單詞對應一個。

    LSTM 適用於含有時間步的輸入,是一個適合有序信息的神經網絡。若是你展開咱們的模型,就會看到像下圖所示的那樣。對於每一個向下遞推的步驟,你須要保持一樣的權重。對於舊的輸出和新的輸出,你能夠分別設置一套權重。


    將加權後的輸入和輸出用激活函數鏈接在一塊兒,它就是對應時間步的輸出。因爲咱們重複使用這些權重,它們將從一些輸入中提取信息,並創建起有關序列的知識。

    如下是 LSTM 中每一個時間步的簡化版本。


    爲了理解這個邏輯,我建議你參考 Andrew Trask 的精彩教程,本身從頭開始構建一個 RNN。

    理解 LSTM 層中的不一樣單元

    每一個 LSTM 層的單元(unit)數量決定了它的記憶能力,以及每一個輸出特徵的大小。須要再次指出的是,一個特徵是用於在層與層之間傳輸信息的一長串數字。

    LSTM 層中的每一個單元會學習跟蹤語法的不一樣方面。下面是對一個單位跟蹤原始 div 信息的可視化結果,是咱們用來訓練 Bootstrap 模型的簡化標籤。


    每一個 LSTM 單元會維護一個細胞狀態(cell state)。把細胞狀態想象成記憶,而權重和激活函數用來以不一樣的方式修改狀態。這使得 LSTM 層可以微調每一個輸入要保留和丟棄哪些信息。

    除了每一個輸入傳遞輸出特徵以外,LSTM 層還會傳遞細胞狀態,其中每一個單元都分別對應一個值。爲了理解 LSTM 中的組件是如何相互做用的,我推薦 Colah 的教程、Jayasiri 的 Numpy 實現以及 Karphay 的講座和文章。


    測試準確性

    找到一個公平的方法來衡量準確性很是困難。假設你選擇逐字比較,那麼若是你的預測中有一個字不一樣步,那麼你的準確性就可能會是零。若是你刪掉一個符合預測的單詞,最後的準確性也多是 99%。

    我用的是 BLEU 測評法,這是一種用於機器翻譯和圖像字幕模型的最佳實踐。它按照 1 到 4 個單詞序列把句子分紅四個 gram。在下面的預測中的「cat」應該是「code」。


    爲了拿到最終的分數,你須要將獲得的數字都乘以 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。求和的結果再乘以句子長度的處罰值。由於咱們例子中的句子長度是正確的,因此求和的結果直接就是最終的結果。

    你能夠經過增長 gram 的數量讓它變得更難。四個 gram 的模型是最符合人類翻譯的模型。我建議使用下面的代碼運行幾個例子並閱讀 Wiki 頁,來加深對這方面的瞭解。


    輸出


    一些輸出樣本的連接:

    • 生成網站 1——original 1

    https://emilwallner.github.io/bootstrap/pred_1/

    • 生成網站 2——original 2

    https://emilwallner.github.io/bootstrap/real_2/

    • 生成網站 3——original 3

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

    生成網站 4——original 4

    • https://emilwallner.github.io/bootstrap/pred_4/

    生成網站 5——original 5

    • https://emilwallner.github.io/bootstrap/pred_5/

    我掉過的坑:
    • 理解不一樣模型的弱點,而不是測試隨機模型。開始的時候,我使用了相似批次標準化和雙向網絡這類隨機模型,並嘗試實現注意力機制。而後看了測試數據,才發現這樣沒法準確預測顏色和位置,我意識到 CNN 有一個弱點。這就致使我採用更大的步幅來取代 maxpooling。以後驗證損失就從 0.12 變爲 0.02,而 BLEU 得分從 85%提升到了 97%。

    • 若是它們相關的話,只使用預先訓練好的模型。鑑於給定的數據集很小,我認爲通過預訓練的圖像模型會提升性能。從個人實驗來看,端到端的模型訓練起來比較慢,須要更多的內存,可是精度要高出 30%。

    • 在遠程服務器上運行模型時,你的計劃須要有所調整。在個人 Mac 上,它會按字母順序來讀取文件。可是在遠程服務器上,它是隨機定位的。這就形成了截圖和代碼之間的不匹配。雖然它仍然收斂,但驗證數據比我修正以後的要差 50%。

    • 確保你理解庫函數。包括詞彙表中空記號的填充空格。當我沒有添加填充空格時,預測中沒有包括任何一個空記號。這也是我看了好幾遍輸出結果以後才注意到的,並且模型歷來沒有預測到一個單記號。通過快速的檢查,我發現到這甚至不在詞彙表中。另外,詞彙表要以相同的順序進行訓練和測試。

    • 試驗時使用更輕量級的模型。使用 GRU 而不是 LSTM 會將每一個 epoch 週期減小 30%,而且對性能沒有太大的影響。

    下一步

    前端開發是應用深度學習的理想領域。由於生成數據很容易,而且目前的深度學習算法能夠映射絕大部分的邏輯。

    其中最使人興奮的領域之一是注意力機制在 LSTM 上的應用。這不只會提升準確性,並且還能使咱們可以直觀地看到 CNN 在產生標籤時將焦點放在了哪裏。

    注意力機制也是標籤、樣式表、腳本和後端之間溝通的關鍵。注意力層能夠跟蹤變量,確保神經網絡可以在編程語言之間進行通訊。

    但在不久的未來,最大的問題在於如何找到一種可伸縮的方式來生成數據,這樣就能夠逐步加入字體、顏色、文字和動畫。

    到目前爲止,大部分的進步都是發生在將草圖轉化爲模板應用程序的過程當中。在不到兩年的時間裏,咱們將能夠在紙上畫一個應用程序,並在不到一秒的時間內就能夠得到相應的前端代碼。Airbnb 的設計團隊和 Uizard 已經構建了兩個可用的原型。

    一些實驗
    開始
    • 運行全部的模型

    • 嘗試不一樣的超參數

    • 測試一個不一樣的 CNN 構架

    • 添加雙向 LSTM 模型

    • 用不一樣的數據集來實現模型

    進一步的試驗
    • 使用相應的語法建立一個可靠的隨機應用程序或網頁生成器。

    • 從草圖到應用模型的數據。將應用程序或網頁截圖自動轉換爲草圖,並使用 GAN 建立不一樣類型的草圖。

    • 應用一個注意力層,可視化每一個預測在圖像上的焦點,相似於這個模型。

    • 爲模塊化方法建立一個框架。好比,有字體的多個編碼器模型,其中一個用於顏色,另外一個用於排版,以後將這些編碼器整合到一個解碼器中。得到穩定的固體圖像特徵是一個好兆頭。

    • 爲神經網絡提供簡單的 HTML 組件,而且教它使用 CSS 生成動畫。

    原文連接:

    https://blog.floydhub.com/turning-design-mockups-into-code-with-deep-learning/

    更多幹貨內容請關注微信公衆號「AI 前線」,(ID:ai-front)

    相關文章
    相關標籤/搜索