整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          20個編寫現代 CSS 代碼的建議

          20個編寫現代 CSS 代碼的建議

          白何謂Margin Collapse

          不同于其他很多屬性,盒模型中垂直方向上的Margin會在相遇時發生崩塌,也就是說當某個元素的底部Margin與另一個元素的頂部Margin相鄰時,只有二者中的較大值會被保留下來,可以從下面這個簡單的例子來學習:

          .square { width: 80px; height: 80px;
          }.red { background-color: #F44336; margin-bottom: 40px;
          }.blue { background-color: #2196F3; margin-top: 30px;
          }

          在上述例子中我們會發現,紅色和藍色方塊的外邊距并沒有相加得到70px,而是只有紅色的下外邊距保留了下來。我們可以使用一些方法來避免這種行為,不過建議來說還是盡量統一使用margin-bottom屬性,這樣就顯得和諧多了。

          使用Flexbox進行布局

          在傳統的布局中我們習慣使用Floats或者inline-blocks,不過它們更適合于格式化文檔,而不是整個網站。而Flexbox則是專門的用于進行布局的工具。Flexbox模型允許開發者使用很多便捷可擴展的屬性來進行布局,估計你一旦用上就舍不得了:

          .container { display: flex; /* Don't forget to add prefixes for Safari */display: -webkit-flex;
          }

          我們已經在Tutorialzine上提供了很多的關于Flexbox的介紹與小技巧,譬如5 Flexbox Techniques You Need to Know About。

          使用CSS Reset

          雖然這些年來隨著瀏覽器的迅速發展與規范的統一,瀏覽器特性碎片化的情況有所改善,但是在不同的瀏覽器之間仍然存在著很多的行為差異。而解決這種問題的最好的辦法就是使用某個CSS Reset來為所有的元素設置統一的樣式,保證你能在相對統一干凈的樣式表的基礎上開始工作。目前流行的Reset庫有 normalize.css, minireset以及 ress ,它們都可以修正很多已知的瀏覽器之間的差異性。而如果你不打算用某個外在的庫,那么建議可以使用如下的基本規則:

          * { margin: 0; padding: 0; box-sizing: border-box;
          }

          上面的規則看起來沒啥用,不過如果不同的瀏覽器在默認情況下為你設置了不同的外邊距/內邊距的默認值,還是會挺麻煩的。

          一切應為Border-box

          雖然很多初學者并不了解box-sizing這個屬性,但是它確實相當的重要。而最好的理解它的方式就是看看它的兩種取值:

          • 默認值為content-box,即當我們設置某個元素的heght/width屬性時,僅僅會作用于其內容尺寸。而所有的內邊距與邊都是在其之上的累加,譬如某個<div>標簽設置為寬100,內邊距為10,那么最終元素會占用120(100 + 2*10)的像素。

          • border-box:內邊距與邊是包含在了width/height之內,譬如設置了width:100px<div>無論其內邊距或者邊長設置為多少,其占有的大小都是100px。

          將元素設置為border-box會很方便你進行樣式布局,這樣的話你就可以在父元素設置高寬限制而不擔心子元素的內邊距或者邊打破了這種限制。

          以背景圖方式使用Images

          如果需要在響應式的環境下展示圖片,有個簡單的小技巧就是使用該圖片作為某個<div>的背景圖而不是直接使用img標簽。基于這種方式配合上background-sizebackground-position這兩個屬性,可以很方便地按比例縮放:

          img { width: 300px; height: 200px;
          }div { width: 300px; height: 200px; background: url('http://cdn.tutorialzine.com/wp-content/uploads/2016/08/bicycle.jpg'); background-position: center center; background-size: cover;
          }section{ float: left; margin: 15px;
          }

          不過這種方式也是存在缺陷的,譬如你無法設置圖片的懶加載、圖片無法被搜索引擎或者其他類似的工具抓取到,有個不錯的屬性叫object-fit可以解決這個問題,不過該屬性目前的瀏覽器支持并不是很完善。

          Better Table Borders

          HTML中使用Tables進行布局一直是個很頭疼的問題,它們使用起來很簡單,但是無法進行響應式操作,并且也不方便進行全局樣式設置。譬如,如果你打算為Table的邊與單元的邊添加樣式,可能得到的結果如下:

          table { width: 600px; border: 1px solid #505050; margin-bottom: 15px; color:#505050;
          }td{ border: 1px solid #505050; padding: 10px;
          }

          這里存在的問題是出現了很多的重復的邊,會導致視覺上不協調的情況,那么我們可以通過設置border-collapse:collapse來進行處理:

          注釋格式優化

          CSS雖然談不上一門編程語言但是其仍然需要添加注釋以保障整體代碼的可讀性,只要添加些簡單的注釋不僅可以方便你更好地組織整個樣式表還能夠讓你的同事或者未來的自己更好地理解。對于CSS中整塊的注釋或者使用在Media-Query中的注釋,建議是使用如下形式:

          /*---------------
           #Header
          ---------------*/header { }header nav { }/*---------------
           #Slideshow
          ---------------*/.slideshow { }

          而設計的細節說明或者一些不重要的組件可以用如下單行注釋的方式:

          /* Footer Buttons */.footer button { }.footer button:hover { }

          同時,不要忘了CSS中是沒有//這種注釋方式的:

          /* Do */p {
           padding: 15px; /*border: 1px solid #222;*/}/* Don't */p {
           padding: 15px; // border: 1px solid #222; }

          使用Kebab-case命名變量

          對于樣式類名或者ID名的命名都需要在多個單詞之間添加-符號,CSS本身是大小寫不敏感的因此你是用不了camelCase的,另一方面,很久之前也不支持下劃線,所以現在的默認的命名方式就是使用-:

          /* Do */.footer-column-left { }/* Don't */.footerColumnLeft { }.footer_column_left { }

          而涉及到具體的變量命名規范時,建議是使用BEM規范,只要遵循一些簡單的原則即可以保證基于組件風格的命名一致性。你也可以參考CSS Tricks來獲得更多的細節描述。

          避免重復代碼

          大部分元素的CSS屬性都是從DOM樹根部繼承而來,這也是其命名為級聯樣式表的由來。我們以font屬性為例,該屬性往往是繼承自父屬性,因此我們并不需要再單獨地為元素設置該屬性。我們只需要在html或者body中添加該屬性然后使其層次傳遞下去即可:

          html { font: normal 16px/1.4 sans-serif;
          }

          使用transform添加CSS Animations

          不建議直接改變元素的widthheight屬性或者left/top/bottom/right這些屬性來達到動畫效果,而應該優先使用transform()屬性來提供更平滑的變換效果,并且能使得代碼的可讀性會更好:

          .ball { left: 50px; transition: 0.4s ease-out;
          }/* Not Cool*/.ball.slide-out { left: 500px;
          }/* Cool*/.ball.slide-out { transform: translateX(450px);
          }

          Transform的幾個屬性translaterotatescale都具有比較好的瀏覽器兼容性可以放心使用。

          不要重復造輪子

          現在CSS社區已經非常龐大,并且不斷地有新的各式各樣的庫開源出來。這些庫可以幫助我們解決從小的代碼片到用于構建完整的響應式應用的全框架。所以如果下次你再碰到什么CSS問題的時候,在打算擼起袖子自己上之前可以嘗試在GitHUB或者CodePen上搜索可行方案。

          盡可能使用低優先級的選擇器

          并不是所有的CSS選擇器的優先級都一樣,很多初學者在使用CSS選擇器的時候都是考慮以新的特性去復寫全部的繼承特性,不過這一點在某個元素多狀態時就麻煩了,譬如下面這個例子:

          a{ color: #fff; padding: 15px;
          }a#blue-btn { background-color: blue;
          }a.active { background-color: red;
          }

          我們本來希望將.active類添加到按鈕上然后使其顯示為紅色,不過在上面這個例子中很明顯起不了作用,因為button已經以ID選擇器設置過了背景色,也就是所謂的Higher Selector Specificity。一般來說,選擇器的優先級順序為:ID(#id) > Class(.class) > Type(header)

          避免使用!important

          認真的說,千萬要避免使用!important,這可能會導致你在未來的開發中無盡的屬性重寫,你應該選擇更合適的CSS選擇器。而唯一的可以使用!important屬性的場景就是當你想去復寫某些行內樣式的時候,不過行內樣式本身也是需要避免的。

          使用text-transform屬性設置文本大寫

          <div class="movie-poster">Star Wars: The Force Awakens</div>.movie-poster {
           text-transform: uppercase;
          }

          Em, Rem, 以及 Pixel

          已經有很多關于人們應該如何使用em,rem,以及px作為元素尺寸與文本尺寸的討論,而筆者認為,這三個尺寸單位都有其適用與不適用的地方。不同的開發與項目都有其特定的設置,因此并沒有通用的規則來決定應該使用哪個單位,這里是我總結的幾個考慮:

          • em – 其基本單位即為當前元素的font-size值,經常適用于media-queries中,em是特別適用于響應式開發中。

          • rem – 其是相對于html屬性的單位,可以保證文本段落真正的響應式尺寸特性。

          • px – Pixels 并沒有任何的動態擴展性,它們往往用于描述絕對單位,并且可以在設置值與最終的顯示效果之間保留一定的一致性。

          在大型項目中使用預處理器

          估計你肯定聽說過 Sass, Less, PostCSS, Stylus這些預處理器與對應的語法。Preprocessors可以允許我們將未來的CSS特性應用在當前的代碼開發中,譬如變量支持、函數、嵌套式的選擇器以及很多其他的特性,這里我們以Sass為例:

          $accent-color: #2196F3;a {
           padding: 10px 15px;
           background-color: $accent-color;
          }a:hover {
           background-color: darken($accent-color,10%);
          }

          使用Autoprefixers來提升瀏覽器兼容性

          使用特定的瀏覽器前綴是CSS開發中常見的工作之一,不同的瀏覽器、不同的屬性對于前綴的要求也不一樣,這就使得我們無法在編碼過程中記住所有的前綴規則。并且在寫樣式代碼的時候還需要加上特定的瀏覽器前綴支持也是個麻煩活,幸虧現在也是有很多工具可以輔助我們進行這樣的開發:

          • Online tools: Autoprefixer

          • Text editor plugins: Sublime Text, Atom

          • Libraries: Autoprefixer (PostCSS)

          在生產環境下使用Minified代碼

          為了提升頁面的加載速度,在生產環境下我們應該默認使用壓縮之后的資源代碼。在壓縮的過程中,會將所有的空白與重復剔除掉從而減少整個文件的體積大小。當然,經過壓縮之后的代碼毫無可讀性,因此在開發階段我們還是應該使用普通的版本。對于CSS的壓縮有很多的現行工具:

          • Online tools – CSS Minifier (API included), CSS Compressor

          • Text editor plugins: Sublime Text, Atom

          • Libraries: Minfiy (PHP), CSSO and CSSNano (PostCSS, Grunt, Gulp)

          選擇哪個工具肯定是依賴于你自己的工作流啦~

          多參閱Caniuse

          不同的瀏覽器在兼容性上差異很大,因此如果我們可以針對我們所需要適配的瀏覽器,在caniuse上我們可以查詢某個特性的瀏覽器版本適配性,是否需要添加特定的前綴或者在某個平臺上是否存在Bug等等。不過光光使用caniuse肯定是不夠的,我們還需要使用些額外的服務來進行檢測。

          Validate:校驗

          對于CSS的校驗可能不如HTML校驗或者JavaScript校驗那么重要,不過在正式發布之前用Lint工具校驗一波你的CSS代碼還是很有意義的。它會告訴你代碼中潛在的錯誤,提示你一些不符合最佳實踐的代碼以及給你一些提升代碼性能的建議。就像Minifers與Autoprefixers,也有很多可用的工具:

          • Online tools: W3 Validator, CSS Lint

          • Text editor plugins: Sublime Text, Atom

          • Libraries: lint (Node.js, PostCSS), css-validator (Node.js)

          (作者:Danny Markov,翻譯:王下邀月熊_Chevalier)

          英語原文:20 Protips For Writing Modern CSS

          年云棲大會期間,阿里云 Hands on Labs 動手實驗室推出有獎體驗活動,立即參加體驗從設計稿自動生成 H5 應用的神奇。

          ? 來源:yunqi.aliyun.com ? 作者:Imgcook ?

          (本文字數:3960,閱讀時長大約:6 分鐘)

          文末有驚喜,不要忘了去文末看哦~

          什么是 imgCook?

          imgcook 可以使用 Sketch、PSD、靜態圖片等形式作為輸入,通過智能化技術一鍵生成可維護的前端代碼,包含視圖代碼、數據字段綁定、組件代碼、部分業務邏輯代碼等。

          Img Cook 期望能夠利用智能化手段,讓自己成為一位前端工程師,在對設計稿輕約束的前提下實現高度還原,釋放前端生產力,助力前端與設計師高效協作,讓工程師們專注于更具挑戰性的工作!

          設計稿生成代碼的難點

          視圖代碼研發,一般是根據視覺稿編寫 HTML 和 CSS 代碼。如何提效,當面對 UI 視圖開發重復性的工作時,自然想到組件化、模塊化等封裝復用物料的解決方案,基于此解決方案會有各種 UI 庫的沉淀,甚至是可視化拼裝搭建的更高階的產品化封裝,但復用的物料不能解決所有場景問題。個性化業務、個性化視圖遍地開花,直面問題本身,直接生成可用的 HTML 和 CSS 代碼是否可行?

          這是業界一直在不斷嘗試的命題,通過設計工具的開發插件可以導出圖層的基本信息,但這里的主要難點還是對設計稿的要求高生成代碼可維護性差,這是核心問題,我們來繼續拆解。

          設計稿要求高

          對設計稿的要求高,會導致設計師的成本加大,相當于前端的工作量轉嫁給了設計師,導致推廣難度會非常大。一種可行的辦法是采用 CV(ComputerVision, 計算機視覺) 結合導出圖層信息的方式,以去除設計稿的約束,當然對設計稿的要求最好是直接導出一張圖片,那樣對設計師沒有任何要求,也是我們夢寐以求的方案,我們也一直在嘗試從靜態圖片中分離出各個適合的圖層,但目前在生產環境可用度不夠(小目標識別精準度問題、復雜背景提取問題仍待解決),畢竟設計稿自帶的元信息,比一張圖片提取處理的元信息要更多更精準。

          代碼可維護性

          生成的代碼結構一般都會面臨可維護性方面的挑戰:

          • 合理布局嵌套:包括絕對定位轉相對定位、冗余節點刪除、合理分組、循環判斷等方面;
          • 元素自適應:元素本身擴展性、元素間對齊關系、元素最大寬高容錯性;
          • 語義化:類名的多級語義化;
          • 樣式 CSS 表達:背景色、圓角、線條等能用 CV 等方式分析提取樣式,盡可能用 CSS 表達樣式代替使用圖片;

          問題如何解決?

          基于上述的概述和問題分解后,我們對現有的 D2C(Design 2 Code) 智能化技術體系做了能力概述分層,主要分為以下三部分:

          • 識別能力:即對設計稿的識別能力。智能從設計稿分析出包含的圖層、基礎組件、業務組件、布局、語義化、數據字段、業務邏輯等多維度的信息。如果智能識別不準,就可視化人工干預補充糾正,一方面是為了可視化低成本干預生成高可用代碼,另一方面這些干預后的數據就是標注樣本,反哺提升智能識別的準確率。
          • 表達能力:主要做數據輸出以及對工程部分接入:a)通過 DSL 適配將標準的結構化描述做 Schema2Code;b)通過 IDE 插件能力做工程接入。
          • 算法工程:為了更好的支撐 D2C 需要的智能化能力,將高頻能力服務化,主要包含數據生成處理、模型服務部分:
          • 樣本生成:主要處理各渠道來源樣本數據并生成樣本
          • 模型服務:主要提供模型 API 封裝服務以及數據回流

          (前端智能化 D2C 能力概要分層)

          在整個方案里,我們用同一套**數據協議規范(D2C Schema)**來連接各層的能力,確保其中的識別能夠映射到具體對應的字段上,在表達階段也能正確地通過出碼引擎等方案生成代碼。

          智能識別技術分層

          在整個 D2C 項目中,最核心的是上述識別能力部分的機器智能識別部分,這層的具體再分解如下:

          • 物料識別層:主要通過圖像識別能力識別圖像中的物料(模塊識別、原子模塊識別、基礎組件識別、業務組件識別)。
          • 圖層處理層:主要將設計稿或者圖像中圖層進行分離處理,并結合上一層的識別結果,整理好圖層元信息。
          • 圖層再加工層:對圖層處理層的圖層數據做進一步的規范化處理。
          • 布局算法層:轉換二維中的絕對定位圖層布局為相對定位和 Flex 布局。
          • 語義化層:通過圖層的多維特征對圖層在生成代碼端做語義化表達。
          • 字段綁定層:對圖層里的靜態數據結合數據接口做接口動態數據字段綁定映射。
          • 業務邏輯層:對已配置的業務邏輯通過業務邏輯識別和表達器來生成業務邏輯代碼協議。
          • 出碼引擎層:最后輸出經過各層智能化處理好的代碼協議,經過表達能力(協議轉代碼的引擎)輸出各種 DSL 代碼。

          (D2C 識別能力技術分層)

          技術痛點

          當然,這其中的識別不全面、識別準確度不高一直是 D2C 老生常談的話題,也是 imgcook 的核心技術痛點。我們嘗試從這幾個角度來分析引起這個問題的因素:

          • 識別問題定義不準確:問題定義不準確是影響模型識別不準的首要因素,很多人認為樣本和模型是主要因素,但在這之前,可能一開始的對問題的定義就出現了問題,我們需要判斷我們的識別訴求模型是否合適做,如果合適那該怎么定義清楚這里面的規則等。
          • 高質量的數據集樣本缺乏:我們在識別層的各個機器智能識別能力需要依賴不同的樣本,那我們的樣本能覆蓋多少前端開發場景,各個場景的樣本數據質量怎么樣,數據標準是否統一,特征工程處理是否統一,樣本是否存在二義性,互通性如何,這是我們當下所面臨的問題。
          • 模型召回低、存在誤判:我們往往會在樣本里堆積許多不同場景下不同種類的樣本作為訓練,期望通過一個模型來解決所有的識別問題,但這卻往往會讓模型的部分分類召回率低,對于一些有二義性的分類也會存在誤判。

          如何使用 imgCook 將設計稿變為前端代碼

          在了解了 imgcook 大致思路之后,那么為什么會選擇在云開發平臺上集成 imgcook 呢?那就是 imgcook 和云開發平臺通過彼此的打通,將能夠為雙方解決彼此的痛點,無論是為云上開發者,還是 imgcook 開發者都提供了全新的用戶體驗。

          對于 imgcook 開發者來說,其中一個痛點就來自于對于設計稿的管理,以及前后端交互的邏輯,然而通過云開發平臺,開發者不再需要在本地安裝 Sketch,通過云開發平臺直接上傳設計稿即可開始生成代碼,真正做到了0成本一鍵生成。

          另外云開發平臺上直接提供了 Midway Serverless 框架,我們通過云開發平臺的插件定制化,可以讓開發者直接選擇某個頁面所使用的函數(Function),這樣就節省掉編寫一些前后端交互的基礎邏輯或請求代碼。

          對于云開發平臺的開發者來說,最想得到的便是極速的上線體驗和更加便捷的開發體驗,imgcook 可以降低云開發平臺的使用門檻,比如一位 FaaS 應用工程師不再需要學習如何切圖,如何寫 CSS,而只需要編寫 FaaS 函數的邏輯即可,剩下的前端邏輯代碼都可以通過 imgcook 插件在開發平臺內即可完成,這是多么棒的體驗啊!

          那么,接下來就看看如何快速地從 0 到 1 生成代碼吧。

          首先需要先打開云開發平臺創建應用,選擇 imgcook 創建應用:

          然后在應用的 WebIDE 中通過右鍵打開 imgcook 云插件,就可以正式開始使用了。

          第一步,在插件中選擇“導入”,打開上傳設計稿界面:

          第二步,imgcook 可視化編輯器:

          第三步,生成代碼:

          第四步,導出代碼到應用:

          第五步,上線應用:

          $ npm install
          
          $ npm run dev
          
          正在啟動,請稍后...
          
          ---------------------------------------
          
          開發服務器已成功啟動
          
          請打開 >>> http://*****-3000.xide.aliyun.com/
          
          ---------------------------------------
          
          感謝使用 Midway Serverless,歡迎 Star!
          
          https://github.com/midwayjs/midway
          
          ---------------------------------------
          

          啟動成功后通過命令行的地址打開頁面效果如下,是不是很簡單呢?

          總結

          本文通過介紹前端智能化的背景,imgcook 的問題定義以及技術方案,以及如何在云開發平臺上使用 imgcook 開始智能開發,總的來說,還是希望讓業內的前端工程師們從使用 imgcook 開始,將日常工作中的一些繁瑣、耗時的工作交給 AI 來完成,這樣能關注工程師本身更感興趣,也更有價值的事情,也相信不久的將來,前端工程師將借助于 AI 能更加快樂與從容地工作!

          一場腦洞實驗

          今年云棲大會期間,阿里云 Hands on Labs 動手實驗室推出有獎體驗活動,立即參加體驗從設計稿自動生成 H5 應用的神奇。

          同時,由 Hands-on Labs 發起的萬人云上 Hello World 實驗上線

          • 這是一場腦洞實驗,想邀請 10000 名開發者云上 Hello World。希望你愿意來見證這場實驗;
          • 每一位參與實驗的開發者都會收到一張電子榮譽證書,不為別的,和另外 9999 人紀念一下可好?
          • 每一位成功參與實驗的開發者都有機會參與每天一次的錦鯉程序員抽獎活動,哪怕可能性只有萬分之一,來都來了,參與一下唄;
          • 感謝中國國內技術社區們的大力支持,有你們的情懷在,才有這場腦洞實驗從發起到落地。

          點擊“了解更多”可訪問文內鏈接

          深度學習自動生成HTML代碼

          選自Floydhub

          作者:Emil Wallner

          機器之心編譯

          如何用前端頁面原型生成對應的代碼一直是我們關注的問題,本文作者根據 pix2code 等論文構建了一個強大的前端代碼生成模型,并詳細解釋了如何利用 LSTM 與 CNN 將設計原型編寫為 HTML 和 CSS 網站。

          項目鏈接:github.com/emilwallner…

          在未來三年內,深度學習將改變前端開發。它將會加快原型設計速度,拉低開發軟件的門檻。

          Tony Beltramelli 在去年發布了論文《pix2code: Generating Code from a Graphical User Interface Screenshot》,Airbnb 也發布Sketch2code(airbnb.design/sketching-i…)。

          目前,自動化前端開發的最大阻礙是計算能力。但我們已經可以使用目前的深度學習算法,以及合成訓練數據來探索人工智能自動構建前端的方法。在本文中,作者將教神經網絡學習基于一張圖片和一個設計模板來編寫一個 HTML 和 CSS 網站。以下是該過程的簡要概述:

          1)向訓練過的神經網絡輸入一個設計圖

          2)神經網絡將圖片轉化為 HTML 標記語言

          3)渲染輸出

          我們將分三步從易到難構建三個不同的模型,首先,我們構建最簡單地版本來掌握移動部件。第二個版本 HTML 專注于自動化所有步驟,并簡要解釋神經網絡層。在最后一個版本 Bootstrap 中,我們將創建一個模型來思考和探索 LSTM 層。

          代碼地址:

          • github.com/emilwallner…
          • www.floydhub.com/emilwallner…

          所有 FloydHub notebook 都在 floydhub 目錄中,本地 notebook 在 local 目錄中。

          本文中的模型構建基于 Beltramelli 的論文《pix2code: Generating Code from a Graphical User Interface Screenshot》和 Jason Brownlee 的圖像描述生成教程,并使用 Python 和 Keras 完成。

          核心邏輯

          我們的目標是構建一個神經網絡,能夠生成與截圖對應的 HTML/CSS 標記語言。

          訓練神經網絡時,你先提供幾個截圖和對應的 HTML 代碼。網絡通過逐個預測所有匹配的 HTML 標記語言來學習。預測下一個標記語言的標簽時,網絡接收到截圖和之前所有正確的標記。

          這里是一個簡單的訓練數據示例:docs.google.com/spreadsheet…。

          創建逐詞預測的模型是現在最常用的方法,也是本教程使用的方法。

          注意:每次預測時,神經網絡接收的是同樣的截圖。也就是說如果網絡需要預測 20 個單詞,它就會得到 20 次同樣的設計截圖。現在,不用管神經網絡的工作原理,只需要專注于神經網絡的輸入和輸出。

          我們先來看前面的標記(markup)。假如我們訓練神經網絡的目的是預測句子「I can code」。當網絡接收「I」時,預測「can」。下一次時,網絡接收「I can」,預測「code」。它接收所有之前單詞,但只預測下一個單詞。

          神經網絡根據數據創建特征。神經網絡構建特征以連接輸入數據和輸出數據。它必須創建表征來理解每個截圖的內容和它所需要預測的 HTML 語法,這些都是為預測下一個標記構建知識。把訓練好的模型應用到真實世界中和模型訓練過程差不多。

          我們無需輸入正確的 HTML 標記,網絡會接收它目前生成的標記,然后預測下一個標記。預測從「起始標簽」(start tag)開始,到「結束標簽」(end tag)終止,或者達到最大限制時終止。

          Hello World 版

          現在讓我們構建 Hello World 版實現。我們將饋送一張帶有「Hello World!」字樣的截屏到神經網絡中,并訓練它生成對應的標記語言。

          首先,神經網絡將原型設計轉換為一組像素值。且每一個像素點有 RGB 三個通道,每個通道的值都在 0-255 之間。

          為了以神經網絡能理解的方式表征這些標記,我使用了 one-hot 編碼。因此句子「I can code」可以映射為以下形式。

          在上圖中,我們的編碼包含了開始和結束的標簽。這些標簽能為神經網絡提供開始預測和結束預測的位置信息。以下是這些標簽的各種組合以及對應 one-hot 編碼的情況。

          我們會使每個單詞在每一輪訓練中改變位置,因此這允許模型學習序列而不是記憶詞的位置。在下圖中有四個預測,每一行是一個預測。且左邊代表 RGB 三色通道和之前的詞,右邊代表預測結果和紅色的結束標簽。

          #Length of longest sentence
           max_caption_len=3
          #Size of vocabulary 
           vocab_size=3
          # Load one screenshot for each word and turn them into digits 
           images=[]
          for i in range(2):
           images.append(img_to_array(load_img('screenshot.jpg', target_size=(224, 224))))
           images=np.array(images, dtype=float)
          # Preprocess input for the VGG16 model
           images=preprocess_input(images)
          #Turn start tokens into one-hot encoding
           html_input=np.array(
           [[[0., 0., 0.], #start
           [0., 0., 0.],
           [1., 0., 0.]],
           [[0., 0., 0.], #start <HTML>Hello World!</HTML>
           [1., 0., 0.],
           [0., 1., 0.]]])
          #Turn next word into one-hot encoding
           next_words=np.array(
           [[0., 1., 0.], # <HTML>Hello World!</HTML>
           [0., 0., 1.]]) # end
          # Load the VGG16 model trained on imagenet and output the classification feature
           VGG=VGG16(weights='imagenet', include_top=True)
          # Extract the features from the image
           features=VGG.predict(images)
          #Load the feature to the network, apply a dense layer, and repeat the vector
           vgg_feature=Input(shape=(1000,))
           vgg_feature_dense=Dense(5)(vgg_feature)
           vgg_feature_repeat=RepeatVector(max_caption_len)(vgg_feature_dense)
          # Extract information from the input seqence 
           language_input=Input(shape=(vocab_size, vocab_size))
           language_model=LSTM(5, return_sequences=True)(language_input)
          # Concatenate the information from the image and the input
           decoder=concatenate([vgg_feature_repeat, language_model])
          # Extract information from the concatenated output
           decoder=LSTM(5, return_sequences=False)(decoder)
          # Predict which word comes next
           decoder_output=Dense(vocab_size, activation='softmax')(decoder)
          # Compile and run the neural network
           model=Model(inputs=[vgg_feature, language_input], outputs=decoder_output)
           model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
          # Train the neural network
           model.fit([features, html_input], next_words, batch_size=2, shuffle=False, epochs=1000)
          復制代碼
          

          在 Hello World 版本中,我們使用三個符號「start」、「Hello World」和「end」。字符級的模型要求更小的詞匯表和受限的神經網絡,而單詞級的符號在這里可能有更好的性能。

          以下是執行預測的代碼:

          # Create an empty sentence and insert the start token
           sentence=np.zeros((1, 3, 3)) # [[0,0,0], [0,0,0], [0,0,0]]
           start_token=[1., 0., 0.] # start
           sentence[0][2]=start_token # place start in empty sentence
          # Making the first prediction with the start token
           second_word=model.predict([np.array([features[1]]), sentence])
          # Put the second word in the sentence and make the final prediction
           sentence[0][1]=start_token
           sentence[0][2]=np.round(second_word)
           third_word=model.predict([np.array([features[1]]), sentence])
          # Place the start token and our two predictions in the sentence 
           sentence[0][0]=start_token
           sentence[0][1]=np.round(second_word)
           sentence[0][2]=np.round(third_word)
          # Transform our one-hot predictions into the final tokens
           vocabulary=["start", "<HTML><center><H1>Hello World!</H1></center></HTML>", "end"]
          for i in sentence[0]:
          print(vocabulary[np.argmax(i)], 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 和 1 GPS 內部鏈接以運行我的工作流。
          • 在理解輸入與輸出數據之前,其它部分都似懂非懂。輸入 X 是屏幕的截圖和以前標記的標簽,輸出 Y 是下一個標記的標簽。當我理解這一點時,其它問題都更加容易弄清了。此外,嘗試其它不同的架構也將更加容易。
          • 圖片到代碼的網絡其實就是自動描述圖像的模型。即使我意識到了這一點,但仍然錯過了很多自動圖像摘要方面的論文,因為它們看起來不夠炫酷。一旦我意識到了這一點,我對問題空間的理解就變得更加深刻了。

          在 FloydHub 上運行代碼

          FloydHub 是一個深度學習訓練平臺,我自從開始學習深度學習時就對它有所了解,我也常用它訓練和管理深度學習試驗。我們能安裝它并在 10 分鐘內運行第一個模型,它是在云 GPU 上訓練模型最好的選擇。若果讀者沒用過 FloydHub,可以花 10 分鐘左右安裝并了解。

          FloydHub 地址:www.floydhub.com/

          復制 Repo:

          https://github.com/emilwallner/Screenshot-to-code-in-Keras.git
          復制代碼
          

          登錄并初始化 FloydHub 命令行工具:

          cd Screenshot-to-code-in-Keras
          floyd login
          floyd init s2c
          復制代碼
          

          在 FloydHub 云 GPU 機器上運行 Jupyter notebook:

          floyd run --gpu --env tensorflow-1.4 --data emilwallner/datasets/imagetocode/2:data --mode jupyter
          復制代碼
          

          所有的 notebook 都放在 floydbub 目錄下。一旦我們開始運行模型,那么在 floydhub/Helloworld/helloworld.ipynb 下可以找到第一個 Notebook。更多詳情請查看本項目早期的 flags。

          HTML 版本

          在這個版本中,我們將關注與創建一個可擴展的神經網絡模型。該版本并不能直接從隨機網頁預測 HTML,但它是探索動態問題不可缺少的步驟。

          概覽

          如果我們將前面的架構擴展為以下右圖展示的結構,那么它就能更高效地處理識別與轉換過程。

          該架構主要有兩個部,即編碼器與解碼器。編碼器是我們創建圖像特征和前面標記特征(markup features)的部分。特征是網絡創建原型設計和標記語言之間聯系的構建塊。在編碼器的末尾,我們將圖像特征傳遞給前面標記的每一個單詞。隨后解碼器將結合原型設計特征和標記特征以創建下一個標簽的特征,這一個特征可以通過全連接層預測下一個標簽。

          設計原型的特征

          因為我們需要為每個單詞插入一個截屏,這將會成為訓練神經網絡的瓶頸。因此我們抽取生成標記語言所需要的信息來替代直接使用圖像。這些抽取的信息將通過預訓練的 CNN 編碼到圖像特征中,且我們將使用分類層之前的層級輸出以抽取特征。

          我們最終得到 1536 個 8*8 的特征圖,雖然我們很難直觀地理解它,但神經網絡能夠從這些特征中抽取元素的對象和位置。

          標記特征

          在 Hello World 版本中,我們使用 one-hot 編碼以表征標記。而在該版本中,我們將使用詞嵌入表征輸入并使用 one-hot 編碼表示輸出。我們構建每個句子的方式保持不變,但我們映射每個符號的方式將會變化。one-hot 編碼將每一個詞視為獨立的單元,而詞嵌入會將輸入數據表征為一個實數列表,這些實數表示標記標簽之間的關系。

          上面詞嵌入的維度為 8,但一般詞嵌入的維度會根據詞匯表的大小在 50 到 500 間變動。以上每個單詞的八個數值就類似于神經網絡中的權重,它們傾向于刻畫單詞之間的聯系(Mikolov alt el., 2013)。這就是我們開始部署標記特征(markup features)的方式,而這些神經網絡訓練的特征會將輸入數據和輸出數據聯系起來。

          編碼器

          我們現在將詞嵌入饋送到 LSTM 中,并期望能返回一系列的標記特征。這些標記特征隨后會饋送到一個 Time Distributed 密集層,該層級可以視為有多個輸入和輸出的全連接層。

          和嵌入與 LSTM 層相平行的還有另外一個處理過程,其中圖像特征首先會展開成一個向量,然后再饋送到一個全連接層而抽取出高級特征。這些圖像特征隨后會與標記特征相級聯而作為編碼器的輸出。

          標記特征

          如下圖所示,現在我們將詞嵌入投入到 LSTM 層中,所有的語句都會用零填充以獲得相同的向量長度。

          為了混合信號并尋找高級模式,我們運用了一個 TimeDistributed 密集層以抽取標記特征。TimeDistributed 密集層和一般的全連接層非常相似,且它有多個輸入與輸出。

          圖像特征

          對于另一個平行的過程,我們需要將圖像的所有像素值展開成一個向量,因此信息不會被改變,它們只會用來識別。

          如上,我們會通過全連接層混合信號并抽取更高級的概念。因為我們并不只是處理一個輸入值,因此使用一般的全連接層就行了。

          級聯圖像特征和標記特征

          所有的語句都被填充以創建三個標記特征。因為我們已經預處理了圖像特征,所以我們能為每一個標記特征添加圖像特征。

          如上,在復制圖像特征到對應的標記特征后,我們得到了新的圖像-標記特征(image-markup features),這就是我們饋送到解碼器的輸入值。

          解碼器

          現在,我們使用圖像-標記特征來預測下一個標簽。

          在下面的案例中,我們使用三個圖像-標簽特征對來輸出下一個標簽特征。注意 LSTM 層不應該返回一個長度等于輸入序列的向量,而只需要預測預測一個特征。在我們的案例中,這個特征將預測下一個標簽,它包含了最后預測的信息。

          最后的預測

          密集層會像傳統前饋網絡那樣工作,它將下一個標簽特征中的 512 個值與最后的四個預測連接起來,即我們在詞匯表所擁有的四個單詞:start、hello、world 和 end。密集層最后采用的 softmax 函數會為四個類別產生一個概率分布,例如 [0.1, 0.1, 0.1, 0.7] 將預測第四個詞為下一個標簽。

          # Load the images and preprocess them for inception-resnet
           images=[]
           all_filenames=listdir('images/')
           all_filenames.sort()
          for filename in all_filenames:
           images.append(img_to_array(load_img('images/'+filename, target_size=(299, 299))))
           images=np.array(images, dtype=float)
           images=preprocess_input(images)
          # Run the images through inception-resnet and extract the features without the classification layer
           IR2=InceptionResNetV2(weights='imagenet', include_top=False)
           features=IR2.predict(images)
          # We will cap each input sequence to 100 tokens
           max_caption_len=100
          # Initialize the function that will create our vocabulary 
           tokenizer=Tokenizer(filters='', split=" ", lower=False)
          # Read a document and return a string
          def load_doc(filename):
           file=open(filename, 'r')
           text=file.read()
           file.close()
          return text
          # Load all the HTML files
           X=[]
           all_filenames=listdir('html/')
           all_filenames.sort()
          for filename in all_filenames:
           X.append(load_doc('html/'+filename))
          # Create the vocabulary from the html files
           tokenizer.fit_on_texts(X)
          # Add +1 to leave space for empty words
           vocab_size=len(tokenizer.word_index) + 1
          # Translate each word in text file to the matching vocabulary index
           sequences=tokenizer.texts_to_sequences(X)
          # The longest HTML file
           max_length=max(len(s) for s in sequences)
          # Intialize our final input to the model
           X, y, image_data=list(), list(), list()
          for img_no, seq in enumerate(sequences):
          for i in range(1, len(seq)):
          # Add the entire sequence to the input and only keep the next word for the output
           in_seq, out_seq=seq[:i], seq[i]
          # If the sentence is shorter than max_length, fill it up with empty words
           in_seq=pad_sequences([in_seq], maxlen=max_length)[0]
          # Map the output to one-hot encoding
           out_seq=to_categorical([out_seq], num_classes=vocab_size)[0]
          # Add and image corresponding to the HTML file
           image_data.append(features[img_no])
          # Cut the input sentence to 100 tokens, and add it to the input data
           X.append(in_seq[-100:])
           y.append(out_seq)
           X, y, image_data=np.array(X), np.array(y), np.array(image_data)
          # Create the encoder
           image_features=Input(shape=(8, 8, 1536,))
           image_flat=Flatten()(image_features)
           image_flat=Dense(128, activation='relu')(image_flat)
           ir2_out=RepeatVector(max_caption_len)(image_flat)
           language_input=Input(shape=(max_caption_len,))
           language_model=Embedding(vocab_size, 200, input_length=max_caption_len)(language_input)
           language_model=LSTM(256, return_sequences=True)(language_model)
           language_model=LSTM(256, return_sequences=True)(language_model)
           language_model=TimeDistributed(Dense(128, activation='relu'))(language_model)
          # Create the decoder
           decoder=concatenate([ir2_out, language_model])
           decoder=LSTM(512, return_sequences=False)(decoder)
           decoder_output=Dense(vocab_size, activation='softmax')(decoder)
          # Compile the model
           model=Model(inputs=[image_features, language_input], outputs=decoder_output)
           model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
          # Train the neural network
           model.fit([image_data, X], y, batch_size=64, shuffle=False, epochs=2)
          # map an integer to a word
          def word_for_id(integer, tokenizer):
          for word, index in tokenizer.word_index.items():
          if index==integer:
          return word
          return None
          # generate a description for an image
          def generate_desc(model, tokenizer, photo, max_length):
          # seed the generation process
           in_text='START'
          # iterate over the whole length of the sequence
          for i in range(900):
          # integer encode input sequence
           sequence=tokenizer.texts_to_sequences([in_text])[0][-100:]
          # pad input
           sequence=pad_sequences([sequence], maxlen=max_length)
          # predict next word
           yhat=model.predict([photo,sequence], verbose=0)
          # convert probability to integer
           yhat=np.argmax(yhat)
          # map integer to word
           word=word_for_id(yhat, tokenizer)
          # stop if we cannot map the word
          if word is None:
          break
          # append as input for generating the next word
           in_text +=' ' + word
          # Print the prediction
          print(' ' + word, end='')
          # stop if we predict the end of the sequence
          if word=='END':
          break
          return
          # Load and image, preprocess it for IR2, extract features and generate the HTML
           test_image=img_to_array(load_img('images/87.jpg', target_size=(299, 299)))
           test_image=np.array(test_image, dtype=float)
           test_image=preprocess_input(test_image)
           test_features=IR2.predict(np.array([test_image]))
           generate_desc(model, tokenizer, np.array(test_features), 100)
          復制代碼
          

          輸出

          訓練不同輪數所生成網站的地址:

          • 250 epochs:emilwallner.github.io/html/250_ep…
          • 350 epochs:emilwallner.github.io/html/350_ep…
          • 450 epochs:emilwallner.github.io/html/450_ep…
          • 550 epochs:emilwallner.github.io/html/550_ep…

          我走過的坑:

          • 我認為理解 LSTM 比 CNN 要難一些。當我展開 LSTM 后,它們會變得容易理解一些。此外,我們在嘗試理解 LSTM 前,可以先關注輸入與輸出特征。
          • 從頭構建一個詞匯表要比壓縮一個巨大的詞匯表容易得多。這樣的構建包括字體、div 標簽大小、變量名的 hex 顏色和一般單詞。
          • 大多數庫是為解析文本文檔而構建。在庫的使用文檔中,它們會告訴我們如何通過空格進行分割,而不是代碼,我們需要自定義解析的方式。
          • 我們可以從 ImageNet 上預訓練的模型抽取特征。然而,相對于從頭訓練的 pix2code 模型,損失要高 30% 左右。此外,我對于使用基于網頁截屏預訓練的 inception-resnet 網絡很有興趣。

          Bootstrap 版本

          在最終版本中,我們使用 pix2code 論文中生成 bootstrap 網站的數據集。使用 Twitter 的 Bootstrap 庫(getbootstrap.com/),我們可以結合 HTML 和 CSS,降低詞匯表規模。

          我們將使用這一版本為之前未見過的截圖生成標記。我們還深入研究它如何構建截圖和標記的先驗知識。

          我們不在 bootstrap 標記上訓練,而是使用 17 個簡化 token,將其編譯成 HTML 和 CSS。數據集(github.com/tonybeltram…)包括 1500 個測試截圖和 250 個驗證截圖。平均每個截圖有 65 個 token,一共有 96925 個訓練樣本。

          我們稍微修改一下 pix2code 論文中的模型,使之預測網絡組件的準確率達到 97%。

          端到端方法

          從預訓練模型中提取特征在圖像描述生成模型中效果很好。但是幾次實驗后,我發現 pix2code 的端到端方法效果更好。在我們的模型中,我們用輕量級卷積神經網絡替換預訓練圖像特征。我們不使用最大池化來增加信息密度,而是增加步幅。這可以保持前端元素的位置和顏色。

          存在兩個核心模型:卷積神經網絡(CNN)和循環神經網絡(RNN)。最常用的循環神經網絡是長短期記憶(LSTM)網絡。我之前的文章中介紹過 CNN 教程,本文主要介紹 LSTM。

          理解 LSTM 中的時間步

          關于 LSTM 比較難理解的是時間步。我們的原始神經網絡有兩個時間步,如果你給它「Hello」,它就會預測「World」。但是它會試圖預測更多時間步。下例中,輸入有四個時間步,每個單詞對應一個時間步。

          LSTM 適合時序數據的輸入,它是一種適合順序信息的神經網絡。模型展開圖示如下,對于每個循環步,你需要保持同樣的權重。

          加權后的輸入與輸出特征在級聯后輸入到激活函數,并作為當前時間步的輸出。因為我們重復利用了相同的權重,它們將從一些輸入獲取信息并構建序列的知識。下面是 LSTM 在每一個時間步上的簡化版處理過程:

          理解 LSTM 層級中的單元

          每一層 LSTM 單元的總數決定了它記憶的能力,同樣也對應于每一個輸出特征的維度大小。LSTM 層級中的每一個單元將學習如何追蹤句法的不同方面。以下是一個 LSTM 單元追蹤標簽行信息的可視化,它是我們用來訓練 bootstrap 模型的簡單標記語言。

          每一個 LSTM 單元會維持一個單元狀態,我們可以將單元狀態視為記憶。權重和激活值可使用不同的方式修正狀態值,這令 LSTM 層可以通過保留或遺忘輸入信息而得到精調。除了處理當前輸入信息與輸出信息,LSTM 單元還需要修正記憶狀態以傳遞到下一個時間步。

          dir_name='resources/eval_light/'
          # Read a file and return a string
          def load_doc(filename):
           file=open(filename, 'r')
           text=file.read()
           file.close()
          return text
          def load_data(data_dir):
           text=[]
           images=[]
          # Load all the files and order them
           all_filenames=listdir(data_dir)
           all_filenames.sort()
          for filename in (all_filenames):
          if filename[-3:]=="npz":
          # Load the images already prepared in arrays
           image=np.load(data_dir+filename)
           images.append(image['features'])
          else:
          # Load the boostrap tokens and rap them in a start and end tag
           syntax='<START> ' + load_doc(data_dir+filename) + ' <END>'
          # Seperate all the words with a single space
           syntax=' '.join(syntax.split())
          # Add a space after each comma
           syntax=syntax.replace(',', ' ,')
           text.append(syntax)
           images=np.array(images, dtype=float)
          return images, text
           train_features, texts=load_data(dir_name)
          # Initialize the function to create the vocabulary 
           tokenizer=Tokenizer(filters='', split=" ", lower=False)
          # Create the vocabulary 
           tokenizer.fit_on_texts([load_doc('bootstrap.vocab')])
          # Add one spot for the empty word in the vocabulary 
           vocab_size=len(tokenizer.word_index) + 1
          # Map the input sentences into the vocabulary indexes
           train_sequences=tokenizer.texts_to_sequences(texts)
          # The longest set of boostrap tokens
           max_sequence=max(len(s) for s in train_sequences)
          # Specify how many tokens to have in each input sentence
           max_length=48
          def preprocess_data(sequences, features):
           X, y, image_data=list(), list(), list()
          for img_no, seq in enumerate(sequences):
          for i in range(1, len(seq)):
          # Add the sentence until the current count(i) and add the current count to the output
           in_seq, out_seq=seq[:i], seq[i]
          # Pad all the input token sentences to max_sequence
           in_seq=pad_sequences([in_seq], maxlen=max_sequence)[0]
          # Turn the output into one-hot encoding
           out_seq=to_categorical([out_seq], num_classes=vocab_size)[0]
          # Add the corresponding image to the boostrap token file
           image_data.append(features[img_no])
          # Cap the input sentence to 48 tokens and add it
           X.append(in_seq[-48:])
           y.append(out_seq)
          return np.array(X), np.array(y), np.array(image_data)
           X, y, image_data=preprocess_data(train_sequences, train_features)
          #Create the encoder
           image_model=Sequential()
           image_model.add(Conv2D(16, (3, 3), padding='valid', activation='relu', input_shape=(256, 256, 3,)))
           image_model.add(Conv2D(16, (3,3), activation='relu', padding='same', strides=2))
           image_model.add(Conv2D(32, (3,3), activation='relu', padding='same'))
           image_model.add(Conv2D(32, (3,3), activation='relu', padding='same', strides=2))
           image_model.add(Conv2D(64, (3,3), activation='relu', padding='same'))
           image_model.add(Conv2D(64, (3,3), activation='relu', padding='same', strides=2))
           image_model.add(Conv2D(128, (3,3), activation='relu', padding='same'))
           image_model.add(Flatten())
           image_model.add(Dense(1024, activation='relu'))
           image_model.add(Dropout(0.3))
           image_model.add(Dense(1024, activation='relu'))
           image_model.add(Dropout(0.3))
           image_model.add(RepeatVector(max_length))
           visual_input=Input(shape=(256, 256, 3,))
           encoded_image=image_model(visual_input)
           language_input=Input(shape=(max_length,))
           language_model=Embedding(vocab_size, 50, input_length=max_length, mask_zero=True)(language_input)
           language_model=LSTM(128, return_sequences=True)(language_model)
           language_model=LSTM(128, return_sequences=True)(language_model)
          #Create the decoder
           decoder=concatenate([encoded_image, language_model])
           decoder=LSTM(512, return_sequences=True)(decoder)
           decoder=LSTM(512, return_sequences=False)(decoder)
           decoder=Dense(vocab_size, activation='softmax')(decoder)
          # Compile the model
           model=Model(inputs=[visual_input, language_input], outputs=decoder)
           optimizer=RMSprop(lr=0.0001, clipvalue=1.0)
           model.compile(loss='categorical_crossentropy', optimizer=optimizer)
          #Save the model for every 2nd epoch
           filepath="org-weights-epoch-{epoch:04d}--val_loss-{val_loss:.4f}--loss-{loss:.4f}.hdf5"
           checkpoint=ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_weights_only=True, period=2)
           callbacks_list=[checkpoint]
          # Train the model
           model.fit([image_data, X], y, batch_size=64, shuffle=False, validation_split=0.1, callbacks=callbacks_list, verbose=1, epochs=50)
          復制代碼
          

          測試準確率

          找到一種測量準確率的優秀方法非常棘手。比如一個詞一個詞地對比,如果你的預測中有一個詞不對照,準確率可能就是 0。如果你把百分百對照的單詞移除一個,最終的準確率可能是 99/100。

          我使用的是 BLEU 分值,它在機器翻譯和圖像描述模型實踐上都是最好的。它把句子分解成 4 個 n-gram,從 1-4 個單詞的序列。在下面的預測中,「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。然后用總和乘以句子長度的懲罰函數。因為在我們的示例中,長度是正確的,所以它就直接是我們的最終得分。

          你可以增加 n-gram 的數量,4 個 n-gram 的模型是最為對應人類翻譯的。我建議你閱讀下面的代碼:

          #Create a function to read a file and return its content
          def load_doc(filename):
           file=open(filename, 'r')
           text=file.read()
           file.close()
          return text
          def load_data(data_dir):
           text=[]
           images=[]
           files_in_folder=os.listdir(data_dir)
           files_in_folder.sort()
          for filename in tqdm(files_in_folder):
          #Add an image
          if filename[-3:]=="npz":
           image=np.load(data_dir+filename)
           images.append(image['features'])
          else:
          # Add text and wrap it in a start and end tag
           syntax='<START> ' + load_doc(data_dir+filename) + ' <END>'
          #Seperate each word with a space
           syntax=' '.join(syntax.split())
          #Add a space between each comma
           syntax=syntax.replace(',', ' ,')
           text.append(syntax)
           images=np.array(images, dtype=float)
          return images, text
          #Intialize the function to create the vocabulary
           tokenizer=Tokenizer(filters='', split=" ", lower=False)
          #Create the vocabulary in a specific order
           tokenizer.fit_on_texts([load_doc('bootstrap.vocab')])
           dir_name='../../../../eval/'
           train_features, texts=load_data(dir_name)
          #load model and weights 
           json_file=open('../../../../model.json', 'r')
           loaded_model_json=json_file.read()
           json_file.close()
           loaded_model=model_from_json(loaded_model_json)
          # load weights into new model
           loaded_model.load_weights("../../../../weights.hdf5")
          print("Loaded model from disk")
          # map an integer to a word
          def word_for_id(integer, tokenizer):
          for word, index in tokenizer.word_index.items():
          if index==integer:
          return word
          return None
          print(word_for_id(17, tokenizer))
          # generate a description for an image
          def generate_desc(model, tokenizer, photo, max_length):
           photo=np.array([photo])
          # seed the generation process
           in_text='<START> '
          # iterate over the whole length of the sequence
          print('\nPrediction---->\n\n<START> ', end='')
          for i in range(150):
          # integer encode input sequence
           sequence=tokenizer.texts_to_sequences([in_text])[0]
          # pad input
           sequence=pad_sequences([sequence], maxlen=max_length)
          # predict next word
           yhat=loaded_model.predict([photo, sequence], verbose=0)
          # convert probability to integer
           yhat=argmax(yhat)
          # map integer to word
           word=word_for_id(yhat, tokenizer)
          # stop if we cannot map the word
          if word is None:
          break
          # append as input for generating the next word
           in_text +=word + ' '
          # stop if we predict the end of the sequence
          print(word + ' ', end='')
          if word=='<END>':
          break
          return in_text
           max_length=48 
          # evaluate the skill of the model
          def evaluate_model(model, descriptions, photos, tokenizer, max_length):
           actual, predicted=list(), list()
          # step over the whole set
          for i in range(len(texts)):
           yhat=generate_desc(model, tokenizer, photos[i], max_length)
          # store actual and predicted
          print('\n\nReal---->\n\n' + texts[i])
           actual.append([texts[i].split()])
           predicted.append(yhat.split())
          # calculate BLEU score
           bleu=corpus_bleu(actual, predicted)
          return bleu, actual, predicted
           bleu, actual, predicted=evaluate_model(loaded_model, texts, train_features, tokenizer, max_length)
          #Compile the tokens into HTML and css
           dsl_path="compiler/assets/web-dsl-mapping.json"
           compiler=Compiler(dsl_path)
           compiled_website=compiler.compile(predicted[0], 'index.html')
          print(compiled_website )
          print(bleu)
          復制代碼
          

          輸出

          樣本輸出的鏈接:

          • Generated website 1 - Original 1 (emilwallner.github.io/bootstrap/r…)
          • Generated website 2 - Original 2 (emilwallner.github.io/bootstrap/r…)
          • Generated website 3 - Original 3 (emilwallner.github.io/bootstrap/r…)
          • Generated website 4 - Original 4 (emilwallner.github.io/bootstrap/r…)
          • Generated website 5 - Original 5 (emilwallner.github.io/bootstrap/r…)

          我走過的坑:

          • 理解模型的弱點而不是測試隨機模型。首先我使用隨機的東西,比如批歸一化、雙向網絡,并嘗試實現注意力機制。在查看測試數據,并知道其無法高精度地預測顏色和位置之后,我意識到 CNN 存在一個弱點。這致使我使用增加的步幅來取代最大池化。驗證損失從 0.12 降至 0.02,BLEU 分值從 85% 增加至 97%。
          • 如果它們相關,則只使用預訓練模型。在小數據的情況下,我認為一個預訓練圖像模型將會提升性能。從我的實驗來看,端到端模型訓練更慢,需要更多內存,但是精確度會提升 30%。
          • 當你在遠程服務器上運行模型,我們需要為一些不同做好準備。在我的 mac 上,它按照字母表順序讀取文檔。但是在服務器上,它被隨機定位。這在代碼和截圖之間造成了不匹配。

          下一步

          前端開發是深度學習應用的理想空間。數據容易生成,并且當前深度學習算法可以映射絕大部分邏輯。一個最讓人激動的領域是注意力機制在 LSTM 上的應用。這不僅會提升精確度,還可以使我們可視化 CNN 在生成標記時所聚焦的地方。注意力同樣是標記、可定義模板、腳本和最終端之間通信的關鍵。注意力層要追蹤變量,使網絡可以在編程語言之間保持通信。

          但是在不久的將來,最大的影響將會來自合成數據的可擴展方法。接著你可以一步步添加字體、顏色和動畫。目前為止,大多數進步發生在草圖(sketches)方面并將其轉化為模版應用。在不到兩年的時間里,我們將創建一個草圖,它會在一秒之內找到相應的前端。Airbnb 設計團隊與 Uizard 已經創建了兩個正在使用的原型。下面是一些可能的試驗過程:

          實驗

          開始

          • 運行所有模型
          • 嘗試不同的超參數
          • 測試一個不同的 CNN 架構
          • 添加雙向 LSTM 模型
          • 用不同數據集實現模型

          進一步實驗

          • 使用相應的語法創建一個穩定的隨機應用/網頁生成器
          • 從草圖到應用模型的數據。自動將應用/網頁截圖轉化為草圖,并使用 GAN 創建多樣性。
          • 應用注意力層可視化每一預測的圖像聚焦,類似于這個模型
          • 為模塊化方法創建一個框架。比如,有字體的編碼器模型,一個用于顏色,另一個用于排版,并使用一個解碼器整合它們。穩定的圖像特征是一個好的開始。
          • 饋送簡單的 HTML 組件到神經網絡中,并使用 CSS 教其生成動畫。使用注意力方法并可視化兩個輸入源的聚焦將會很迷人。

          原文鏈接:blog.floydhub.com/turning-des…

          本文為機器之心編譯,轉載請聯系本公眾號獲得授權。


          主站蜘蛛池模板: 乱人伦一区二区三区| 无码精品一区二区三区在线| 一区五十路在线中出| 爆乳熟妇一区二区三区| 国产成人无码精品一区二区三区| 肉色超薄丝袜脚交一区二区| 成人精品一区二区三区校园激情| 精品综合一区二区三区| 亚洲国产美国国产综合一区二区| 亚洲av色香蕉一区二区三区 | 濑亚美莉在线视频一区| 视频一区视频二区制服丝袜 | 一区二区三区精密机械| 中文字幕在线无码一区| 在线精品自拍亚洲第一区| 日韩精品视频一区二区三区| 一区二区三区在线看| 日本国产一区二区三区在线观看| 国产午夜精品一区二区三区漫画| 日本在线视频一区二区三区 | 日韩高清一区二区| 国产精品久久久久久麻豆一区| 亚洲综合国产一区二区三区| 精品视频一区二区三区在线播放| 四虎成人精品一区二区免费网站| 亚洲国产一区国产亚洲| 麻豆一区二区三区精品视频| 一区二区三区免费视频网站| 精品一区二区高清在线观看| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 亚洲愉拍一区二区三区| 亚洲美女高清一区二区三区 | 久久久无码精品国产一区| 亚洲一区二区三区国产精品| 亚洲AV成人精品一区二区三区 | 国产精品无码一区二区在线观 | 亚洲欧洲专线一区| 国产高清视频一区三区| 久草新视频一区二区三区| 区三区激情福利综合中文字幕在线一区亚洲视频1| 一区二区三区福利视频免费观看|