1. 程式人生 > >“Spark上流式機器學習演算法實現”終期檢查報告

“Spark上流式機器學習演算法實現”終期檢查報告

    自6月底申請專案到現在9月初撰寫專案結題報告,眨眼一瞬間兩個半月很快成為過去,在這兩個半月的時間裡,在不斷的看文章和除錯程式碼,首先我得感謝和我一起合作的賴百勝同學與我並肩作戰,是他給了我一次次戰勝bug的勇氣,是他讓我感覺到整個專案做下來而不覺得孤單。當然還要感謝intel中國研究院的尹老師,是他指導我們一步步由淺入深地學習spark程式設計,給我們指明研究的方向。最後,必須要感謝CSDN能提供此次實習機會,讓我們在暑假還能收穫這麼一段珍貴的實習經歷。經歷過這次開源實習後,我們團隊成員都深深的感受到開源專案的重要性和巨大的意義。

   下面我們通過三個部分來介紹整個專案執行過程中的情況並進行總結。

一、專案實施情況

   在這兩個半月的時間裡面,我們牢牢按照專案初期安排實施專案的工作。

1、專案背景

   Scala語言是近10年來逐漸發展起來的一種函式式的面嚮物件語言,語法類似於java,其良好的併發特性受到很多開發者的喜愛。另外目前國外的大型網站如Twitter,Amazon等也宣佈其後端程式都用的是Scala語言。可以說Scala語言有巨大的潛力等待著人們發掘。

   Spark是UCBerkeley開發的基於mapreduce演算法實現的通用平行計算框架,其主要優點在於job的中間輸出結果可以儲存在記憶體中,從而不一定需要讀寫HDFS,因而spark能更好地適用於資料探勘與及機器學習等演算法。

   Spark streaming是構建在spark上的一個處理流資料的框架,接收到的資料流分成小的時間片,以類似批量處理的方式來處理這部分的資料,非常適合與一些需要歷史資料和實時資料聯合分析的場合使用。

   MLlib是spark中常用的機器學習演算法的實現庫,支援四種常見的機器學習問題:二元分類、迴歸、聚類以及協同過濾。但是spark自帶的機器學習演算法都是基於已有的資料進行模型訓練然後對訓練的模型進行預測和評估。如果需要對新的訓練資料進行訓練, MLlib中的模型需要重新訓練,必將消耗很多的較多時間和CPU計算資源。

   隨著機器學習領域的發展,近些年來一些線上的機器學習演算法也不斷湧現,這些線上的機器學習演算法在能以較低的計算複雜度對模型中新進入的資料進行學習和改進模型,使得新得到的模型具有更高的預測準確性,在目前基於地理位置的帶有推薦功能的軟體(如大眾點評、淘點點等)中有巨大的應用。我們的專案也即基於這個背景出發,希望能改進MLlib庫中的現有的機器學習演算法,使其能成為線上的機器學習演算法,為開源社群做出一點貢獻。

2、熟悉scala和spark開發環境和程式語言

   俗話說的好“工欲善其事,必先利其器”。我們在接到專案後花了大約一週左右的時間搭建開發環境,併購置了由瑞士洛桑理工(EPFL)的Martin Odersky撰寫的scala語言的經典教科書《Programmingin Scala》。

   spark官方網站建議在linux平臺上執行spark程式,我們藉助scala和spark官方網站及其他一些網站的相關操作介紹在實驗室的linux伺服器上搭建好可以執行spark程式的環境。詳見博文《基於linux的spark與scala開發環境搭建》和《基於spark執行scala程式》。在試著執行spark自帶的計算π和單詞統計的例程時候發現spark的獨特的基於記憶體的分散式計算的特性,這個特性可以使程式的執行速度成倍的提高。為了更好地理解spark底層工作原理,我們還學習了專案導師(尹老師)在小象學院開設的公開課《Spark上機器學習方法的模式與效能》,受益匪淺。

   另外,由於linux上一般是用命令列或者指令碼進行操作,執行程式很方便並且效率高,但是寫程式顯得並不是那麼方便,我們在coursa上的《Functional ProgrammingPrinciples in Scala》課程中學習到了在windows環境下用scala-IDE這個平臺編輯程式碼非常的好用,這個軟體是基於eclipse開發的scala語言的程式設計環境。我們只需要在scala-IDE中將scala程式碼可以打包成jar檔案,然後上傳到linux伺服器上,然後就可以歡快地跑起來了,這樣編輯程式和執行程式兩不誤。

3、廣義線性線性模型的流式機器學習

   我們實現的基於sparkStreaming的廣義線性模型包含最小線性二乘、邏輯斯特迴歸、嶺迴歸和Lasso。

   假設每個資料為a_i(i=1,2,…,n),所有資料按行排列成資料矩陣為A,所有資料的觀測為向量y,模型引數為x,最小線性二乘的模型如下:

   邏輯斯特迴歸的模型如下:

   嶺迴歸的模型如下:

   λ是正則引數。

   上述三種模型中的目標優化函式都可以對x求梯度,因此可以直接用梯度下降法對它們進行求解。我們只需要求上述三種模型的梯度即可。其中最小線性二乘關於x的梯度為:

   邏輯斯特迴歸模型關於x的梯度為:

   嶺迴歸模型關於x的梯度為:

   而對於Lasso,它的模型為

   注意到正則項不能對x求梯度,所以不能直接用梯度下降法,為了解決這個問題,我們參照spark中的方法,使用HuberFunction對正則項 進行逼近。HuberFunction的定義為:

   使用HuberFunction替換L1項後,我們可以對目標優化函式求關於x的梯度,它是:

   其中:


   有了四種模型的目標優化函式關於求解變數x的梯度後,梯度下降更新模型引數x的方法是:


   其中,η是更新的步長。

   上述四種廣義線性模型還不是流式的學習演算法,為了用流式的資料對模型進行訓練,我們將上述提到的梯度下降法改為隨機梯度下降法,即每次計算梯度只用當前資料進行計算。為了減小呼叫函式的頻率,實際的實現中,我們使用一組(batch)資料進行梯度的計算,這一點和spark中的隨機梯度下降法也是一致的。

   我們利用sparkstreaming,從網路埠或資料夾中讀取DStream的流式資料,先對資料進行解析,然後輸入模型進行流式訓練。

   我們使用上述模型在資料集breast-cancer-wisconsin(詳見我們的Code庫)上進行測試,其中共有700個數據,將其中560個數據用來流式地訓練,即每次只接收一個batch的資料,每次一個batch的資料進行訓練後,我們都對測試集上140個數據進行測試,計算其準確率,可以看到測試誤差會呈現下降的趨勢。以下是邏輯斯特迴歸的訓練結果:


   每個演算法我們有兩種實現,第一種實現中,每個演算法單獨使用,並且訓練過程是我們編寫的;第二種實現,我們藉助了spark中的非基於Streaming的廣義線性模型的實現,新寫了StreamingGeneralizedLinearAlgorithm類,這個類調指定了模型和演算法後,會用spark自帶的各種線性模型和隨機梯度下降演算法,因此細節是被封裝了的。

4、基於ALS演算法的簡易線上推薦系統

   在前期實現了廣義線性模型的流式機器學習演算法後,我們轉向了對推薦系統的研究,因為網路上充滿著各種各樣的資訊,而且數量相當龐大,並且還在以相當驚人的速度增長,如何在海量的資訊中快速的找到我們所需要的資訊並快速的反饋給使用者,是網際網路推薦系統需要考慮的一個十分重要的問題。

   推薦系統中最核心和關鍵的部分就是使用的推薦演算法,其在很大程度上決定了推薦系統性能的優劣。推薦演算法大致可以分為以下幾類:①基於內容的推薦演算法(content-basedrecommendation)②協同過濾推薦演算法(collaborativefiltering recommendation)③基於知識的推薦演算法(knowledge-basedrecommendation)。

   最初我們想基於協同過濾推薦演算法在目前廣泛應用的movielens資料集上計算和推薦使用者電影根據推薦結果和已有的樣本資料進行比較在模型不斷學習過程中推薦的準確性。後面我們發現在spark的MLlib庫中自帶有基於ALS(迭代最小二乘法)演算法的推薦程式,雖然ALS演算法由於其計算複雜度較大,在實際應用中並不是很多,但是在movielens這個資料集上卻顯示出其優越性。

   因此我們改寫了spark中的ALS模型訓練的程式,使其可以對新的資料進行學習,詳見博文《基於ALS演算法的簡易線上推薦系統》。但是在博文中我們也提到了,由於目前的spark框架對於矩陣的運算操作支援的並不是特別好,因此將ALS演算法改進為可以流式學習的演算法有較大的難度,我們僅僅加入了將TCP流獲得的資料合併到以前的資料集中,然後再進行模型訓練,但是這樣做的話由於元素過多和演算法複雜度過高的關係,在小記憶體的機器上難以完美地執行,有待改進為演算法複雜度更低的ALS模型更新演算法。

    在movielens資料集上,我們測試的效果如下,由於初始接收的資料不夠多,無法對測試集中的所有的資料進行預測,因此RMSE偏小,隨著到達的資料樣本不斷增多,學習後的模型在測試集上的的誤差也在不斷的減小。

5、線上的PCA演算法

   PCA是大規模機器學習中常用的工具,可以大量降低資料的維度,減少運算量。我們找到了線上PCA的具體演算法,但是由於Spark中分散式的矩陣操作,特別是把多個矩陣拼接在一起,沒有現成的函式,而實現這樣的功能有比較複雜,我們在最後不得已放棄了線上PCA演算法的實現。但是我們在Matlab上進行了如下的模擬。

   線上PCA演算法通過流式的資料訓練一個對映矩陣,將高維的資料降到低維。可以想象,用來訓練的資料越多,對映矩陣也就越高,即主成分的選取越準確。我們在MIT的人臉識別資料集CBCL上,對資料分成三個部分,PCA訓練資料,SVM訓練資料,SVM測試資料。其中,將PCA訓練資料等分成20份,用不同數量的PCA訓練資料進行PCA訓練,然後對這些不同資料量訓練出來的對映矩陣對同樣的SVM訓練資料進行降維,使用降維後的資料進行SVM訓練,然後在SVM測試資料上進行測試,計算錯誤率。得到以下結果:

   這個模擬說明,隨著PCA訓練資料的增加,其得到的主成分也越好。

二、專案的一些遺憾

   前面第一部分主要闡述了我們在實施專案過程中所獲得的一些小的階段性成果,但是回首過去,在執行專案過程中總有一些遺憾的事情沒能很好的完成,這裡也做一個簡要的回顧。

1、Scala程式設計規範

   儘管我們盡力按照scala和spark的程式設計規範去寫程式碼,但是第一次寫這種程式碼,心裡總是心有餘悸,得先把演算法實現了再去改程式碼規範,因此寫出來的程式碼並不是那麼的清楚易懂,另外,scala語言那種良好的封裝特性,也讓我們理解演算法遇到了一定的障礙。

2、基於ALS模型的線上演算法改進

   其實我們挺想將ALS模型的線上學習改進為演算法複雜度更低的演算法,但是真的受制於spark的發展,讓我們難以像在matlab一樣對矩陣進行靈活的操作,因此改進ALS模型遇到了極大的阻力,希望後續更新spark的程式設計師能加強spark對矩陣操作的支援,這樣改進其他的相關演算法就容易多了。

3、線上PCA演算法未能實現

   同樣是受限於spark對矩陣操作的支援,我們沒能實現線上的PCA演算法。還有一個原因是我們對spark中運用到的breeze庫不是很熟悉,這個庫可以用來做local矩陣和向量的操作。

三、專案結語

   在這個臨近中秋的夜晚寫這份結題報告心中真是悲喜交加,喜的是兩個月多月的實習期終於結束了,悲的是在執行的專案中總會留下那麼一些遺憾感覺難以實現,並且感覺還有很多等待我們去實現的地方沒有完成。

   但是無論如何在我們的專案過程中,我們充分認識到了開源工作真的是非常的有意義,但是是一種長期漫長的工作,需要很多感興趣寫程式碼的人的不斷的努力才能完成一個比較偉大的project。最後再次感謝CSDN提供的這次開源專案實習機會,讓我們受益匪淺。


附:專案程式碼見下面連結

https://code.csdn.net/zhangyuming010/zju_spark_2014