使用 TensorFlow 實現神經網路

原文連接:來自TalkingDataSDK技術博客

  • 介紹

      一直關注 數據科學機器學習 的同學,一定會經常看到或聽到關於 深度學習神經網路相關信息。如果你對 深度學習 感興趣,但卻還沒有實際動手操作過,你可以從這裡得到實踐。

     在本文中,我將介紹 TensorFlow , 幫你了解 神經網路 的實際作用,並使用 TensorFlow來解決現實生活中的問題。 讀這篇文章前,需要知道 神經網路 的基礎知識和一些編程理念,文章中的代碼是使用 Pyhton 編寫的,所以還需要了解一些 Python 的基本語法,才能更有利對於文章的理解。

    目錄

    • 什麼時候應用神經網路?
    • 通常神經網路能解決的問題
    • 了解圖像數據和主流的庫來解決問題
    • 什麼是 TensorFlow?
    • TensorFlow 一個 典型 的 「 流 」
    • 在 TensorFlow 中實現 MLP
    • TensorFlow 的限制
    • TensorFlow 與其他庫
    • 從這裡去哪裡?

    什麼時候用神經網路?

      神經網路 已經在相當一段時間成為機器學習中的焦點。 對於 神經網路 和 深度學習 上這裡有更詳細的解釋 點擊閱讀 。 其 「更深」 的功能在許多領域都有取得巨大的突破,如圖像識別,語音和自然語言處理等。

      主要的問題在於如何用好 神經網路 ?現在,每天都會有許多新發現,這個領域就像一個金礦,為了成為這個 「淘金熱」 的一部分,必須記住幾件事:

    • 首先,神經網路 需要有明確和翔實的數據(主要是大數據)訓練, 試著想像 神經網路 作為一個孩子,它一開始會觀察它父母走路,然後它試圖自己走,每一步就像學習執行一個特定的任務。 它可能會失敗幾次,但經過幾次失敗的嘗試,它將會如何走路。所以需要為孩子提供更多的機會,如果不讓它走,它可能永遠不會學習如何走路。

    • 一些人會利用 神經網路 解決複雜的問題,如圖像處理, 神經網路 屬於一類代表學習的演算法,這些演算法可以把複雜的問題分解為簡單的形式,使他們成為可以理解的(或 「可表示」),就像吞咽食物之前的咀嚼,讓我們更容易吸收和消化。這個分解的過程如果使用傳統的演算法來實現也可以,但是實現過程將會很困難。

    • 選擇適當類型的 神經網路 ,來解決問題, 每個問題的複雜情況都不一樣,所以數據決定你解決問題的方式。 例如,如果問題是序列生成的問題,遞歸神經網路 更合適。如果它是圖像相關的問題,想更好地解決可以採取 卷積神經網路。

    • 最後也是最重要的就是 硬體 要求了,硬體是運行 神經網路 模型的關鍵。 神經網被 「發現」 很久以前,他們在近年來得到推崇的主要的原因就是計算資源更好,能更大發揮它的光芒,如果你想使用 神經網路 解決這些現實生活中的問題,那麼你得準備購買一些高端的硬體了??!

    通常神經網路解決的問題

      神經網路是一種特殊類型的 機器學習(ML)演算法。 因此,作為每個 ML 演算法都遵循 數據預處理 、模型建立 和 模型評估 的工作流流程。為了簡明起見,下面列出了如何處理 神經網路 問題的 TODO 列表。

    • 檢查它是否為 神經網路 ,把它看成一個傳統的演算法問題
    • 做一個調查,哪個 神經網路 框架最適合解決這個問題
    • 定義 神經網路 框架,通過它選擇對應的 編程語言 和 庫
    • 將數據轉換為正確的格式並分批分割
    • 根據您的需要預處理數據
    • 增強數據以增加大小並製作更好的訓練模型
    • 批次供給到 神經網路
    • 訓練和監測,培訓和驗證數據集的變化
    • 測試你的模型,並保存以備將來使用

      本文將專註於圖像數據,我們從 TensorFlow 入手。

    了解圖像數據和主流的庫來解決問題

      圖像大多排列為 3-D 陣列,具體指 高度、寬度 和 顏色通道。例如,如果你使用電腦截屏,它將首先轉換成一個 3-D 數組,然後壓縮它為 『.jpeg』 或 『.png』 文件格式。

      雖然這些圖像對於人類來說很容易理解,但計算機很難理解它們。 這種現象稱為「語義空隙」。我們的大腦可以看看圖像,並在幾秒鐘內讀懂完整的圖片。但計算機會將圖像看作一個數字數組,問題來了,它想知道這是一張什麼樣的圖像,我們應該怎麼樣把圖像解釋給機器它才能讀懂?

      在早期,人們試圖將圖像分解為機器的 「可理解」 格式,如「模板」。例如,面部總是具有在每個人中有所保留的特定結構,例如眼睛,鼻子或我們的臉的形狀。 但是這種方法將是有缺陷的,因為當要識別的對象的數量將增加到一定量級時,「模板」 將不成立。

      2012年一個深層神經網路架構贏得了 ImageNet 的挑戰,從自然場景中識別對象,它在即將到來的 ImageNet 挑戰中繼續統治其主權,從而證明了解決圖像問題的有用性。 人們通常使用哪些 庫 / 語言 來解決圖像識別問題?最近的一次調查中,最流行的深度學習庫,支持的最友好的語言有 Python ,其次是 Lua ,對 Java 和 Matlab 支持的也有。最流行的庫舉幾個例子:

    • Caffe
    • DeepLearning4j
    • TensorFlow
    • Theano
    • Torch

    現在,我們了解了圖像的存儲方式以及使用的常用庫,讓我們看看 TensorFlow 提供的功能。

    什麼是 TensorFlow ?

    讓我們從官方定義開始.

      「TensorFlow 是一個開源軟體庫,用於使用數據流圖進行數值計算。圖中的節點表示數學運算,而圖邊表示在它們之間傳遞的多維數據陣列(也稱為張量)。 靈活的架構允許您使用單一 API 將計算部署到桌面、伺服器或移動設備中的一個或多個的 CPU 或 GPU 中。

      如果感覺這聽起來太高大上,不要擔心。這裡有我簡單的定義,TensorFlow 看起來沒什麼,只是 numpy 有些難以理解。如果你以前使用過 numpy ,理解 TensorFlow 將是手到擒來! numpy 和 TensorFlow 之間的主要區別是 TensorFlow 遵循惰性編程範例。 TensorFlow 的操作基本上都是對 session 的操作,它首先構建一個所有操作的圖形,當我們調用 session 時 TensorFlow 就開始工作了。它通過將內部數據表示轉換為張量(Tensor,也稱為多維數組)來構建為可擴展的。 構建計算圖可以被認為是 TensorFlow 的主要成分。想更多地了解一個計算圖形的數學結構,可以閱讀 這篇文章 。

      通過上面的介紹,很容易將 TensorFlow 分類為神經網路庫,但它不僅僅是如此。它被設計成一個強大的神經網路庫, 但它有能力做更多的事情。可以構建它為其他機器學習演算法,如 決策樹 或 k-最近鄰,你可以從字面上理解,你可以做一切你在 numpy 上能做的事情!我們暫且稱它為 「全能的 numpy」 。

    使用 TensorFlow 的優點是:

    • 它有一個直觀的結構 ,顧名思義它有 「張量流」,你可以輕鬆地可視每個圖中的每一個部分。
    • 輕鬆地在 cpu / gpu 上進行分散式計算
    • 平台的靈活性 。可以隨時隨地運行模型,無論是在移動端、伺服器還是 PC 上。

    TensorFlow 的典型 「流」

      每個庫都有自己的「實現細節」,即一種寫其遵循其編碼範例的方式。 例如,當實現 scikit-learn 時,首先創建所需演算法的對象,然後在訓練和測試集上構建一個模型獲得預測,如下所示:

    # define hyperparamters of ML algorithmclf = svm.SVC(gamma=0.001, C=100.)# train clf.fit(X, y)# test clf.predict(X_test)

    正如我前面所說,TensorFlow 遵循一種懶惰的方法。 在 TensorFlow 中運行程序的通常工作流程如下:

    • 建立一個計算圖, 任何的數學運算可以使用 TensorFlow 支撐。
    • 初始化變數, 編譯預先定義的變數
    • 創建 session, 這是神奇的開始的地方 !
    • 在 session 中運行圖, 編譯圖形被傳遞到 session ,它開始執行它。
    • 關閉 session, 結束這次使用。

    TensoFlow 中使用的術語很少

    placeholder:將數據輸入圖形的一種方法feed_dict:將數值傳遞到計算圖的字典

    讓我們寫一個小程序來添加兩個數字!

    # import tensorflowimport tensorflow as tf# build computational grapha = tf.placeholder(tf.int16)b = tf.placeholder(tf.int16)addition = tf.add(a, b)# initialize variablesinit = tf.initialize_all_variables()# create session and run the graphwith tf.Session() as sess: sess.run(init) print "Addition: %i" % sess.run(addition, feed_dict={a: 2, b: 3})# close sessionsess.close()

    在 TensorFlow 中實現神經網路

    注意:我們可以使用不同的神經網路體系結構來解決這個問題,但是為了簡單起見,我們在深入實施中討論 前饋多層感知器。

    讓我們記住對神經網路的了解。

    神經網路的典型實現如下:

    • 定義要編譯的神經網路體系結構
    • 將數據傳輸到模型
    • 整個運行中,數據首先被分成批次,以便它可以被攝取。首先對批次進行預處理,擴增,然後送入神經網路進行訓練
    • 然後,模型被逐步地訓練
    • 顯示特定數量的時間步長的精度
    • 訓練後保存模型供將來使用
    • 在新數據上測試模型並檢查其運行方式

    在這裡,我們解決了我們深刻的學習實踐中的問題 - [識別數字],讓再我們花一點時間看看問題陳述。

      我們的問題是圖像識別,以識別來自給定的 28×28 圖像的數字。 我們有一個圖像子集用於訓練,其餘的用於測試我們的模型。首先下載訓練和測試文件。數據集包含數據集中所有圖像的壓縮文件, train.csv 和 test.csv 都有相應的訓練和測試圖像的名稱。數據集中不提供任何其他功能,只是原始圖像以 「.png」 格式提供。

      如之前說的,我們將使用 TensorFlow 來創建一個神經網路模型。 所以首先在你的系統中安裝 TensorFlow 。 請參考 官方的安裝指南 進行安裝,按您的系統規格。

    我們將按照上述模板

    • 讓我們來 導入所有需要的模塊

    %pylab inlineimport osimport numpy as npimport pandas as pdfrom scipy.misc import imreadfrom sklearn.metrics import accuracy_scoreimport tensorflow as tf

    • 讓我們來 設置一個種子值,這樣我們就可以控制我們的模型隨機性

    # To stop potential randomnessseed = 128rng = np.random.RandomState(seed)

    • 第一步是設置目錄路徑,以便保管!

    root_dir = os.path.abspath(../..)data_dir = os.path.join(root_dir, data)sub_dir = os.path.join(root_dir, sub)# check for existenceos.path.exists(root_dir)os.path.exists(data_dir)os.path.exists(sub_dir)

    • 現在讓我們讀取我們的數據集,這些是 .csv 格式,並有一個文件名以及相應的標籤

    train = pd.read_csv(os.path.join(data_dir,Train,train.csv))test = pd.read_csv(os.path.join(data_dir,Test.csv))sample_submission = pd.read_csv(os.path.join(data_dir,Sample_Submission.csv))train.head()

    • 讓我們看看我們的數據是什麼樣子!我們讀取我們的形象並顯示出來。

    img_name = rng.choice(train.filename)filepath = os.path.join(data_dir, Train, Images, train, img_name)img = imread(filepath, flatten=True)pylab.imshow(img, cmap=gray)pylab.axis(off)pylab.show()

    上面的圖像表示為 numpy 數組,如下所示

    • 為了方便數據操作,讓我們 的存儲作為 numpy 的陣列的所有圖片

    temp = []for img_name in train.filename: image_path = os.path.join(data_dir, Train, Images, train, img_name) img = imread(image_path, flatten=True) img = img.astype(float32) temp.append(img) train_x = np.stack(temp)temp = []for img_name in test.filename: image_path = os.path.join(data_dir, Train, Images, test, img_name) img = imread(image_path, flatten=True) img = img.astype(float32) temp.append(img) test_x = np.stack(temp)

    • 由於這是典型的 ML 問題,為了測試我們的模型的正確功能,我們創建一個驗證集,讓我們以 70:30 的分割訓練集 和 驗證集

    split_size = int(train_x.shape[0]*0.7)train_x, val_x = train_x[:split_size], train_x[split_size:]train_y, val_y = train.label.values[:split_size], train.label.values[split_size:]

    • 我們定義一些輔助函數,我們稍後在我們的程序中使用

    def dense_to_one_hot(labels_dense, num_classes=10): """Convert class labels from scalars to one-hot vectors""" num_labels = labels_dense.shape[0] index_offset = np.arange(num_labels) * num_classes labels_one_hot = np.zeros((num_labels, num_classes)) labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 return labels_one_hotdef preproc(unclean_batch_x): """Convert values to range 0-1""" temp_batch = unclean_batch_x / unclean_batch_x.max() return temp_batchdef batch_creator(batch_size, dataset_length, dataset_name): """Create batch with random samples and return appropriate format""" batch_mask = rng.choice(dataset_length, batch_size) batch_x = eval(dataset_name + _x)[[batch_mask]].reshape(-1, 784) batch_x = preproc(batch_x) if dataset_name == train: batch_y = eval(dataset_name).ix[batch_mask, label].values batch_y = dense_to_one_hot(batch_y) return batch_x, batch_y

    • 主要部分! 讓我們定義我們的神經網路架構。 我們定義一個神經網路具有 3 層,輸入、隱藏 和 輸出, 輸入和輸出中的神經元數目是固定的,因為輸入是我們的 28×28 圖像,並且輸出是表示類的 10×1 向量。 我們在隱藏層中取 500 神經元。這個數字可以根據你的需要變化。我們把值 賦給 其餘變數。 可以閱讀 神經網路的基礎知識的文章 ,以更深的了解它是如何工作。

    ### set all variables# number of neurons in each layerinput_num_units = 28*28hidden_num_units = 500output_num_units = 10# define placeholdersx = tf.placeholder(tf.float32, [None, input_num_units])y = tf.placeholder(tf.float32, [None, output_num_units])# set remaining variablesepochs = 5batch_size = 128learning_rate = 0.01### define weights and biases of the neural network (refer this article if you dont understand the terminologies)weights = { hidden: tf.Variable(tf.random_normal([input_num_units, hidden_num_units], seed=seed)), output: tf.Variable(tf.random_normal([hidden_num_units, output_num_units], seed=seed))}biases = { hidden: tf.Variable(tf.random_normal([hidden_num_units], seed=seed)), output: tf.Variable(tf.random_normal([output_num_units], seed=seed))}

    • 現在創建我們的神經網路計算圖

    hidden_layer = tf.add(tf.matmul(x, weights[hidden]), biases[hidden])hidden_layer = tf.nn.relu(hidden_layer)output_layer = tf.matmul(hidden_layer, weights[output]) + biases[output]

    • 此外,我們需要定義神經網路的成本

    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output_layer, y))

    • 設置優化器,即我們的反向傳播演算法。 這裡我們使用 Adam ,這是梯度下降演算法的高效變體。 有在 tensorflow 可用許多其它優化(參照 此處 )

    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

    • 定義我們的神經網路結構後,讓我們來 初始化所有的變數

    init = tf.initialize_all_variables()

    • 現在讓我們創建一個 Session ,並在 Session 中運行我們的神經網路。我們還驗證我們創建的驗證集的模型準確性

    with tf.Session() as sess: # create initialized variables sess.run(init) ### for each epoch, do: ### for each batch, do: ### create pre-processed batch ### run optimizer by feeding batch ### find cost and reiterate to minimize for epoch in range(epochs): avg_cost = 0 total_batch = int(train.shape[0]/batch_size) for i in range(total_batch): batch_x, batch_y = batch_creator(batch_size, train_x.shape[0], train) _, c = sess.run([optimizer, cost], feed_dict = {x: batch_x, y: batch_y}) avg_cost += c / total_batch print "Epoch:", (epoch+1), "cost =", "{:.5f}".format(avg_cost) print "
    Training complete!" # find predictions on val set pred_temp = tf.equal(tf.argmax(output_layer, 1), tf.argmax(y, 1)) accuracy = tf.reduce_mean(tf.cast(pred_temp, "float")) print "Validation Accuracy:", accuracy.eval({x: val_x.reshape(-1, 784), y: dense_to_one_hot(val_y.values)}) predict = tf.argmax(output_layer, 1) pred = predict.eval({x: test_x.reshape(-1, 784)})

    這將是上面代碼的輸出

    Epoch: 1 cost = 8.93566Epoch: 2 cost = 1.82103Epoch: 3 cost = 0.98648Epoch: 4 cost = 0.57141Epoch: 5 cost = 0.44550Training complete!Validation Accuracy: 0.952823

    • 驗證我們自己的眼睛,讓我們來 想像它的預言

    img_name = rng.choice(test.filename)filepath = os.path.join(data_dir, Train, Images, test, img_name)img = imread(filepath, flatten=True) test_index = int(img_name.split(.)[0]) - 49000print "Prediction is: ", pred[test_index]pylab.imshow(img, cmap=gray)pylab.axis(off)pylab.show()

    Prediction is: 8

    • 我們看到的模型性能是相當不錯! 現在讓我們 創建一個提交

    sample_submission.filename = test.filename sample_submission.label = predsample_submission.to_csv(os.path.join(sub_dir, sub01.csv), index=False)

      終於完成了! 我們剛剛創建了自己的訓練神經網路!

    TensorFlow 的限制

    • 儘管 TensorFlow 是強大的,它仍然是一個低水平庫,例如,它可以被認為是機器級語言,但對於大多數功能,您需要自己去模塊化和高級介面,如 keras
    • 它仍然在繼續開發和維護,這是多麼??啊!
    • 它取決於你的硬體規格,配置越高越好
    • 不是所有變成語言能使用它的 API 。
    • TensorFlow 中仍然有很多庫需要手動導入,比如 OpenCL 支持。

    上面提到的大多數是在 TensorFlow 開發人員的願景,他們已經制定了一個路線圖,計劃庫未來應該如何開發。

    TensorFlow 與其他庫

      TensorFlow 建立在類似的原理,如使用數學計算圖表的 Theano 和 Torch,但是隨著分散式計算的額外支持,TensorFlow 更好地解決複雜的問題。 此外,TensorFlow 模型的部署已經被支持,這使得它更容易用於工業目的,打開一些商業的三方庫,如 Deeplearning4j ,H2O 和 Turi。 TensorFlow 有用於 Python,C ++ 和 Matlab 的 API 。 最近還出現了對 Ruby 和 R 等其他語言的支持。因此,TensorFlow 試圖獲得通用語言支持。

    從這裡去哪裡?

      以上你看到了如何用 TensorFlow 構建一個簡單的神經網路,這段代碼是為了讓人們了解如何開始實現 TensorFlow。 要解決更複雜的現實生活中的問題,你必須在這篇文章的基礎上在調整一些代碼才行。

      許多上述功能可以被抽象為給出無縫的端到端工作流,如果你使用 scikit-learn ,你可能知道一個高級庫如何抽象「底層」實現,給終端用戶一個更容易的界面。儘管 TensorFlow 已經提取了大多數實現,但是也有更高級的庫,如 TF-slim 和 TFlearn。

    參考資源

    • TensorFlow 官方庫
    • Rajat Monga(TensorFlow技術負責人) 「TensorFlow為大家」 的視頻
    • 一個專用資源的策劃列表

    關於原文

    感謝原文作者 Faizan Shaikh 的分享, 這篇文章是在 An Introduction to Implementing Neural Networks using TensorFlow 的基礎上做的翻譯和局部調整,如果發現翻譯中有不對或者歧義的的地方歡迎在下面評論里提問,我會加以修正 。

推薦閱讀:

學習筆記TF004:張量表示、類型、形狀、計算
NLP(2) Tensorflow 文本- 價格建模 Part2
深入淺出Tensorflow(五):循環神經網路簡介
GTX 1070 +CUDA 8.0 +cuDNN 5.1 + TensorFlow +Ubuntu 16.04 雙硬碟安裝記錄

TAG:TensorFlow | 機器學習 | 神經網路 |