TensorFlow深度學習,一篇文章就夠了
作者: 陳迪豪,就職小米科技,深度學習工程師,TensorFlow程式碼提交者。
TensorFlow深度學習框架
Google不僅是大資料和雲端計算的領導者,在機器學習和深度學習上也有很好的實踐和積累,在2015年年底開源了內部使用的深度學習框架TensorFlow。
與Caffe、Theano、Torch、MXNet等框架相比,TensorFlow在Github上Fork數和Star數都是最多的,而且在圖形分類、音訊處理、推薦系統和自然語言處理等場景下都有豐富的應用。最近流行的Keras框架底層預設使用TensorFlow,著名的斯坦福CS231n課程使用TensorFlow作為授課和作業的程式語言,國內外多本TensorFlow書籍已經在籌備或者發售中,AlphaGo開發團隊Deepmind也計劃將神經網路應用遷移到TensorFlow中,這無不印證了TensorFlow在業界的流行程度。
TensorFlow從入門到應用
毫不誇張得說,TensorFlow的流行讓深度學習門檻變得越來越低,只要你有Python和機器學習基礎,入門和使用神經網路模型變得非常簡單。TensorFlow支援Python和C++兩種程式語言,再複雜的多層神經網路模型都可以用Python來實現,如果業務使用其他程式設計也不用擔心,使用跨語言的gRPC或者HTTP服務也可以訪問使用TensorFlow訓練好的智慧模型。
那使用Python如何編寫TensorFlow應用呢?從入門到應用究竟有多難呢?
下面我們編寫了一個Hello world應用,輸出字串和進行簡單的運算。
從這段簡單的程式碼可以瞭解到TensorFlow的使用非常方便,通過Python標準庫的形式匯入,不需要啟動額外的服務。第一次接觸TensorFlow可能比較疑惑,這段邏輯Python也可以實現,為什麼要使用tf.constant()和tf.Session()呢?其實TensorFlow通過Graph和Session來定義執行的模型和訓練,這在複雜的模型和分散式訓練上有非常大好處,將在文章的後續部分介紹到。
前面的Hello world應用並沒有訓練模型,接下來介紹一個邏輯迴歸問題與模型。我們使用numpy構建一組線性關係的資料,通過TensorFlow實現的隨機梯度演算法,在訓練足夠長的時間後可以自動求解函式中的斜率和截距。
上面的程式碼可以在tensorflow_examples專案中找到,經過訓練,我們看到輸出的斜率w約為2,截距b約為10,與我們構建的資料之間的關聯關係十分吻合!注意在TensorFlow程式碼中並沒有實現最小二乘法等演算法,也沒有if-else來控制程式碼邏輯,完全是由資料驅動並且根據梯度下降演算法動態調整Loss值學習出來的。這樣我們即使換了其他資料集,甚至換成影象分類等其他領域的問題,無需修改程式碼也可以由機器自動學習,這也是神經網路和TensorFlow強大的地方。
前面的模型只有w和b兩個變數,如果資料處於非線性關係就難以得到很好的結果,因此我們建議使用深層神經網路,這也是TensorFlow設計重點就要解決的深度學習模型。我們知道Google在2014年憑藉Inception模型贏下了ImageNet全球競賽,裡面程式碼就是基於TensorFlow實現的,下面是較為複雜的模型定義程式碼。
使用TensorFlow已經封裝好的全連線網路、卷積神經網路、RNN和LSTM,我們已經可以組合出各種網路模型,實現Inception這樣的多層神經網路如拼湊Lego一樣簡單。但在選擇優化演算法、生成TFRecords、匯出模型檔案和支援分散式訓練上,這裡有比較多的細節,接下來我們將在一篇文章的篇幅內介紹所有TensorFlow相關的核心使用技巧。
TensorFlow核心使用技巧
為了介紹TensorFlow的各種用法,我們將使用deep_recommend_system這個開源專案,它實現了TFRecords、QueueRunner、Checkpoint、TensorBoard、Inference、GPU支援、分散式訓練和多層神經網路模型等特性,而且可以輕易拓展實現Wide and deep等模型,在實際的專案開發中可以直接下載使用。
1. 準備訓練資料
一般TensorFlow應用程式碼包含Graph的定義和Session的執行,程式碼量不大可以封裝到一個檔案中,如cancer_classifier.py檔案。訓練前需要準備樣本資料和測試資料,一般資料檔案是空格或者逗號分隔的CSV檔案,但TensorFlow建議使用二進位制的TFRecords格式,這樣可以支援QueuRunner和Coordinator進行多執行緒資料讀取,並且可以通過batch size和epoch引數來控制訓練時單次batch的大小和對樣本檔案迭代訓練多少輪。如果直接讀取CSV檔案,需要在程式碼中記錄下一次讀取資料的指標,而且在樣本無法全部載入到記憶體時使用非常不便。
在data目錄,專案已經提供了CSV與TFRecords格式轉換工具convert_cancer_to_tfrecords.py,參考這個指令碼你就可以parse任意格式的CSV檔案,轉成TensorFlow支援的TFRecords格式。無論是大資料還是小資料,通過簡單的指令碼工具就可以直接對接TensorFlow,專案中還提供print_cancer_tfrecords.py指令碼來呼叫API直接讀取TFRecords檔案的內容。
2. 接受命令列引數
有了TFRecords,我們就可以編寫程式碼來訓練神經網路模型了,但眾所周知,深度學習有過多的Hyperparameter需要調優,我們就優化演算法、模型層數和不同模型都需要不斷調整,這時候使用命令列引數是非常方便的。
TensorFlow底層使用了python-gflags專案,然後封裝成tf.app.flags介面,使用起來非常簡單和直觀,在實際專案中一般會提前定義命令列引數,尤其在後面將會提到的Cloud Machine Learning服務中,通過引數來簡化Hyperparameter的調優。
3. 定義神經網路模型
準備完資料和引數,最重要的還是要定義好網路模型,定義模型引數可以很簡單,建立多個Variable即可,也可以做得比較複雜,例如使用使用tf.variable_scope()和tf.get_variables()介面。為了保證每個Variable都有獨特的名字,而且能都輕易地修改隱層節點數和網路層數,我們建議參考專案中的程式碼,尤其在定義Variables時注意要繫結CPU,TensorFlow預設使用GPU可能導致引數更新過慢。
上述程式碼在生產環境也十分常見,無論是訓練、實現inference還是驗證模型正確率和auc時都會用到。專案中還基於此程式碼實現了Wide and deep模型,在Google Play應用商店的推薦業務有廣泛應用,這也是適用於普遍的推薦系統,將傳統的邏輯迴歸模型和深度學習的神經網路模型有機結合在一起。
4. 使用不同的優化演算法
定義好網路模型,我們需要覺得使用哪種Optimizer去優化模型引數,是應該選擇Sgd、Rmsprop還是選擇Adagrad、Ftrl呢?對於不同場景和資料集沒有固定的答案,最好的方式就是實踐,通過前面定義的命令列引數我們可以很方便得使用不同優化演算法來訓練模型。
在生產實踐中,不同優化演算法在訓練結果、訓練速度上都有很大差異,過度優化網路引數可能效果沒有使用其他優化演算法來得有效,因此選用正確的優化演算法也是Hyperparameter調優中很重要的一步,通過在TensorFlow程式碼中加入這段邏輯也可以很好地實現對應的功能。
5. Online learning與Continuous learning
很多機器學習廠商都會宣稱自己的產品支援Online learning,其實這只是TensorFlow的一個基本的功能,就是支援線上資料不斷優化模型。TensorFlow可以通過tf.train.Saver()來儲存模型和恢復模型引數,使用Python載入模型檔案後,可不斷接受線上請求的資料,更新模型引數後通過Saver儲存成checkpoint,用於下一次優化或者線上服務。
而Continuous training是指訓練即使被中斷,也能繼續上一次的訓練結果繼續優化模型,在TensorFlow中也是通過Saver和checkpoint檔案來實現。在deep_recommend_system專案預設能從上一次訓練中繼續優化模型,也可以在命令列中指定train_from_scratch,不僅不用擔心訓練程序被中斷,也可以一邊訓練一邊做inference提供線上服務。
6. 使用TensorBoard優化引數
TensorFlow還集成了一個功能強大的圖形化工具,也即是TensorBoard,一般只需要在程式碼中加入我們關心的訓練指標,TensorBoard就會自動根據這些引數繪圖,通過視覺化的方式來了解模型訓練的情況。
tf.scalar_summary('loss', loss)
tf.scalar_summary('accuracy', accuracy)
tf.scalar_summary('auc', auc_op)
7. 分散式TensorFlow應用
最後不得不介紹TensorFlow強大的分散式計算功能,傳統的計算框架如Caffe,原生不支援分散式訓練,在資料量巨大的情況下往往無法通過增加機器scale out。TensorFlow承載了Google各個業務PB級的資料,在設計之初就考慮到分散式計算的需求,通過gRPC、Protobuf等高效能庫實現了神經網路模型的分散式計算。
實現分散式TensorFlow應用並不難,構建Graph程式碼與單機版相同,我們實現了一個分散式的cancer_classifier.py例子,通過下面的命令就可以啟動多ps多worker的訓練叢集。
cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=ps --task_index=0 cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=ps --task_index=1 cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=worker --task_index=0 cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=worker --task_index=1
在深入閱讀程式碼前,我們需要了解分散式TensorFlow中ps、worker、in-graph、between-graph、synchronous training和asynchronous training的概念。首先ps是整個訓練叢集的引數伺服器,儲存模型的Variable,worker是計算模型梯度的節點,得到的梯度向量會交付給ps更新模型。in-graph與between-graph對應,但兩者都可以實現同步訓練和非同步訓練,in-graph指整個叢集由一個client來構建graph,並且由這個client來提交graph到叢集中,其他worker只負責處理梯度計算的任務,而between-graph指的是一個叢集中多個worker可以建立多個graph,但由於worker執行的程式碼相同因此構建的graph也相同,並且引數都儲存到相同的ps中保證訓練同一個模型,這樣多個worker都可以構建graph和讀取訓練資料,適合大資料場景。同步訓練和非同步訓練差異在於,同步訓練每次更新梯度需要阻塞等待所有worker的結果,而非同步訓練不會有阻塞,訓練的效率更高,在大資料和分散式的場景下一般使用非同步訓練。
8. Cloud Machine Learning
前面已經介紹了TensorFlow相關的全部內容,細心的網友可能已經發現,TensorFlow功能強大,但究其本質還是一個library,使用者除了編寫TensorFlow應用程式碼還需要在物理機上起服務,並且手動指定訓練資料和模型檔案的目錄,維護成本比較大,而且機器之間不可共享。
縱觀大資料處理和資源排程行業,Hadoop生態儼然成為了業界的標準,通過MapReduce或Spark介面來處理資料,使用者通過API提交任務後由Yarn進行統一的資源分配和排程,不僅讓分散式計算成為可能,也通過資源共享和統一排程平的臺極大地提高了伺服器的利用率。很遺憾TensorFlow定義是深度學習框架,並不包含叢集資源管理等功能,但開源TensorFlow以後,Google很快公佈了Google Cloud ML服務,我們從Alpha版本開始已經是Cloud ML的早期使用者,深深體會到雲端訓練深度學習的便利性。通過Google Cloud ML服務,我們可以把TensorFlow應用程式碼直接提交到雲端執行,甚至可以把訓練好的模型直接部署在雲上,通過API就可以直接訪問,也得益於TensorFlow良好的設計,我們基於Kubernetes和TensorFlow serving實現了Cloud Machine Learning服務,架構設計和使用介面都與Google Cloud ML類似。
TensorFlow是很好深度學習框架,對於個人開發者、科研人員已經企業都是值得投資的技術方向,而Cloud Machine Learning可以解決使用者在環境初始化、訓練任務管理以及神經網路模型的線上服務上的管理和排程問題。目前Google Cloud ML已經支援automatically hyperparameter tunning,引數調優未來也將成為計算問題而不是技術問題,即使有的開發者使用MXNet或者其他,而不是TensorFlow,我們也願意與更多深度學習使用者和平臺開發者交流,促進社群的發展。
最後總結
總結一下,本文主要介紹TensorFlow深度學習框架的學習與應用,通過deep_recommend_system專案介紹了下面使用TensorFlow的8個核心要點,也歡迎大家下載原始碼試用和反饋。