Swift for Tensorflow

Swift for Tensorflow

內容來源:2018 年 9 月 15 日,SwiftGG資深灌水師王文槿在“2018@swift 第三屆 Swift 開發者大會”進行《Swift for Tensorflow》演講分享。IT 大咖說作為獨家視頻合作方,經主辦方和講者審閱授權發佈。

閱讀字數:3628 | 10分鐘閱讀

Swift for Tensorflow

獲取嘉賓完整演講視頻及PPT,請複製:http://t.cn/EArXaIQ,粘貼至瀏覽器即可。

Why Swift for Machine Learning

本次我們談論的Machine Learning並不是在客戶端而是在服務端側,因此接下來的內容有一個大背景,即都是基於Server-side Swift。

Swift既像腳本語言一樣有很強的Productive,開發起來快速簡潔,性能又和老牌的編譯型語言類似。正是優秀的特性,使得Swift在服務端獲得廣泛的應用。

Swift有三個主要特點。第一是高性能;第二是社區很活躍,不過在Server-side部分還有很長路要走;第三是快速安全。

Next Big Thing on Server

之前的Server服務大多是些增刪改查,頂多再做些DBA、主從之類的,但這些正逐步被雲服務的基礎設施所替代。而目前基於機器學習的App在服務端正呈現井噴式的發展,像分析系統、音視頻理解、超解析、聊天機器人等。

這些機器學習類的服務端App所使用的語言主要有兩個。第一個毫無疑問是C++,無論是caffeine還是Tensorflow最初都是用C++實現的,它的特點在於安全和高性能,缺點是僅有少量的productive。另一個就是python,和C++相反,python寫起來很容易,但也正因為如此會多寫出很多垃圾代碼,同時它也不夠安全。

那麼有沒有一種語言,兼具安全高性能和Easy with write呢?答案顯而易見,就是今天的主角——Swift。

Swift for TensorFlow

Swift for TensorFlow是作為一個整體存在的,並不僅是Swift引入了TensorFlow API,它可算作一門新的語言,官方簡寫為TFiwS。

Intro

TFiwS的首個released是在2018年TFDEVSummit上,它是Open source的,並加入了TensorFlow Ecosystem。在TFiwS中機器學習是"第一等公民",而並非只是將TensorFlow API包裝成庫拿來使用。

雖然TFiwS尚處於早期階段,但得益於TensorFlow的支持,它可以跑在CPU、GPU、以及Cloud TPU上。並且迭代速度很快,基本上兩週發佈一個新版本。

與Swift的結合,使得TFiwS兼顧了性能和可用性。還能夠應用Swift生態的東西,比如在Xcode Playground工作,同時支持macOS和ubuntu。

Playground

Swift for Tensorflow

上圖為Playground中TFiwS的代碼,其中Tensor對象可以簡單理解為一個多維數組,用來幫助我們做一些運算。比如對於圖中2級3維的數組,我們可以直接對Tensor對象做加乘操作。可以看到這種寫法與腳本語言很類似,雖然這是咋一看很普通的特性,但其實對可用性來說很重要,相比一些線性代數庫要好用很多。

Core Ideas

Swift for Tensorflow

TensorFlow模型中有兩種模式,分別是Graph和Eager Execution。上圖為Graph模式代碼,這段代碼前半部分並沒有實際進行運算,只是在構建Graph結構,直到sess.run() 之後才真正執行。

這種模式的優勢在於高性能,因為可以在執行前對圖進行各種優化。但缺點也很明顯,首先是很難Debug,比如我們沒法通過在xt後添加一行print來打印出它的值,因為此時代碼沒有執行;其次是可用性差,我們不能按照直覺去寫代碼,而是先要在腦中構建出圖,讓再由代碼執行。

Swift for Tensorflow

Eager Execution是一種立即執行模式,每個操作都可以獲取到結果。這種的優勢在於Define-by-run,即可以運用一些控制流程來決定代碼的執行;同時對Debug友好。缺點嘛,就是沒有優化。

其實我們可以簡單的理解,Graph是編譯模式,Eager Execution是解釋模式。

TFiwS Mode

Swift for Tensorflow

現在TensorFlow現在有了第三種模式,也就是TFiwS模式。雖然上面的這段代碼是以Eager Execution模式寫的,但是執行的時候卻是以Graph模型運行,所以它有圖模式所有的優化。其原理是在編譯階段生成圖,然後生成的圖和代碼在最終執行期間並行執行,並進行智能調度。

How

Swift for Tensorflow

對於圖中這段代碼,我們如果想要獲取到它的圖該怎麼辦呢?這裡的關鍵點在於Swift沒有runtime,這樣的話只能通過遍歷語法樹來實現(如下圖)。語法樹中保存有類型信息、運算信息、參與運算的變量類信息等等。

Swift for Tensorflow

之所以可以怎麼做,主要得益於Swift的靜態類型系統,這也是為什麼這種方式適用於Swift而不適用於pyton的原因。

Swift for Tensorflow

編譯完成之後就變成了這樣形式,原先的立即執行代碼都變成了圖來調用,最後返回結果。

Swift for Tensorflow

這段代碼與前一個有兩點不同,首先它多了一條用於打印tmp2的語句,其次它並非直接返回tmp2,而是對tmp2進行運算後返回tmp3,且涉及的另一個運算變量是由本地的其他函數返回。

Swift for Tensorflow

這是對這段代碼進行靜態分析後構建出的圖。這裡第一個問題就是magic的值未知,因為它是由本地函數返回,在編譯期間獲取不到。第二個就是我們不知道tmp2的值何時返回,因為圖是直接執行的。

Program Slice Stage

要理解上面的問題,首先要明白程序變換,程序變換第一步是將原始代碼變換成一份用來構建圖的代碼,第二步是將原始代碼變換成可以跑的代碼。

Swift for Tensorflow

上圖為第一階段變換的代碼,圖右側就是用來構建圖的代碼,可以看到其中一些本地代碼都被刪除並用其他東西來替代,比如Print操作被替換成了send發送。Send和Recvice是標準的TensorFlow節點,用於跑分佈式學習的時候不同的集群間交換結果。

Swift for Tensorflow

上圖為第二階段變化後用於跑的代碼(host),這段代碼中所有的tensor code都已被刪除。第一行為啟動圖的代碼,然後通過receive接受圖代碼中send的tmp2,並打印出來。接著調用magicNumber函數計算出result發送給圖代碼。最後接受圖代碼返回的結果並拋出。

Swift for Tensorflow

以上就是整個變換流程圖,左邊是Host的代碼,右邊是圖代碼,他們之間通過Receive和Send通信。這樣還帶來了一個好處,即圖代碼和host 代碼可以運行在不同的地方,比如圖代碼跑GPU,host代碼跑CPU,或者在遠程GPU上運行。

Summary

Swift for Tensorflow

TFiwS本質上是在Swift和Complier之間實現了一個Pass,它會將原始代碼拆分成兩塊——Host Code和Graph Code。Host Code在Swift Runtime上執行,Graph Code在TF Runtime上執行。這兩個Runtime之間通過Send和Receive節點進行通信,最終輸出。

Example

Linear Classification

Swift for Tensorflow

我們先來給這張圖賦予一些實際意義,假設上圖是對一片被汙染的海域進行53次採樣後獲得的結果,其中點表示該區域海水是乾淨的,方塊表示已被汙染。現在的問題是,給出一個座標如何判斷該位置是否已被汙染。

Swift for Tensorflow

很明顯這是一個線性可分的問題,那麼我們首先找出一條線,應用上面的線性模式公式。這裡我們假設W0後還有一個X0,這個X0等於1,且X1和X2都已計算處理出來了。這個線性方程計算後會有4個連續的值,值域從正無窮到負無窮。

接下來問題是如何確定這個值對應的位置是否被汙染。對此有兩種方案,一種是直接設定一個閾值,用它來作為標準;另一種是通過函數將Line(X)的返回值map到固定的範圍內。

Swift for Tensorflow

上圖的函數定義域是負無窮到正無窮,值域是0到1。將Line(x)的值放入該函數中後會返回一個0到1的值,我們可以用0和1分別表示一個標籤。這樣就獲得一個新的模型。

Swift for Tensorflow

然後就是如何基於53個觀察數據計算出W。如果以概率的角度來看,其實我們可以用極大似然估計法得到關於W的可視函數,然後使用梯度下降的方式最大化極大似然估計法求出來的W。

Swift for Tensorflow

上圖為簡寫後的矩陣形式,用這個公式就可以迭代多次以獲得最好的W。這種方式被稱為對數幾率迴歸。

Code Time

下面我們來看下上面的問題如何在TFiwS中實現。

Swift for Tensorflow

這段代碼的關鍵在於最後的兩個結構體。我們用Model表示最終想要的模型,模型中的參數為ParameterAggregate類型,它在TFiwS中表示一個模型。

Swift for Tensorflow

這裡僅是在做一些變換,裡面構造了用來做(未知)的Tensor和每個數據的標記。

Swift for Tensorflow

模型的訓練通過處理函數完成,內部不停迭代模型。可以看到TFiwS定義了很多操作,讓我們像寫公式一張寫代碼。

Swift for Tensorflow

以上為使用python的matplot展示的最終效果,與我們預想中的連線相差無幾。

Collaborative Filtering

Collaborative Filtering協同過濾是現在推薦系統的基礎,本質是基於用戶對某個事物的評分來進行推薦。它有兩種方法,item to item和user to item,分別是基於商品和用戶畫像。本次主要介紹item to item的實現。

假設我們現在要基於目標用戶和其他用戶的觀看歷史來推薦電影,使用的是常用的MovieLens Dataset,其中有10萬條記錄,為943個用戶對1682部電影的評分。

這10萬條數據其實是很稀疏的,因為943乘以1682遠不止10萬,也就是說有很多用戶對某些電影的評分我們是沒有的。因此我們要基於現有數據推測出一些沒有的數據。

Swift for Tensorflow

對於相似性的計算推薦系統中最常用的就是cosine similarity(餘弦相似性),如上圖所示,計算的是兩者之間的夾角,角度越小相似度越高。

而對於建模我們可以從數據入手,將數據劃分成測試數據和訓練數據。以訓練數據作為模型,然後給測試數據進行預測,最終比較預測值和原測試數據值之間的差值,以此來判斷業務模型的訓練效果。

1. Load Data

Swift for Tensorflow

上圖為TFiwS中的實現,首先加載數據,再進行一些變換,接著切分測試和訓練數據,最後將數據的轉換成TFiwS tensor。

2. Compute Similarity

Swift for Tensorflow

Swift for Tensorflow

這是相似度計算公式與實際代碼,該公式其實可以被直接轉換成矩陣相乘的形式,這樣就能通過少量代碼進行計算。

3. Make Prediction

Swift for Tensorflow

Swift for Tensorflow

和相似度公式類似,我們也可以將預測公式轉換成矩陣形式,在TFiwS中以少量的代碼表示。

4. Validation

Swift for Tensorflow

Swift for Tensorflow

最終的驗證階段,我們只需要將測試數據放到預測後的大矩陣中找到對應的值,然後將他們一一相減,最後將所有和測試數據對應的點的()抓取出來求平方就可以了。

5. Result

最終的結果為總用戶943,電影總量1682,mse為10.776904。我們我們還可以對此做進一步優化。

因為預測的時候我們是將某個商品乘以與其相似的所有商品,但在計算過程中其實有很多不相關的商品也摻雜在裡面。如果與該商品進行計算的是與其相關度Top k的商品,那麼最終的結果會更加準確。

ReSource

Swift for Tensorflow

上圖展示的是一些相關資源。第一個是最後的兩個案例的代碼;第二個是TFiwS的文檔,像本次講的圖模式原理就在裡面;第三個是教程和Demo的鏈接,比如Swift-models的倉庫中就有很多現成的模型。


分享到:


相關文章: