當前位置:
首頁 > 新聞 > 手把手教你為iOS系統開發TensorFlow(附開源代碼)

手把手教你為iOS系統開發TensorFlow(附開源代碼)

選自machinethink.net

機器之心編譯

參與:趙華龍、邵明、吳攀、李澤南

手把手教你為iOS系統開發TensorFlow(附開源代碼)


在你使用深度神經網路做預測之前,你首先要訓練神經網路。現在存在許多不同的神經網路訓練工具,TensorFlow 正迅速成為其中最熱門的選擇。近日,獨立開發者 Matthijs Hollemans 在 machinethink.net 的博客上發布了一篇講解如何在 iOS 系統上運行 TensorFlow 的深度長文教程,並開源了相關的代碼。機器之心對本文進行了編譯介紹。關於 TensorFlow 的更多資訊和教程,請參閱機器之心文章《谷歌召開首屆 TensorFlow 開發者大會,正式發布 TensorFlow 1.0》和《首屆 TensorFlow 開發者大會:值得關注的亮點都在這裡(附資源)》。

項目地址:https://github.com/hollance/TensorFlow-iOS-Example

你可以使用 TensorFlow 來訓練你的機器學習模型,並使用這些模型進行預測。訓練通常在強大的機器上或雲端完成,但是 TensorFlow 也可以在 iOS 上運行——儘管有一些限制。

在這篇博文中,我將解釋 TensorFlow 背後的思想,如何使用它來訓練一個簡單的分類器,以及如何將這個分類器放在你的 iOS 應用程序中。

我們將通過音頻和語音分析的性別識別數據集(Gender Recognition by Voice and Speech Analysis,https://www.kaggle.com/primaryobjects/voicegender)來學習如何將一段錄音識別為男性或女性的聲音。你可以在上面的 GitHub 地址找到此項目的源代碼。

什麼是 TensorFlow 以及為何我需要它?

TensorFlow 是一個用於構建計算圖(computational graph)以便進行機器學習的軟體庫。

許多其它的工具工作在更高的抽象層次上。以 Caffe 為例,你可以通過連接不同類型的「層(layer)」來設計神經網路。這和 iOS 中 BNNS 以及 MPSCNN 的功能類似。在 TenseFlow 中,你也可以使用這樣的層來工作,不過你還可以做得更深入,一直到構成你演算法的單個計算。

你可以將 TensorFlow 視為一個實現新機器學習演算法的工具包,而其它的深度學習工具則是為了使用其他人實現的那些演算法。

這並不意味著你總是要從頭開始構建一切。TensorFlow 附帶有可復用的構建塊的集合,而且還有其他庫(如 Keras)也在 TensorFlow 上提供了方便的模塊。

所以精通數學不是使用 TensorFlow 的一個要求,但如果你想成為頂尖專家,還是應該掌握。

基於 logistic 回歸的二值分類

在這篇博文中,我們將使用 logistic 回歸演算法創建一個分類器。是的,我們將從頭開始構建它。那就捲起袖子開始吧!

分類器接收一些輸入數據,然後告訴你該數據屬於哪個類別或類。對於這個項目,我們只有兩個類:男性或女性,因此我們是一個二值分類器(binary classifier)。

註:二值分類器是最簡單的分類器,但它使用的思路與可以區分數百或數千個不同的類的分類器相同。所以即使我們在本教程中並沒有做到真正的深度學習,但兩者也仍有很多共同之處。

我們將使用的輸入數據由 20 個數字組成,這些數字代表某人說話的特定錄音的各種聲學特性。稍後我會再解釋一下,其中包括音頻的頻率這樣的信息。

在下圖中,你可以看到這 20 個數字連接到一個叫做 sum 的小塊。根據分類器,這些連接具有不同的權重(weight),這對應於這 20 個數字中的每一個的重要程度。

這是 logistic 分類器工作方式的框圖:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

在 sum 塊內,由 x0 - x19 給出的輸入及其連接權重 w0 - w19 的權重被簡單的加在一起。這就是一個常規的點積:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

我們還在最後添加了一個所謂的偏置(bias)項 b。這只是另一個數字。

數組中的權重 w 和 b 的值是該分類器要學習的內容。訓練分類器就是找到 w 和 b 的正確數字的問題。最初,我們將所有的 w 和 b 設為零。經過多輪訓練,w 和 b 將包含一組數字,分類器可以用它們來分辨男性的語音和女性的語音。

為了將這個 sum 值轉換成 0 到 1 之間的概率值,我們採用 logistic sigmoid 函數:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這個公式可能看起來很嚇人,但它的作用很簡單:如果 sum 是一個大的正數,則該 sigmoid 函數返回 1,表示概率為 100%。如果 sum 是一個大的負數,則該 sigmoid 函數返回 0。所以對於大的正數或負數,我們可以得到一個有信心的「是」或「否」預測。

然而,如果 sum 接近 0,則該 sigmoid 函數給出的概率接近 50%,因為它對預測不能確信。當我們開始訓練該分類器時,初始預測將對半分,因為分類器還沒有學到任何東西,並且對結果沒有信心。但是我們訓練越多,概率越趨於 1 和 0,分類器變得越明確。

現在,y_pred 包含了預測結果,其概率表示的是該語音來自男性的概率。即如果超過 0.5(或 50%),我們認為該聲音是男性,否則是女性。

這就是使用 logistic 回歸進行二值分類的思想。分類器的輸入由描述音頻錄音的聲學特徵的 20 個數字組成,我們計算加權和並採用 sigmoid 函數,我們得到的輸出是說話人是男性的概率。

然而,我們仍然需要建立訓練該分類器的機制,所以現在我們來看看 TensorFlow。

在 TensorFlow 中實現該分類器

要在 TensorFlow 中使用該分類器,我們首先需要將其設計轉換為計算圖(computational graph)。計算圖由執行計算的節點和在這些節點之間流動的數據組成。

我們的 logistic 回歸的圖如下所示:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這與前面的圖表看起來有點不同,但是這是因為輸入 x 不再是 20 個獨立的數字,而是包含 20 個元素的向量。權重由矩陣 W 表示。因此,之前的點積被單個矩陣乘法替代了。

還有一個輸入 y。這用於訓練分類器並驗證其有效性。我們使用的數據集有 3,168 個錄音樣本,每個樣本我們也知道是男聲還是女聲。那些已知的結果(男性或女性)也被稱為數據集的標籤(label),而這就是我們將放在 y 中的。

為了訓練該分類器,我們將其中一個樣本載入到 x 中,並讓該圖做出預測:是男性還是女性?因為最初的權重都是零,所以分類器可能會做出錯誤的預測。我們需要一種方法來計算錯誤的程度——通過損失函數(loss function)。損失函數將預測結果 y_pred 與正確的結果 y 進行比較。

確定了訓練樣本的損失後,我們使用一種稱為反向傳播(backpropagation)的技術,反向通過計算圖來調整權重 W 和 b 到正確的方向。如果預測是男性,但正確的答案是女性,權重就會上下移動一點,使得下一次「女性」將更有可能成為該特定的輸入的結果。

該訓練過程在該數據集的所有樣本上一次又一次地重複,直到該圖確定了最佳權重集。隨著時間的推移,用來衡量預測錯誤的損失就會變得越來越低。

反向傳播是訓練這種計算圖的一種很好的技術,但是所涉及的數學可能有點棘手。而 TensorFlow 的炫酷之處就在於:由於我們將所有的「前向」操作都表示為了圖中的節點,因此其可以自動找出反向傳播的「反向」操作——你自己不必進行任何數學運算,很贊吧!

那麼什麼是張量呢?

在上面的圖中,數據從左到右流動,從輸入到輸出。這就是 TensorFlow 名稱中的「流(flow)」部分。但什麼是「張量(tensor)呢?

流經圖的所有數據都是以張量的形式存在的。張量只是一個 n 維數組的一個很酷的名字。我說過 W 是權重矩陣,但就 TensorFlow 而言,它實際上是一個二階張量(second-order tensor)——換句話說就是一個二維數組。

  • 標量數是零階張量

  • 向量是一階張量

  • 矩陣是二階張量

  • 三維數組是一個三階張量

  • 等……

這就是需要說明的一切。在卷積神經網路等深度學習方法中,你通常需要處理四維的張量,但是我們的 logistic 分類器要簡單得多,所以我們不會超出二階張量,或者說矩陣。

我還說過 x 是一個向量——或者說一個一階張量——但是我們將把它當作一個矩陣。同樣 y 也是如此。這使我們可以一次性計算整個數據集的損失。

單個樣本有 20 個數據元素。如果我們將所有 3,168 個樣本載入到 x 中,則 x 將成為一個 3168×20 矩陣。將 x 與 W 相乘後,結果 y_pred 為一個 3168×1 矩陣。也就是說,y_pred 對於數據集中的每個樣本都有一個預測。

通過用矩陣/張量表達我們的圖,我們可以一次性對許多樣本案例進行預測。

安裝 TensorFlow

好的,理論結束。現在讓我們把它付諸實踐。我們將使用 TensorFlow 與 Python。你的 Mac 可能已經安裝了一個 Python 版本,但它可能是一個舊版本。我在本教程中使用了 Python 3.6,所以最好你也安裝它。

使用 Homebrew 軟體包管理器安裝 Python 3.6 是最簡單的。如果你還沒有安裝 Homebrew 軟體,請先按照這些說明進行操作:https://brew.sh

然後打開一個終端,並鍵入以下命令來安裝最新版本的 Python:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

Python 自帶它自己的軟體包管理器 pip,我們將使用它來安裝我們需要的軟體包。從終端里,執行以下操作:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

除了 TensorFlow,我們還將安裝 NumPy、SciPy、pandas 和 scikit-learn:

  • NumPy 是一個使用 n 維數組的庫。聽起來很熟悉么?NumPy 不稱它們為張量,但是它們是一回事。TensorFlow Python API 構建在 NumPy 之上。

  • SciPy 是數值計算庫。它被其它一些軟體包所使用。

  • pandas 用於載入數據集並清理它們。

  • scikit-learn 在某種程度上是 TensorFlow 的競爭對手,因為它是一個機器學習庫。我們在我們的項目里使用它是因為它有一些方便的函數。由於 TensorFlow 和 scikit-learn 都使用 NumPy 數組,因此它們可以很好地協同工作。

你使用 TensorFlow 不一定需要 pandas 和 scikit-learn,但它們方便而且任何數據科學家的工具箱都可以有它。

這些包將被安裝在/usr/local/lib/python3.6/site-packages。這在如果你需要查看 TensorFlow 源代碼而網站上沒有相關文檔的情況下是很有用的。

註:pip 將為你的系統自動安裝最好的 TensorFlow 版本。如果要安裝其他版本,請參閱官方安裝說明(https://www.tensorflow.org/install)。你還可以從源代碼編譯 TensorFlow,當我們構建適用於 iOS 的 TensorFlow 時,我們會在稍後做一些這樣的事。

讓我們進行一個快速測試,以確保一切安裝正確。創建一個新的包含以下內容的文本文件 tryit.py:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

然後從終端運行此腳本:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

它將輸出有關 TensorFlow 正在運行的設備的一些調試信息(很可能是 CPU,但也可能是 GPU——如果您的 Mac 具有 NVIDIA GPU)。最後它應該輸出,

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這是兩個向量 a 和 b 的和。

你可能還會看到以下消息:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

如果發生這種情況,那就說明你的系統上安裝的 TensorFlow 版本對你的 CPU 而言不是最為合適的。解決此問題的一種方法是從源代碼編譯 TensorFlow:https://www.tensorflow.org/install/install_sources,因為這樣你可以配置所有選項。但到目前來說,如果你看到這些警告,也並不是什麼大不了的事情。

仔細觀察數據

要訓練一個分類器,你需要數據。

對於這個項目,我們使用 Kory Becker 的「Gender Recognition by Voice」數據集,這是我在 Kaggle 網站上找到的。

下載地址:https://www.kaggle.com/primaryobjects/voicegender

那麼你如何從音頻里識別語音?如果你下載了該數據集並查看 voice.csv 文件,你將只會看到一行又一行的數字:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

要意識到這不是實際的音頻數據,這是很重要的!相反,這些數字表示的是音頻的不同聲學特性。這些屬性(或特徵)是通過腳本從音頻中提取出來並轉換為此 CSV 文件的。對這個過程的解釋超出了本教程的範圍,但如果你有興趣,可以參考原始的 R 語言源代碼:https://github.com/primaryobjects/voice-gender

該數據集包含 3,168 個這樣的樣本(每個對應表格中的每一行),大約一半是男性說話者,一半是女性說話者。其中每個樣本有 20 個聲學特徵,比如:

  • 平均頻率(kHz)

  • 頻率的標準差

  • 音譜平坦度

  • 音譜熵

  • 峰度

  • 聲信號測量的最大基頻

  • 調製指數

  • 等等…

對於大多數這些,我不知道它們的意思,而且這也不是很重要。我們所關心的是,我們可以使用這些數據來訓練分類器,以便根據這些特徵來分辨男性和女性的聲音。

如果你想在應用程序中使用此分類器來分辨來自麥克風的音頻或錄音中說話人的性別,那麼你首先必須從音頻數據中提取這些聲學屬性。一旦你有這 20 個數值,你可以把它們提供給訓練好的分類器,而它會告訴你這個聲音是男性還是女性。所以我們的分類器不會直接在錄音上工作,而只是在從錄音中提取的特徵上工作。

註:此處可以很好地指出深度學習和更傳統的演算法(如 logistic 回歸)之間的區別。我們正在訓練的分類器不能學習非常複雜的事情,你需要通過在預處理步驟中從數據里提取特徵來幫助它。對於這個特定數據集來說,就是從音頻中提取聲學特徵。

關於深度學習的很酷的地方是,你可以訓練神經網路來學習如何讓它自己來提取這些聲學特徵。因此,深度學習系統可以將原始音頻作為輸入,提取其認為重要的聲學特徵,然後進行分類,而無需進行任何預處理。

創建訓練集和測試集

前面我提到我們通過以下方式訓練分類器:

1. 提供給它數據集中所有的樣本

2. 測量預測的錯誤程度

3. 根據損失調整權重

實際上我們不應該使用所有的數據進行訓練。我們需要將一部分數據(稱為測試集)分離出來,以便我們可以評估我們的分類器的效果。因此,我們將數據集分為兩部分:我們用於訓練分類器的訓練集,以及我們用來查看分類器的準確度的測試集。

為了將數據分成訓練集和測試集,我創建了一個名為 split_data.py 的 Python 腳本:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

一步一步來講,這個腳本是這樣工作的:

  1. 導入 NumPy 和 pandas 包。pandas 可以讓我們可以輕鬆載入 CSV 文件,並對數據進行預處理。

  2. 使用 pandas 將數據集從 voice.csv 載入到所謂的 dataframe 中。此對象的工作原理非常像電子表格或 SQL 表。

  3. label 列包含該數據集的標籤:樣本是男還是女。這裡我們將標籤提取到一個新的 NumPy 數組中。原始標籤是文本,但我們將其轉換為數字:1=男性,0=女性。(這些數字的分配是任意的——在二值分類器中,我們經常使用 1 來表示「正」類,或者說我們試圖檢測到的類)。

  4. 這個新的 labels 數組是一維數組,但是我們的 TensorFlow 腳本將會有一個 3,168 行的二維張量,其每行有一列。所以在這裡我們將該數組「重塑」成二維。這不會改變內存中的數據,只是改變從現在起 NumPy 解讀這些數據的方式。

  5. 一旦我們完成了 label 列,我們將其從 dataframe 中刪除,這樣我們便留下了用來描述該輸入的 20 個特徵。我們也將該 dataframe 轉換為了一個常規的 NumPy 數組。

  6. 我們使用 scikit-learn 的一個輔助函數將 data 和 labels 數組拆分成兩部分。這隨機地將基於 random_state 的數據集中的樣本進行重排,random_state 是隨機生成器的種子。這個種子是什麼無關緊要,但如果總是使用相同的種子,我們就可以創建一個可復現的實驗。

  7. 最後,以 NumPy 的二進位文件格式保存四個新的數組。我們現在就有了一個訓練集和一個測試集!

你可以對此腳本中的數據進行其它預處理(例如擴展特徵),使其具有零均值和相同的方差;但是我沒將其放在這個簡單的項目中。

從終端運行如下腳本:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這給了我們四個包含訓練樣本(X_train.npy)及其標籤(y_train.npy)和測試樣本(X_test.npy)及其標籤(y_test.npy)的新文件。

註:你可能會想知道為什麼一些變數名稱被大寫,為什麼別的沒有。在數學中,矩陣通常被寫成大寫字母而向量為小寫。在我們的腳本中,X 是矩陣,y 是向量。這樣的慣例在大量機器學習代碼中很常見。

構建計算圖

現在我們將數據整理好了,我們可以編寫一個用 TensorFlow 訓練 logistic 分類器的腳本。這個腳本叫做 train.py。為了節省空間,我不會在這裡展示整個腳本,你可以在 GitHub 上看到它。

同樣,我們首先導入我們需要的包。然後我們將訓練數據載入到兩個 NumPy 數組中:X_train 和 y_train。(我們不會在這個腳本中使用測試數據。)

手把手教你為iOS系統開發TensorFlow(附開源代碼)

現在我們可以創建我們的計算圖。首先我們為我們的輸入 x 和 y 定義所謂的佔位符(placeholder):

手把手教你為iOS系統開發TensorFlow(附開源代碼)

tf.name_scope(「...」)可用於將圖的不同部分分組到不同的範圍(scope),這樣可以更容易地了解圖。我們把 x 和 y 放在「input」範圍內。我們還給它們命名「x-input」和「y-input」,這樣我們稍後可以很容易地引用它們。

回想一下,每個輸入樣本就是一個 20 個元素的向量。每個樣本也有一個標籤(1 是男,0 是女)。我還提到,如果我們將所有的樣本合并成一個矩陣,我們可以一次性計算所有的數據。這就是為什麼 x 和 y 在這裡被定義為二維張量:x 的維度是 [None,20],y 的維度是 [None,1]。

None 意味著第一維度是靈活的而且尚不知道。對於訓練集,我們將把 2,217 個樣本放在 x 和 y 中;對於測試集,則是 951 個樣本。

現在,TensorFlow 知道我們的輸入是什麼,我們可以定義分類器的參數(parameter):

手把手教你為iOS系統開發TensorFlow(附開源代碼)

張量 W 包含分類器將要學習的權重(一個 20×1 矩陣,因為有 20 個輸入特徵和 1 個輸出),b 包含偏置值。這兩個被聲明為 TensorFlow 變數,這意味著它們可以通過反向傳播過程進行更新。

就緒之後,我們可以聲明在我們的 logistic 回歸分類器的核心位置的計算:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

其中 x 和 W 相乘,加上偏差 b,然後執行 logistic sigmoid。y_pred 的結果是由 x 中的特徵所描述的音頻數據的說話人是男性的概率。

註:上面的代碼行實際上並沒有計算任何東西——所有我們一直在做的是創建計算圖。這行代碼是簡單地將節點添加到圖中用於矩陣乘法(tf.matmul)、加法(+)和 Sigmoid 函數(tf.sigmoid)。一旦我們構建了整個圖,我們可以創建一個 TensorFlow 會話並在實際數據上運行它。

我們還沒有完成。為了訓練該模型,我們需要定義一個損失函數(loss function)。對於二值 logistic 回歸分類器,使用損失日誌 log loss 是有意義的,幸運的是 TensorFlow 有一個內置的 log_loss() 函數,可以避免我們寫出實際的數學公式:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

log_loss 圖節點以 y(我們當前正在查看的樣本的標籤)作為輸入,並將它們與我們的預測 y_pred 進行比較。這就產生了一個代表損失的數字。

當我們開始訓練時,對於所有的樣本,預測 y_pred 將為 0.5(即 50%的概率是男性),因為分類器不知道正確的答案應該是什麼。因此,以 -ln(0.5) 計算的初始損失為 0.693146。隨著訓練的進行,損失將越來越小。

計算損失的第二行增加了一些稱為 L2 正則化(L2 regularization)的東西。這樣做是為了防止過擬合,使得分類器無法確切地記憶訓練數據。在這裡,這不會是一個很大的問題,因為我們的分類器的「記憶」只包含 20 個權重值和一個偏置值。但是正則化是一種常見的機器學習技術,所以我以為我會包括它。

regularization 值是另一個佔位符:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

我們已經使用了佔位符來定義我們的輸入 x 和 y,但它們也可用於定義超參數(hyperparameter)。超參數可讓你配置模型和訓練方式。它們被稱為「超」參數,因為與常規參數 W 和 b 不同,它們不被模型學習——你必須自己將它們設置為適當的值。

learning_rate(學習率)超參數告訴優化器應該採取多大的步伐。優化器(optimizer)是執行反向傳播的:它以損失為輸入,並將其反饋到圖中,以確定更新權重和偏置的程度。有很多可能的優化器,我們將使用 ADAM:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這將在圖中創建一個名為 train_op 的節點。這是我們稍後將運行的節點,以便訓練分類器。

為了確定分類器的運行情況,我們將在訓練期間偶爾進行快照,並記數出訓練集中已經正確預測的樣本個數。訓練集上的準確性並不是分類器工作的良好指標,但是無論如何,它對跟蹤訓練是有用的——如果你正在進行訓練,並且訓練集上的預測準確性變得更糟,那麼一定是哪裡出現了問題!

我們定義一個圖節點來計算準確性:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

我們可以運行 accurary 節點來查看有多少樣本被正確預測。回想一下,y_pred 包含 0 到 1 之間的概率。通過做 tf.to_float(y_pred> 0.5),如果預測是女性,我們得到一個值 0,如果預測是男性,則得到 1。我們可以將其與 y 進行比較,y 中包含正確的值。那麼準確性就是正確的預測數除以預測的總數。

之後,我們還將在測試集上使用同一個 accuracy 節點,以了解分類器的真正效果。

多定義一個節點很有用。這一個節點用於對我們根本沒有任何標籤的數據進行預測:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

要在應用程序中使用此分類器,你要錄製一些話,分析它以提取 20 個聲學特徵,然後將其提供給分類器。因為這是新的數據,不是來自訓練集或測試集的數據,顯然不會有標籤。你只能將此新數據提供給分類器,並希望它預測正確的結果。這就是 inference(推理)節點所需要做的。

好的,之前那麼多工作僅僅就是為了創建計算圖。現在我們想在訓練集上實際訓練它。

訓練分類器

訓練通常是一個無限循環的過程。要訓練一個簡單的、功能稍微強大的 logistic 回歸分類器,一般一分鐘之內就能完成,但是如果要訓練一個性能優異的深度神經網路,可能需要花費幾個小時甚至幾天時間才能完成。

以下是「train.py」文件中訓練迴路的第一部分:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

首先,我們在 TensorFlow 中創建一個新的 session 對象。為了運行計算圖,你需要首先啟動會話(session)。調用 sess.run(init) 將 W 和 b 重置為 0。

我們也將此計算圖寫入到了一個文件。將我們剛才創建的所有節點序列化到文件/tmp/voice/graph.pb 中,稍後在測試集上運行分類器時,我們需要這個定義圖,我們也可以將這個訓練好的分類器放入 iOS 應用程序中。

在這個 while True 中,我們執行以下命令:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

首先,我們將訓練樣本隨機混洗——這一步很重要,因為你不希望這個分類器無意中學習到與樣本順序有關的信息。

接下來這一點很重要:我們告訴 session 去運行 train_op 結點,這將在計算圖上執行單次訓練。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

當你運行 sess.run() 時,你需要提供一個 feed_dict,feed_dict 是告訴你想佔位符(placeholder)結點中相應的輸入數據。

由於這是一個非常簡單的分類器,因此我們總是一次性地訓練整個訓練集。我們將 X_train,y_train 的訓練數據分別傳入佔位符 x,y 中。對於較大的數據集,你可以採用分批訓練的方法,比如以每批 100-1000 個樣例進行訓練。

這些都是我們需要做的。訓練是一個循環過程,因此 train_op 結點要運行很多很多次。在每一次迭代過程中,反向傳播機制就會使權重 W 和 b 做出微小的變化。多次訓練後,我們一般能得到權重的最優或較優值。

理解訓練的過程對於我們理解神經網路是非常有幫助的,所以我們將訓練過程的進度報告列印出來(本項目中,每 1000 步列印一次):

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這一次,我們不是運行 train_op 結點,而是其它結點:準確率(accuracy)和損失函數(loss)。我們使用了相同的 feed_dict,以便於在訓練集上計算準確率和損失函數。

正如我之前所說,在訓練集上表現高準確度的分類器並不一定在測試集上表現也很好。但是有一點很肯定,那就是你很希望看到準確率這個指標隨著訓練而不斷上升,損失函數值不斷減少。

我們很多時候都會保存一個檢查點(checkpoint)。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

將分類器學習到的 W 和 b 的值保存到一個 checkpoint 文件中,當我們想在測試集上運行該分類器的時候,我們將再次讀取 checkpoint 文件中的數據。checkpoint 文件保存在/tmp/voice/目錄下。

在終端輸入如下命令運行訓練腳本:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

輸出應該是像這樣的:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

一旦你看到損失函數停止下降時,保持等待,直到你看見*** SAVED MODEL ***的提示信息,然後在計算機上按下 Ctrl+C 停止訓練。使用我選擇的正則化參數和學習率,你應該看到在訓練集上的準確率大約為 97%,損失函數約為 0.157(如果你將正則化參數設置為 0,損失函數值將更小)。

分類器的表現如何?

訓練好分類器後,我們需要測試它在實際生活中的表現如何。那麼你就需要使用沒有用於訓練的數據來評估分類器,這就是為什麼我們將數據集分為訓練集合測試集。

我們創建了一個新的腳本 test.py,用於載入定義好的計算圖和測試集,最終計算出在測試集中的分類準確率。

註:測試準確率總是低於訓練準確率(本文為 97%),但是也不會低太多。如果你的分類器在測試集上準確率遠不及在訓練集上準確率,你的分類器很可能存在過擬合,這時你需要重新調整你的訓練程序。我們期望此分類器在測試集上的準確率達 95%,如果低於 90%,那麼就需要引起你的注意了。

像之前一樣,腳本中首先導入相關的包。包括使用 scikit-learn 中的 metrics 包來列印一些相關報告。當然,這次我們載入的是測試集而不是訓練集。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

為了計算測試集上的準確率,我們需要再次使用我們的計算圖,但這並不是使用整個計算圖,此處我們不需要使用 train_op 和 loss 結點。

我們可以再次手動構建此圖,但是由於我們已經保存在了 graph.pb 文件中,我們只需要載入它而已。代碼如下:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

TensorFlow 喜歡將其數據存儲為協議緩衝區文件(擴展名為.pb),因此我們使用一些幫助代碼來載入該文件,並將其作為圖形導入到會話中。

接下來,我們需要從 checkpoint 文件中載入訓練好的 W 和 b 值:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這就是為什麼我們將結點限制範圍並給它們相應的名字,所以我們只需要使用 get_tensor_by_name() 函數就能夠很方便地再次找到它們。如果你沒有為你的結點取上意義明確的名字。那麼你要找到它們就麻煩了。

我們也需要獲得一些結點的引用(references),特別是輸入 x,y 以及進行預測的結點。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

OK,目前為止,我們已經將計算圖載入到內存中。我們也已經載入好了先前分類器訓練好的 W 和 b。現在我們可以在測試集(以前未見過的數據集)中測試。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

使用 X_test 做預測,將預測值與標籤 y_test 做對比,驗證預測是否準確並計算準確率。

注意:這次在 feed_dict 中不需要指定正則化參數和學習速率。我們僅需要運行計算圖中的相關部分,不需要使用計算圖中的佔位符部分。我們也可以利用 scikit-learn 包來生產一些其它報告:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這次我們使用 inference 結點做預測。由於 inference 僅僅計算預測值而不檢查預測值的準確率,因此只需要向 feed_dict 傳入 x(不需要 y)。

運行此腳本,您應該看到類似如下的輸出:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

在測試集上的準確率幾乎達到了 96%,正如預期所說,測試集上的準確率要低於訓練集上的準確率。這意味著我們的訓練是相當成功的,我們的模型在未知數據上表現也很成功。這還不夠完美:在每 25 次預測中幾乎會犯錯一次。但是對於我們的目的而言,這已經很好了。

分類報告和混淆矩陣展示了被錯誤預測樣例的統計數據。從混淆矩陣來看,有 446 名女性被正確預測,有 28 名女性被誤認為男性;466 名男性被正確預測,11 名男性被誤認為女性。

這似乎該分類器在預測女性過程中更容易犯錯,來自分類報告的準確率/召回率也說明了相同的事實。

在 iOS 上構建 TensorFlow

現在,我們已經訓練了一個在測試集上表現很好的模型,讓我們建立一個簡單的利用該模型做預測的 iOS 應用程序。首先,我們將製作一個利用 TensorFlow C++庫的應用程序。在下一節中,我們將此模型用於 Metal 中作比較。

當然,這樣做既有好處也有壞處。壞消息是你必須從源構建 TensorFlow。實際上,它會變得更糟:你需要安裝 Java 來實現。好消息是這個過程相對較簡單。完整的指導說明你能在這裡(Full instructions are here (https://www.tensorflow.org/install/install_sources))找到,但是還需要以下幾個步驟(在 TensorFlow 1.0 上做測試)。

當然,你應該安裝好了 Xcode,並確保激活指向 Xcode 安裝的開發者目錄(如果你在安裝 Xcode 之前已經安裝好了 Homebrew,這可能會指向錯誤的位置,這種情況下,TensorFlow 將不會安裝成功。)

手把手教你為iOS系統開發TensorFlow(附開源代碼)

建立 TensorFlow 需要使用一款叫做 bazel 的工具,bazel 需要 Java JDK 8 支持。使用 Homebrew 很容易安裝你所需要的包:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

一旦你完成上述步驟,你需要克隆 TensorFlow 的 GitHub 倉庫。注意:將此保存在沒有空格的路徑中,否則 bazel 將拒絕構建 TensorFlow!我將此 GitHub 倉庫簡單地克隆到我的主目錄下:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

-b r1.0 標識符表示克隆 r1.0 分支。當然,你也可以隨時自由獲取最新的分支或主要分支。

注意:在 macOS Sierra 上,運行下面的配置腳本將會給出一些錯誤。我不得不以克隆主分支來代替。在 OS X El Capitan 上,r1.0 分支沒有錯誤。

完成克隆步驟後,你需要運行配置腳本。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這裡你可能會遇到一些的問題,我在此給出它們的答案:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

請指定 python 的位置,默認路徑是/usr/bin/python。因為我想使用 Python3.6 版本,因此路徑應為 /usr/local/bin/python3。如果你選擇默認選項,TensorFlow 將建立在 Python2.7 之上。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

請指定編譯期間需要使用的優化標識符,默認是-march=native。

只需按下回車確認即可。接下來的幾個問題選擇「n」代替「no」即可。

當他詢問要使用哪個 Python 庫的時候,請按下 Enter 選擇默認選項(這應該是 Python3.6 庫)。

剩下的幾個問題用「n」代替「no」來回答即可。現在腳本將下載一些依賴並為建立 TensorFlow 做準備。

建立靜態庫

構建 TensorFlow 有如下兩個選項:

1. 在 Mac 上,使用 bazel 工具

2. 在 iOS 上,使用 Makefile

我們想為 iOS 構建 TensorFlow,所以我們使用第二個選項。然而,我們也將需要構建一些與選項一有關的額外工具。

在 TensorFlow 的目錄下中執行以下腳本:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

首先下載幾個依賴,然後啟動構建程序。如果一切都順利的話,它將創建三個需要鏈接到你應用程序的靜態庫:libtensorflow-core.a,libprotobuf.a,libprotobuf-lite.a。

警告:建立這些庫需要花費一段時間:在我的 iMac 上,用了將近 20 多分鐘,在相對較老的 MacBook Pro 上,則花費了超過 3 個小時。在安裝過程中,你也可能會看到很多編譯警告信息,甚至錯誤信息。最簡單的處理方式:先忽略它們。

現在,我們還需要另外另個輔助安裝工具。在終端運行下面兩條命令:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

注意:這將需要花費 20 分鐘左右的時間,因為它是從頭開始構建 TensorFlow(此次使用 bazel);如果此過程中遇到麻煩,請參閱官方說明。

為 Mac 構建 TensorFlow

這一步是可選項,但是由於你已經安裝好了所有依賴環境,所以要為你的 Mac 建立 TensorFlow 一點兒也不困難。這創建了一個新的 pip 包,因此你不需要利用官方 TensorFlow 包進行安裝。

為什麼要這樣做呢?因為這樣你就可以創建一個具有自定義選項的 TensorFlow 版本。例如,當你在運行 train.py 文件時,如果你得到「The TensorFlow library wasn"t compiled to use SSE4.1 instructions」的警告信息時,你可以編譯一個能執行這些指令的 TensorFlow 版本。

要為 Mac 構建 TensorFlow,在終端運行運行下面的命令:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

「-march=native option」選項對 SSE, AVX, AVX2, FMA 等指令(如果這些指令能夠在你的 CPU 上可用的話)增加了支持。

然後安裝下面的包:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

更多詳細說明,請參考 TensorFlow 官網。

Freezing the graph

我們將建立的 iOS 應用程序將載入我們曾經訓練好的模型,並用此應用程序來做一些預測。

回憶一下,train.py 文件將計算圖的定義保存到了/tmp/voice/graph.pb 之中。很遺憾的是,你不能將此圖原樣地載入到 iOS 應用程序中。完整的計算圖包含某些不受 TensorFlow C++ API 的支持的操作。這就是為什麼我們需要使用兩個額外工具的原因。

freeze_graph 能將 graph.pb 文件和保存模型訓練好的超參數值 W 和 b 的 checkpoint 文件合并到一個文件中,它還能夠移除 iOS 不支持的任何操作。

在終端的 TensorFlow 的目錄下運行此工具:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這就在 /tmp/voice/frozen.pb 文件中創建了一個簡化圖,其中只包含到 y_pred 和 inference 的所有結點,它不包括用於訓練的結點。

使用 freeze_graph 的優勢在於它能夠將訓練好的權重粘貼到文件中,所以你不需要單獨載入它們: frozen.pb 包含了我們所需要的一切內容。

optimize_for_inference 工具將進一步簡化圖,它將 frozen.pb 文件作為輸入,寫入 /tmp/voice/inference.pb 文件作為輸出。這個輸出文件就是我們將要嵌入在 iOS 應用程序中的文件,使用如下命令運行此工具。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

iOS 應用程序

你可以在 VoiceTensorFlow 文件夾中的 github.com/hollance/TensorFlow-iOS-Example 中找到該 iOS 應用程序.

在 Xcode 中打開項目,你需要注意如下幾點:

  • 該應用程序是用面向對象的 C++語言寫成的,源文件後綴為.mm。這裡沒有用到 TensorFlow 的 Swift API,只用到了 C++。

  • inference.pb 已經存在於該項目中,你可以將自己的 inference.pb 版本複製到項目文件夾中。

  • 此應用程序連接到 Accelerate.framework 上。

  • 此應用程序與你編譯的靜態庫鏈接。

轉到項目設置屏幕並切換到構建設置選項卡。在其他鏈接器標識符下,你將看到以下內容:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

除非你的命名也是「matthijs」,否則你將需要用克隆的 TensorFlow 倉庫路徑來代替它。(注意 TensorFlow 出現兩次,因此文件夾名稱應該為 tensorflow / tensorflow / ...)

注意:你也可以將這三個.a 文件複製到項目文件夾中,然後你就不需要擔心路徑出錯的問題了。對於這個項目我不想這樣做,因為 libtensorflow-core.a 太大,是一個佔用 440MB 的庫。

然後檢查標題搜索路徑(**Header Search Paths**),它們當前位置是:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

最後,你必須將這些路徑更新到克隆倉庫的位置。

這裡還有一些設置,如下:

  • Enable Bitcode: No

  • Warnings / Documentation Comments: No

  • Warnings / Deprecated Functions: No

TensorFlow 當前不支持 Bitcode,所以我把它禁用了。我也關閉了警告,否則在你編譯應用程序時,你會遇到很多問題(你仍然將會收到幾個 Value Conversion Issue 警告,當然你也可以禁用這些警告,但我很喜歡這些警告信息)。

一旦你對其它鏈接器標誌(Other Linker Flags)和標題搜索路徑(Header Search Paths)做出更改後,你就可以建立並運行這個應用程序了。

很好,現在你已經有一個使用了 TensorFlow 的 iOS 應用程序!讓我看看看它是怎樣工作的。

使用 TensorFlow C++ API

iOS 上的 TensorFlow 是用 C++編寫的,但是你需要編寫的 C++代碼的程序是非常有限的!這一點你很幸運。通常你將執行以下一些操作:

1. 載入.pb 文件中的權重和圖;

2. 使用圖時先啟動會話;

3. 將你的輸入數據放入輸入張量;

4. 在一個或多個結點上運行計算圖;

5 得到輸出結點的輸出張量值,

在這個演示的應用程序中,這一切都在 ViewController.mm 文件中完成。首先,讓我們載入計算圖:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

Xcode 項目包括了 inference.pb 圖,它是由我們在 graph.pb 上運行 freeze_graph 和 optimize_for_inference 得到的。如果你試圖載入 graph.pb,你將得到一些錯誤信息:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

該 C++ API 支持的操作比 Python API 支持的操作少。在這裡,在我們損失函數結點的 L2Loss 操作在 iOS 上是不可用的。這就是為什麼我們使用 freeze_graph 來簡化我們的圖的原因。在載入圖後,我們開始啟動會話:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

一旦我們啟動了會話,我們就能夠利用它做一些預測。預測:將包含 20 個浮點數的數組作為作為聲學特徵傳入計算圖。

讓我們看看該方法是怎樣工作的:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

首先,我們定義輸入數據張量 x,該張量的形狀為 {1,20},即 1 個樣例,20 個特徵。然後將我們的數據從數組轉換成 TensorFlow 中的張量。

接下來,我們運行會話:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

使用如下類似 Python 中的代碼,看看發生了什麼:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這條命令並不那麼簡潔,我們創建了 feed_dict,結點矢量,以及保存結果的一個矢量。最後,我們告訴會話來做我們想做的事情。

一旦啟動會話,運行了結點,我們就能列印出結果:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

出於我們的目的,僅僅運行到 inference 結點就足夠了,但是我也想看看預測的準確率,所以我們也運行了 y_pred 結點。

運行應用程序

你可以在 iPhone 模擬器或其它設備上運行該應用程序。在模擬器上,你可能會再次接到「The TensorFlow library wasn"t compiled to use SSE4.1 instructions」的消息,但是在設備上,你不應該會接收到這些消息。

僅僅用於測試的目的,該應用程序將僅僅做出兩類預測:預測男性或女性。我們可以僅僅從測試集中隨機取出相應的數據來做預測。

運行該應用程序,你應該看到以下輸出。該應用程序首先列印出圖中的節點:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

注意:此圖僅僅包括了進行預測所需的操作,並沒有給出訓練信息。然後列印預測結果:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

如果你在 Python 腳本中嘗試相同的樣例,你將得到完全相同的答案。我們的任務終於完成了!

注意:對於這個演示項目,我們使用的數據僅僅是從測試集中抽取出來。如果你想使用該模型去處理實際音頻,那麼你需要將音頻轉換成 20 種聲學特徵。

iOS 行 TensorFlow 的優點和缺點

TensorFlow 是一款強大的用於訓練機器學習模型和實現新演算法的框架。為了訓練大模型,你甚至可以在雲端使用 TensorFlow。

本文除了講述如何訓練模型外,還展示了如何將 TensorFlow 添加到你的 iOS 應用程序中。在本節中,我想總結一下這樣做的優點與缺點。

iOS 上使用 TensorFlow 的優點:

  • 使用一個工具做所有事情。一方面,你可以使用 TensorFlow 訓練模型,也可以進行推理,這不需要將你的計算圖從 TensorFlow 移植到其他的 API,例如 BNNS 或 Metal 上;另一方面,你只需要將少部分的 Python 代碼換成 C++就能完成。

  • TensorFlow 比 BNNS 或 Metal 有更多的特色。

  • 使用 TensorFlow,你可以在模擬器上測試(Metal 通常需要在設備上運行)。

iOS 上 TensorFlow 的不足:

  • 目前還沒有 GPU 支持。TensorFlow 使用 Accelerate 框架來利用 CPU 矢量指令,速度不如在 Metal 上快。

  • TensorFlow 的 API 是 C++,所以你需要在面向對象的 C++中編寫代碼,你不能直接在 Swift 的編碼。

  • C++的 API 比 Python 的 API 更受限制。這意味著你不能在設備上訓練模型,因為目前不支持反向傳播過程中所需的自動梯度計算。目前這並不太重要,因為在移動設備硬體上訓練模型並不是主要需求。

  • TensorFlow 靜態庫約佔 40 MB 空間。你可以通過減少支持的操作數來減小佔用的空間,但這會帶來很大的麻煩。這還不包括你的模型的大小。

個人認為,我現在不提倡在 iOS 上使用 TensorFlow。目前優點還不足以戰勝缺點,但作為一款年輕的產品,誰知道它未來會怎樣呢?

注意:如果你決定在你的 iOS 應用程序中使用 TensorFlow,你應該意識到人們很容易從你的應用程序包中複製計算圖的.pb 文件,這很不安全。但這個問題並不是 TensorFlow 中所特有的,由於凍結圖文件(frozen graph file)包含了你的模型參數和計算圖定義,因此你可以由此進行逆向工程。如果你的模型相當具有競爭力,你可能需要找出某種方式避免它被剽竊。

使用 Metal,在 GPU 上訓練模型

在 iOS 應用程序中使用 TensorFlow 的一個缺點是不能使用 GPU。對於特定的項目,可能模型和數據都較小,TensorFlow 可能滿足我們的需求。然而,對於更大的模型,尤其是深度學習,你可能最好使用 GPU。在 iOS 上,就意味著使用 Metal。

你仍然可以在你的 Mac 上利用 TensorFlow 訓練模型,對於大模型你可以使用 GPU 甚至在雲端訓練,但在 iOS 上運行的推理代碼使用了 Metal,而不是 TensorFlow 庫。

訓練好之後,我們需要導出我們學習到的參數 W 和 b,將其轉換成 Metal 能夠讀取的某種格式。幸運的是,我們可以將它們保存為二進位格式的浮點數列表。

再花時間寫一個 Python 腳本 export_weights.py;它與 test.py 文件很相似,用於載入計算圖的定義和檢查點(checkpoint)。使用如下代碼:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

W.eval() 用於計算當前的 W 值,並以 NumPy 數組返回(這與 sess.run(W) 所做的事情一樣)。然後,我們使用 tofile() 將 Numpy 數組保存為二進位文件,這就是我們需要做的事情。

註:對於我們簡單的分類器,W 是一個 20 x 1 的矩陣,它僅包括了 20 個浮點數。對於更加複雜的模型,你模型的參數可能會是一個 4D 的張量。這種情況下,你將不得不對其中的一些維度做變換,因為 TensorFlow 中的數據存儲形式與 Metal 的數據存儲形式不一樣。這可以通過簡單的 tf.transpose() 命令來實現,但是這對於我們的分類器而言是不需要的。

讓我們看看我們 logistic 回歸的 Metal 版本。你可以在源代碼的 VoiceMetal 文件夾中找到這個 Xcode 項目,它是用 Swift 語言寫的。

logistic 回歸使用了如下公式計算:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這個公式與神經網路中的全連接層中所用的公式一樣,所以要用 Metal 實現我們的分類器,我們僅僅需要使用 MPSCNNFullyConnected 層。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

首先我們將 W.bin 和 b.bin 載入到 Data 對象中;

然後我們創建全連接層:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

由於輸入是 20 個數字,所以我決定使用一個全連接層來處理有 20 個通道的維度為 1 x 1 的「圖片」。預測結果 y_pred 是一個數值,所以全連接層僅使用一個輸出通道。

輸入和輸出數據被儲存在(與它們維度相同的)MPSImage 對象中。

手把手教你為iOS系統開發TensorFlow(附開源代碼)

與應用程序的 TensorFlow 版本一樣:對於每個樣本,預測方法以 20 個浮點數輸入。這是完整的方法定義:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

這是運行會話的 Metal 版本,convert(example:to:) 和 toFloatArray() 方法是載入數據和輸出 MPSImage 對象的幫助器。F

這就是 Metal 應用程序!您需要在設備上運行此應用程序,因為模擬器上不支持。運行時,它應該輸出以下內容:

手把手教你為iOS系統開發TensorFlow(附開源代碼)

註:這些概率與使用 TensorFlow 預測的概率不完全相同,因為 Metal 使用的是 16 位浮點數,但是最終結果很接近

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

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


請您繼續閱讀更多來自 機器之心 的精彩文章:

斯坦福大學Brainstorm神經形態晶元:未來計算的新方向
谷歌論文提出貝葉斯循環神經網路:優於傳統RNN(附開源項目)
機器之心深度研學社每周乾貨:2017-12

TAG:機器之心 |

您可能感興趣

開發者用ARKit把iPhone打造成HoloLens手柄
SE從《殺手》開發商IO Interactive撤出
Whole Foods 停止開發 watchOS 應用
FCA與BMW、Intel和Mobileye宣布聯手開發自動
GitHub開發者呼籲Adobe將Flash開源
VisualStudio插件開發
谷歌正為Chrome OS開發Android模擬器
TensorFlow+Docker我的DL開發環境,你的呢?
移動開發者福利:CodePush可在VS Mobile Center中使用
諾華聯手Conatus開發肝病新葯emricasan 加碼NASH研究
《殺手》系列開發商IO Interactive脫離SE,重新獨立
開發者福音:聯想公開Moto X Force內核源碼
Ready at Dawn結合Touch VR為VR遊戲開發出「虛擬手」
配置Fiori for iOS開發環境
Synopsys和Silicon Mobility日前宣布:推出Synopsys Virtualizer?開發工具包(VDK)
Theano s Dead!Bengio宣布停止Theano維護與開發
Android Wear鼓勵開發獨立手錶應用
維基解密:CIA開發「OutlawCountry」入侵Linux系統
安卓Kotlin開發系列之Java快速轉Kotlin