當前位置:
首頁 > 最新 > 海難倖存者:基於項目的TensorFlow.js簡介

海難倖存者:基於項目的TensorFlow.js簡介

作者:Andrew Ribeiro

編譯:Bot

編者按:今年4月,谷歌在TensorFlow開發者峰會上發布TensorFlow的JavaScript版本,引起開發者廣泛關注。如今3個月過去了,大家學會使用這個機器學習新框架了嗎?在這篇文章中,我們將用一個初級項目Neural Titanic來演示如何使用TensorFlow.js,聯繫到最近發生在泰國的事故,這次我們選用的數據集是「泰坦尼克號」,目標是分析哪些人更能從悲劇中幸免於難(二元分類)。

GIF

Demo

註:本文適合對前端JavaScript開發有基本了解的讀者。

神經網路

經過Geoffrey Hinton、Yoshua Bengio、Andrew Ng和Yann LeCun等人的不懈努力,如今神經網路終於可以正大光明地站在陽光下,並在現實中有了用武之地。眾所周知,傳統統計模型可以處理結構化的數據,但對非結構化的數據,如圖像、音頻和自然語言卻無可奈何。現在,通過往神經網路中添加更多層神經元,也就是我們常說的深度學習研究,對非結構化數據建模已經不再是難事。

以圖像建模為例,圖像中最簡單的特徵是邊緣,這些邊緣是形成紋理的基礎,紋理是形成簡單對象的基礎,而簡單對象又是形成複雜對象的基礎。這種關係正好契合深層神經網路的多層結構,因此我們也能學習這些可組合的特徵。(考慮到文章的目的是介紹TensorFlow.js,我們對深度學習的介紹就此打住。)

如需要以上PPT,歡迎私信哦

在過去這幾十年中,隨著計算機算力和可用數據的急劇增加,神經網路已經成為解決諸多現實世界問題的可行方案。與此同時,像TensorFlow這樣的機器學習庫也在快速崛起,鼓勵開發者嘗試用神經網路解決問題。雖然完全搞懂神經網路不是一時半會兒就能做到的,但我們希望這篇文章能激發開發者興趣,鼓勵他們去創建自己的的神經網路程序。

項目概述

如上所述,神經網路非常適合對非結構化數據進行建模,而本文的示例數據集是泰坦尼克號,它只包含表格數據。這裡我們先澄清一個誤區,看完之前的介紹,一些人可能會認為神經網路是萬能的,它比傳統統計模型更好,但事實上,對於簡單數據,模型結構越簡單,它的性能就越好,因為那樣越不容易出現過擬合。

例如泰坦尼克號數據集,或者其他幾乎所有類型的表格數據,神經網路在處理它們時需要用到的超參數有batch-size、激活函數和神經元數量等,但像決策樹這樣的常規演算法只需調整更少超參數,最後性能也差不多。所以雖然鼓勵新手多多嘗試,但當我們建模時,真的沒有必要事事都用神經網路。

在這個項目中,因為神經網路處理的是簡單數據集的二元分類任務,我們會結合可視化技術,具體介紹最後的單隱藏層神經網路。如果你已經精通前端JavaScript開發,也能熟練使用像React這樣的前端框架,你可以在讀完本文後再去學習官方文檔,相信它會讓你對TensorFlow.js產生更多興趣:js.tensorflow.org/tutorials/mnist.html

數據集和建模概述

泰坦尼克號數據集適合初學者,由於比較小,影響輸出結果的各項特徵也比較好找。我們的任務是根據表格數據預測乘客的生存概率,因此可以被用來輔助預測的列是X,預測的目標列則是Y。下面是數據集中的部分數據:

對應X和Y,我們可以獲得:

預測特徵(X)

pClass:船票等級(1等、2等、3等)

name:乘客的姓名

sex:乘客的性別

age:乘客的年齡

sibsp:船上和乘客相關的兄弟姐妹、配偶人數

parch:船上與乘客相關的父母和孩子人數

ticket:乘客的票號

fare:乘客為船票支付的金額

cabin:乘客所在船艙

Embarked:登船港口(C=Cherbourg, Q=Queenstown, S=Southampton)

目標標籤(Y)

survived:乘客倖存為1,死亡為0

原數據集中包含超過1000名乘客的信息,這裡為了簡潔直觀,我們假裝上表就是我們的數據集,X和y的映射關係如下所示:

從技術意義上講,神經網路為非線性函數擬合提供了一個強大的框架。如果把上圖轉換成函數形式,它就是:

對於神經網路,如果我們要模型學會其中的映射關係,這個學習過程被稱為訓練。最後得到的結果必定是個近似值,而不是精確函數,因為如果是後者,這個神經網路就過擬合了,它強行記住了數據集的所有結果,這樣的模型是沒法用在其他數據上的,泛化(通用化)水平太低。作為深度學習實踐者,我們的目標是構建近似上述函數的神經網路體系結構,讓它不僅在訓練集上表現出色,也能被推廣到從未見過的數據上。

項目設置

為了防止每次開發都要重新綁定源代碼,這裡我們先用webpack bundler把JavaScript源代碼和webpack dev伺服器捆綁起來。

在開始項目前,我們先做一些設置:

安裝Node.js

到github上下載這個repo:github.com/Andrewnetwork/NeuralTitanic

打開終端,再打開下載的repo

設置終端類型:npm install

鍵入以下命令啟動dev伺服器:npm run dev

單擊終端中顯示的URL,或在Web瀏覽器中輸入:localhost:8080/

在步驟4中,用npm來安裝package.json中列出的項目依賴項。在步驟5中,啟動開發伺服器,上面會顯示步驟6中需要點擊的URL。這之後,每當我們保存對源代碼的修改時,網頁上會實時刷新內容,並顯示更改。

如果需要捆綁源代碼,只需運行,它會自動生成文件放進./dist/文件夾中。

代碼

雖然文章開頭我們展示了一個比較美觀的Demo,但這裡我們沒有介紹index.html、index.js、ui.js等內容,一方面是因為本文假設讀者已經熟悉現代前端JavaScript開發,另一方面是這些細枝末節介紹起來太複雜,容易講不清楚。如果確實有需要,可以直接用步驟2中提到的repo,或者Python了解下?學起來很快的!:stuckouttongue:

preprocessing.js

對於任何數據分析工作,數據預處理是非常重要的,也是十分有必要的,上面的代碼就在進行預處理:把分類變數轉換為one-hot編碼,並用0替代缺失值(NaN)。因為這是個簡單數據集,事實上我們還可以更優雅一點,用演算法來填補缺失值,但考慮到篇幅因素,這裡我們都做簡化處理。

在這裡,我們把預處理函數prepTitanicRow映射到數據的每一行,這個函數的輸出是特徵變數X和目標向量y。

modeling.js

現在我們就可以創建單隱藏層神經網路了,它已經被actFn和nNeurons兩個變數參數化。可以發現,我們要近似的函數有多個輸入,卻只有一個輸出,這是因為我們在上面的預處理步驟中擴展了特徵空間的維度;也就是說,我們現在有一個步長為3的one-hot輸入,而不是只有一個輸入埠,如下圖所示:

上圖中這些帶箭頭的線被稱為「邊」,它們自帶權重,我們訓練神經網路的最終目標就是把這些權重調整到最佳值。在剛開始訓練的時候,因為對情況一無所知,這些邊會被隨機分配一個初始值,我們把它稱為初始化策略。

一般情況下,這個初始化不用你自己聲明,TensorFlow提供了通用性較強的默認初始化策略,在大多數情況下都表現良好。但就事論事,這個策略確實會影響神經網路性能,尤其是我們這次用到的數據集太小了,權重的初始值會對訓練過程造成明顯影響。所以這裡我們自選一種初始化策略。

這個序列模型對象就是我們用來構建神經網路的東西。它意味著當我們往裡面添加神經網路層時,它們會按順序堆疊,先輸入層,再隱藏層,最後是輸出層。

在這裡,我們添加了一個輸入層(大小為12),並在它後面又加了個密集連接的隱藏層。密集連接表示這一層的所有神經元都與上一層的每個神經元相連,在圖中,神經元被表示為圓,但需要注意的是,它是個存儲單位,我們的輸入不是神經元。

隱藏層會繼承定義圖層的參數詞典:我們定義了多少參數,它就接收多少參數。除了我們提供的參數,它還有一些默認參數:

units:神經元個數,這是個可調整的超參數。

activation:該層中應用於每個神經元的激活函數,對於本文已超綱,請自學選擇。

kernelInitializer:初始化。

inputShape:輸入空間大小,在我們的例子里是12。

這是我們整個神經網路的最後一層,它只是一個密集連接到隱藏層的單個輸出神經元。我們用sigmoid函數作為該神經元的激活函數,因為函數的範圍是[0,1],剛好適合二元分類問題。如果你還要深究「為什麼這個函數能用於預測概率」,我只能簡單告訴你,它和邏輯回歸息息相關。

截至目前,我們已經完成網路的搭建工作,最後就只剩下TensorFlow編譯了。在編譯過程中,我們會遇到兩個新參數:

optimizer:這是我們在訓練期間使用的優化演算法。如果是新手,用Adam;如果很要求高,梯度下降會是你的最愛。

loss:這個參數的選擇要多加註意,因為不同的建模問題需要不同的損失函數,它決定了我們會如何測量神經網路預測結果和實際結果之間的差異。這個誤差會結合優化演算法、反向傳播演算法進一步訓練模型,一般情況下,我們用交叉熵。

最後就是神經網路模型的實際訓練:

在具體介紹前,我們先看看一些常用的術語:

Epoch:在整個數據集上訓練一次被稱為一個epoch。

Mini-Batch:完整訓練數據的子集。對於每個epoch,我們會把訓練數據分成較小的子集一批批進行訓練,通過對比,想必你也應該理解上一個術語的含義了。

如果還是覺得有困難,這裡是完整版:

創建神經網路

預處理數據

Epoch Loop:我們手動設置的迭代次數

Mini-Batch Loop:我們還沒有完成一個epoch,還有剩餘數據,訓練也沒有停止——在Mini-Batch上訓練模型。

End of epoch:已經進一步訓練了模型,並讓它對數據做了預測,而且已經用函數更新了預測結果。

什麼是「async」和「await」?

ES6允許我們定義非同步函數,常見的有async函數,這裡應該沒問題。當我們訓練模型時,用await,它也是個非同步函數,這樣我們就能讓模型在進入下一個epoch前先完成訓練。

tf.tidy和tf.dispose?

這些函數涉及所創建的張量。你可以在張量或變數上調用dispose來清除它並釋放其GPU內存;或者用tf.tidy執行一個函數並清除所有創建的中間張量,釋放它們的GPU內存(它不清除內部函數的返回值)。

await tf.nextFrame();

如果沒有這個,模型訓練會凍結你的瀏覽器。其實查遍資料,關於它的記錄非常少,這大概是TensorFlow.js早起開發時的產物。

tf.tensor()和dataSync();

因為我們的數據存儲在標準JavaScript數組中,所以我們需要用tf.tensor()將它們轉換為TensorFlow的張量格式。反之,如果要從張量轉回數組,用dataSync()。

小結

如果你下載了repo,而且準確無誤地理解了上述內容,你會得到之前動圖的演示結果,其中紅色表示死亡,綠色表示倖存,亮綠色表示倖存幾率更高。

本文探討了一個完整的現代JavaScript項目,該項目使用TensorFlow.js可視化單層神經網路的演化預測,使用的數據集是泰坦尼克號,問題類型是二元分類。希望讀者能根據這篇文章開始理解如何使用TensorFlow.js。

原文地址:kexp.io/intro_tensorflowjs/


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 論智 的精彩文章:

CVPR 2018:十大最酷論文

TAG:論智 |