作者:Max Woolf機器之心編譯參與:Jane W、吳攀
Keras 是由 Franois Chollet 維護的深度學習高級開源框架,它的底層基於構建生產級質量的深度學習模型所需的大量設置和矩陣代數。Keras API 的底層基於像 Theano 或谷歌的 TensorFlow 的較低級的深度學習框架。Keras 可以通過設置 flag 自由切換後端(backend)引擎 Theano/TensorFlow;而不需要更改前端代碼。
雖然谷歌的 TensorFlow 已廣受關注,但微軟也一直在默默地發布自己的機器學習開源框架。例如 LightGBM 框架,可以作為著名的 xgboost 庫的替代品。例如幾周前發布的 CNTK v2.0(Microsoft Cognitive Toolkit),它與 TensorFlow 相比,顯示出在準確性和速度方面的強勁性能。參閱機器之心報導《開源 | 微軟發行 Cognitive Toolkit 2.0 完整版:從性能更新到應用案例》。
CNTK v2.0 還有一個關鍵特性:兼容 Keras。就在上周,對 CNTK 後端的支持被合併到官方的 Keras 資源庫(repository)中。
Hacker News 論壇對於 CNTK v2.0 也有評論(https://news.ycombinator.com/item?id=14470967),微軟員工聲稱,將 Keras 的後端由 TensorFlow 改為 CNTK 可以顯著提升性能。那麼讓我們來檢驗這句話的真偽吧。
在雲端進行深度學習
在雲端設置基於 GPU 的深度學習實例令人驚訝地被忽視了。大多數人建議使用亞馬遜 AWS 服務,它包含所有可用的 GPU 驅動,只需參照固定流程(https://blog.keras.io/running-jupyter-notebooks-on-gpu-on-aws-a-starter-guide.html)設置遠程操作。然而,對於 NVIDIA Tesla K80 GPU,亞馬遜 EC2 收費 $0.90/小時(不按時長比例收費);對於相同的 GPU,谷歌 Compute Engine(GCE)收費 $0.75/小時(按分鐘比例收費),這對於需要訓練許多小時的深度學習模型是非常顯著的弱點。
要使用 GCE,你必須從一個空白的 Linux 實例中設置深度學習的驅動和框架。我使用 Keras 進行了第一次嘗試(http://minimaxir.com/2017/04/char-embeddings/),但這並不有趣。不過,我最近受到 Durgesh Mankekar 文章(https://medium.com/google-cloud/containerized-jupyter-notebooks-on-gpu-on-google-cloud-8e86ef7f31e9)的啟發,該文章採用了 Docker 容器這種更現代的方法來管理依賴關係,該文章還介紹了名為 Dockerfile 的安裝腳本和容器與 Keras 必需的深度學習驅動/框架。Docker 容器可以使用 nvidia-docker 進行加載,這可以讓 Docker 容器訪問主機上的 GPU。在容器中運行深度學習腳本只需運行 Docker 命令行。當腳本運行完後,會自動退出容器。這種方法恰巧保證了每次執行是獨立的;這為基準評估/重複執行提供了理想的環境。
我稍微調整了 Docker 容器(GitHub 網址 https://github.com/minimaxir/keras-cntk-docker),容器安裝了 CNTK、與 CNTK 兼容的 Keras 版本,並設置 CNTK 為 Keras 的默認後端。
基準方法
Keras 的官方案例(https://github.com/fchollet/keras/tree/master/examples)非常全面,涉及多種現實中的深度學習問題,並能完美地模擬 Keras 在不同模型的性能。我選取了強調不同神經網絡架構的幾個例子(https://github.com/minimaxir/keras-cntk-benchmark/tree/master/test_files),並添加了一個自定義 logger,它能夠輸出含有模型性能和訓練時間進程的 CSV 文件。
如前所述,只需要設置一個 flag 就能方便地切換後端引擎。即使 Docker 容器中 Keras 的默認後端是 CNTK,一個簡單的 -e KERAS_BACKEND ='tensorflow' 命令語句就可以切換到 TensorFlow。
我寫了一個 Python 基準腳本(https://github.com/minimaxir/keras-cntk-benchmark/blob/master/keras_cntk_benchmark.py)(在主機上運行)來管理並運行 Docker 容器中的所有例子,它同時支持 CNTK 和 TensorFlow 後端,並用 logger 收集生成的日誌。
下面是不同數據集的結果。
IMDb 評論數據集
IMDb 評論數據集(http://ai.stanford.edu/~amaas/data/sentiment/)是用於情感分析的著名的自然語言處理(NLP)基準數據集。數據集中的 25000 條評論被標記為「積極」或「消極」。在深度學習成為主流之前,優秀的機器學習模型在測試集上達到大約 88% 的分類準確率。
第一個模型方法(imdb_bidirectional_lstm.py)使用了雙向 LSTM(Bidirectional LSTM),它通過詞序列對模型進行加權,同時採用向前(forward)傳播和向後(backward)傳播的方法。
首先,我們來看一下在訓練模型時的不同時間點測試集的分類準確率:
通常,準確率隨著訓練的進行而增加;雙向 LSTM 需要很長時間來訓練才能得到改進的結果,但至少這兩個框架都是同樣有效的。
為了評估算法的速度,我們可以計算訓練一個 epoch 所需的平均時間。每個 epoch 的時間大致相同;測量結果真實平均值用 95%的置信區間表示,這是通過非參數統計的 bootstrapping 方法得到的。雙向 LSTM 的計算速度:
哇,CNTK 比 TensorFlow 快很多!雖然沒有比 LSTM 的基準測試(https://arxiv.org/abs/1608.07249)快 5-10 倍,但是僅通過設置後端 flag 就幾乎將運行時間減半就已經夠令人震驚了。
接下來,我們用同樣的數據集測試 fasttext 方法(imdb_fasttext.py)。fasttext 是一種較新的算法,可以計算詞向量嵌入(word vector Embedding)的平均值(不論順序),但是即使在使用 CPU 時也能得到令人難以置信的速度和效果,如同 Facebook 官方對 fasttext 的實現(https://github.com/facebookresearch/fastText)一樣。(對於此基準,我傾向於使用二元語法模型/bigram)
由於模型簡單,這兩種框架的準確率幾乎相同,但在使用詞嵌入的情況下,TensorFlow 速度更快。(不管怎樣,fasttext 明顯比雙向 LSTM 方法快得多!)此外,fasttext 打破了 88%的基準,這可能值得考慮在其它機器學習項目中推廣。
MNIST 數據集
MNIST 數據集(http://yann.lecun.com/exdb/mnist/)是另一個著名的手寫數字數據集,經常用於測試計算機視覺模型(60000 個訓練圖像,10000 個測試圖像)。一般來說,良好的模型在測試集上可達到 99%以上的分類準確率。
多層感知器(multilayer perceptron/MLP)方法(mnist_mlp.py)僅使用一個大型全連接網絡,就達到深度學習魔術(Deep Learning Magic)的效果。有時候這樣就夠了。
這兩個框架都能極速地訓練模型,每個 epoch 只需幾秒鐘;在準確性方面沒有明確的贏家(儘管沒有打破 99%),但是 CNTK 速度更快。
另一種方法(mnist_cnn.py)是卷積神經網絡(CNN),它利用相鄰像素之間的固有關係建模,是一種邏輯上更貼近圖像數據的架構。
在這種情況下,TensorFlow 在準確率和速度方面都表現更好(同時也打破 99%的準確率)。
CIFAR-10
現在來研究更複雜的實際模型,CIFAR-10 數據集(https://www.cs.toronto.edu/~kriz/cifar.html)是用於 10 個不同對象的圖像分類的數據集。基準腳本的架構(cifar10_cnn.py)是很多層的 Deep CNN + MLP,其架構類似於著名的 VGG-16(https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)模型,但更簡單,由於大多數人沒有用來訓練的超級計算機集群。
在這種情況下,兩個後端的在準確率和速度上的性能均相等。也許 CNTK 更利於 MLP,而 TensorFlow 更利於 CNN,兩者的優勢互相抵消。
尼採文本生成
基於 char-rnn(https://github.com/karpathy/char-rnn)的文本生成(lstm_text_generation.py)很受歡迎。具體來說,它使用 LSTM 來「學習」文本並對新文本進行抽樣。在使用隨機的尼採文集(https://s3.amazonaws.com/text-datasets/nietzsche.txt)作為源數據集的 Keras 例子中,該模型嘗試使用前 40 個字符預測下一個字符,並儘量減少訓練的損失函數值。理想情況的是損失函數值低於 1.00,並且生成的文本語法一致。
兩者的損失函數值隨時間都有相似的變化(不幸的是,1.40 的損失函數值下,仍有亂碼文本生成),由於 LSTM 架構,CTNK 的速度更快。
對於下一個基準測試,我將不使用官方的 Keras 示例腳本,而是使用我自己的文本生成器架構(text_generator_keras.py),詳見之前關於 Keras 的文章(http://minimaxir.com/2017/04/char-embeddings)。
我的網絡避免了過早收斂,對於 TensorFlow,只需損失很小的訓練速度;不幸的是,CNTK 的速度比簡單模型慢了許多,但在高級模型中仍然比 TensorFlow 快得多。
以下是用 TensorFlow 訓練的我的架構模型生成的文本輸出:
hinks the rich man must be wholly perverity and connection of the english sin of the philosophers of the basis of the same profound of his placed and evil and exception of fear to plants to me such as the case of the will seems to the will to be every such a remark as a primates of a strong of [...]
這是用 CNTK 訓練的模型輸出:
(_x2js1hevjg4z_?z_a?q_gpmj:sn![?(f3_ch=lhw4y n6)gkh kujau momu,?!lj7g)k,!?[45 0as9[d.68éhhptvsx jd_ni,_z!cwkr"_f6-mu_(epp [...]
等等,什麼?顯然,我的模型架構導致 CNTK 在預測時遇到錯誤,而「CNTK+簡單的 LSTM」架構並沒有發生這種錯誤。通過質量評估,我發現批歸一化(batch normalization)是錯誤的原因,並及時提出了這個問題(https://github.com/Microsoft/CNTK/issues/1994)。
結論
綜上,評價 Keras 框架是否比 TensorFlow 更好,這個判斷並沒有設想中的那麼界限分明。兩個框架的準確性大致相同。CNTK 在 LSTM/MLP 上更快,TensorFlow 在 CNN/詞嵌入(Embedding)上更快,但是當網絡同時實現兩者時,它們會打個平手。
撇開隨機錯誤,有可能 CNTK 在 Keras 上的運行還沒有完全優化(實際上,1bit-SGD 的設置不起作用(https://github.com/Microsoft/CNTK/issues/1975)),所以未來還是有改進的空間的。儘管如此,簡單地設置 flag 的效果是非常顯著的,在將它們部署到生產之前,值得在 CNTK 和 TensorFlow 後端上測試 Keras 模型,以比較兩者哪個更好。
原文連結:http://minimaxir.com/2017/06/keras-cntk/