華文網

用TensorFlow實現神經網路很難?看完這篇詳解,「小白」也秒懂!

圖:pixabay

作者:Faizan Shaikh

「機器人圈」編譯:嗯~阿童木呀、多啦A亮

「機器人圈」正式更名為「雷克世界」,

後臺回復「雷克世界」查看更多詳情。

如果你一直在關注資料科學/機器學習等相關領域,那麼你一定不會錯過有關深度學習和神經網路的任何動態。組織正在尋找一些深諳深度學習技能的人,無論他們將深度學習的知識用於何處。從開啟競爭到開源專案再到巨額獎金,人們正在試圖嘗盡一切辦法來挖掘這個領域有限的人才資源。

如果你對深度學習的發展前景充滿憧憬和期望,

但還不曾開始邁進這個領域,那麼,在這裡我將助你開啟旅程。

在本文中,我將介紹TensorFlow的相關知識。相信閱讀本文後,你將能夠瞭解神經網路的應用,並學會使用TensorFlow來解決現實生活中的問題。而在閱讀本文之前,要求你能夠瞭解神經網路的基礎知識,並熟悉程式設計。儘管這篇文章中的代碼是用Python編寫的,但我會將重點放在概念上,並盡可能保持所談論的內容與程式設計無關。

何時使用神經網路

眾所周知,到目前為止,神經網路成為人們關注的焦點已有很長一段時間了。如果還不是很瞭解,點選連結,這裡有有關神經網路和深度學習的更為詳盡的闡述。(https://www.analyticsvidhya.com/blog/2016/10/an-introduction-to-implementing-neural-networks-using-tensorflow/?utm_source=dzone&utm_medium=social)其中,它的“更深度”版本已然在諸如圖像識別、語音和自然語言處理等諸多領域取得了巨大的突破性進展。

而在神經網路的使用這有一個至關重要的問題出現了,

那就是“什麼時候應該使用神經網路?什麼時候不應該使用神經網路呢”?現如今,這個領域儼然就是一座金礦,每天都會有許多“寶藏”破土而出,而如果想要成為這個“淘金熱”的一部分,你必須注意幾點:

•首先,神經網路需要清晰且翔實的資料(主要是大資料)進行訓練。你可以試著將神經網路想像成一個孩子。在最初的時候,它首先要觀察其父母的走路方式,然後,

它試著自己走,一步一步地走下去,這個孩子就學會了如何去執行一項特定的任務。在這個過程中,它可能會跌倒幾次,但經過幾次失敗的嘗試之後,它就學會了如何走路。如果你不讓它嘗試著自己走,那麼它可能永遠也學不會如何走路。你為孩子提供的嘗試機會越多,它就會越來越好。

•對於諸如影像處理這樣的複雜問題,使用神經網路是一種需要很謹慎的行為。神經網路是隸屬於一種稱為表徵學習演算法(representation learning algorithms)的一類演算法。

這些演算法將複雜問題分解成更為簡單的形式,使其變得可以理解(或“可表徵”)。其實你可以把它想像成是在你吞咽食物之前咀嚼食物的行為。而這對於傳統演算法(非表徵學習)來說,將變得更加困難。

•當你認為有了適當的神經網路類型來解決問題時,殊不知每個問題都有自己的難點。而資料將決定你用以解決問題的方式。例如,如果是序列生成的問題,則選擇迴圈神經網路是最為合適的,而如果它是一個和圖像相關的問題,那麼你可能就需要做些改變,採用卷積神經網路才是一個合適的選擇。

如何使用神經網路解決問題

神經網路是一種特殊類型的機器學習(ML)演算法。因此,與每個ML演算法一樣,它遵循資料預處理,模型構建和模型評估的通用ML工作流。為了簡明起見,我列出了一個如何處理神經網路問題的待辦事項清單。

•檢查神經網路是否提升了傳統演算法(參考上述章節中的檢查列表)。

•做一項關於哪個神經網路架構最適合亟待解決問題的調查。

•通過你所選擇的語言/庫來定義神經網路架構。

•將資料轉換為正確的格式,並將其分為若干批量。

•根據需要對資料進行預處理。

•添加資料以增加大小並做出更好的訓練模型。

•將批量饋送到神經網路。

•訓練、監測訓練過程中的變化並驗證資料集。

•對模型進行測試並保存以備將來使用。

對於這篇文章,我將重點介紹圖像資料。在深入瞭解TensorFlow之前,需要首先對其有基本瞭解。

理解圖像資料及用以解決問題的流行庫

圖像大部分以三維陣列的形式排列,其中三維是指高度、寬度和顏色信號通道。例如,如果你在此刻拍攝個人電腦的螢幕截圖,則首先將其轉換成三維陣列,然後將其壓縮為PNG或JPG檔案格式。

監管這些圖像對於人類來說是很容易理解的,但對電腦來說就沒有那麼容易了。這種現象被稱為語義鴻溝(semantic gap)。我們的大腦可以在幾秒鐘內看到圖像,並對完整的圖像加以瞭解。而另一方面,電腦則將圖像視為一個陣列。所以問題是,我們該如何將這個圖像向機器加以解釋。

在早期,人們試圖將這種圖像分解為像一個“範本”一樣的機器 “可理解”的格式。例如,一張臉中總有一個特定的結構,它以某種形式在每個人身上保留下來,比如我眼睛和鼻子的位置,或者臉型。但是這種方法將會非常繁瑣,因為當要識別的目標數量增加時,“範本”就不存在了。

到了2012年,深度神經網路架構贏得了ImageNet挑戰賽,這是一個在從自然場景中識別目標領域的很有聲望的挑戰。後來在所有即將到來的ImageNet挑戰中,神經網路都佔據著主導地位,從而證明了其在解決圖像問題的有效性。

那麼人們通常會使用哪些庫/語言來解決圖像識別問題呢?最近的一項調查結果顯示,大多數受歡迎的深度學習庫都有一個Python介面,其次是Lua、Java和Matlab。下面是最受歡迎的庫中的一些代表:

•Caffe(http://caffe.berkeleyvision.org/)

•DeepLearning4j(https://deeplearning4j.org/)

•TensorFlow(https://www.tensorflow.org/)

•Theano(http://www.deeplearning.net/software/theano/)

•Torch(http://torch.ch/)

現在,你應該瞭解圖像是如何存儲的以及常用的公共庫有哪些了吧,下面請查看TensorFlow必須提供的內容有哪些。

什麼是TensorFlow?

下面是官方定義:

TensorFlow是一個開源軟體庫,用於使用資料流程圖形進行數值計算。圖中的節點表徵數學運算,而圖形邊緣表徵的是在它們之間傳遞的多維資料陣列(又稱張量)。靈活的體系結構使得你能夠將計算部署到桌面,伺服器或具有單個API的移動設備中的一個或多個CPU或GPU。

可能這聽起來有點嚇人,但不用擔心。這裡有一個簡單定義,僅需要把TensorFlow看作一種有著一些難點的numpy。如果你以前曾使用過numpy,那理解TensorFlow也只不過是小菜一碟了! numpy和TensorFlow之間的一個主要區別在於TensorFlow遵循懶惰(lazy)的程式設計範式。它首先會構建一個需要完成的所有操作的圖表,然後當“session”被調用時,它將“run”該圖表。它的構建是可擴展的,因為它是通過將內部資料表征更改為張量(也就是多維陣列)來實現的。構建計算圖表可以被認為是TensorFlow的主要成分。要想瞭解更多關於計算圖表的數學構成,請閱讀本文。(http://colah.github.io/posts/2015-08-Backprop/)

將TensorFlow分類為神經網路庫是一件很容易的事情,但它為並不僅僅如此。實質上來講它是被設計成一個強大的神經網路庫。但它所擁有的力量、能夠做的事情遠遠不止如此。你可以在其上構建其他機器學習演算法,如決策樹或k最近鄰演算法。你可以使用它來做一切你經常使用numpy來做的事情!它恰恰稱為“numpy on steroids”。

使用TensorFlow的優點是:

•它有一個直觀的結構,顧名思義,它有一個“張量流”。你可以很容易將圖表的每一部分視覺化。

•輕鬆地在CPU / GPU上進行分散式運算。

•平臺靈活性,你可以隨時隨地運行模型,無論是在移動設備,伺服器還是PC上。

TensorFlow的典型 “流”

每個庫都有自己的“實現細節”,即一種按照編碼範式編寫的方式。例如,當實現scikit-learn時,首先創建所需演算法的物件,然後在訓練集上建立一個模型,並對測試集進行預測,如下所示:

# define hyperparamters of ML algorithm

clf = svm.SVC(gamma=0.001, C=100.)

# train

clf.fit(X, y)

# test

clf.predict(X_test)

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

•建立一個計算圖,任何的數學運算可以使用TensorFlow支撐。

•初始化變數編譯預先定義的變數。

•創建session,這是神奇開始的地方 !

•在session中運行圖形,編譯圖形被傳遞到session,它開始執行操作。

•關閉session,結束這次使用。

TensorFlow 中使用的術語很少。

placeholder: A way to feed data into the graphs

feed_dict: A dictionary to pass numeric values to computational graph

讓我們寫一個小程式來添加兩個數位!

# import tensorflow

import tensorflow as tf

# build computational graph

a = tf.placeholder(tf.int16)

b = tf.placeholder(tf.int16)

addition = tf.add(a, b)

# initialize variables

init = tf.initialize_all_variables()

# create session and run the graph

with tf.Session() as sess:

sess.run(init)

print "Addition: %i" % sess.run(addition, feed_dict={a: 2, b: 3})

# close session

sess.close()

在TensorFlow中實現神經網路

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

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

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

•定義要編譯的神經網路架構

•將資料傳輸到模型

•在引擎蓋下,資料首先分成批次,以便可以獲取。批次首先進行預處理、增強,然後送入神經網路進行訓練。

•然後模型被逐步地訓練。

•顯示特定數量的時間步長的精度。

•訓練後保存模型供將來使用。

•在新資料上測試模型並檢查其執行情況。

在這裡,我們解決深度學習實踐問題,以用來識別數字。讓我們再花一點時間看看問題陳述。

我們的問題是圖像識別,以識別來自給定的 28×28 圖像的數位。 我們有一部分圖像用於訓練,其餘的用於測試模型。首先,下載訓練和測試檔。資料集包含資料集中所有圖像的壓縮檔,train.csv和test.csv都具有相應訓練和測試圖像的名稱。資料集中不提供任何其他功能,只是原始圖像以 “.png” 格式提供。

如你所知,我們將使用TensorFlow來構建神經網路模型。所以,你應該先在系統中安裝TensorFlow。根據你的系統規格,請參閱官方安裝指南(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/g3doc/get_started/os_setup.md)進行安裝。

我們將按照上述範本,使用Python 2.7內核創建Jupyter notebook ,並按照以下步驟操作。

導入所有必需的模組:

%pylab inline

import os

import numpy as np

import pandas as pd

from scipy.misc import imread

from sklearn.metrics import accuracy_score

import tensorflow as tf

設置種子值,以便我們可以控制模型的隨機性:

# To stop potential randomness

seed = 128

rng = 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 existence

os.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,

由於這是一個典型的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_hot

def preproc(unclean_batch_x):

"""Convert values to range 0-1"""

temp_batch = unclean_batch_x / unclean_batch_x.max()

return temp_batch

def 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, input_num_units)

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

現在是主要部分!讓我們來定義我們的神經網路架構。我們定義一個三層神經網路:輸入、隱藏和輸出。輸入和輸出中的神經元數量是固定的,因為輸入是我們的28x28圖像,輸出是代表類的10x1向量。我們在隱藏層中採集500個神經元。這個數位可以根據你的需要而變化。我們還為剩餘的變數賦值。閱讀文章以訪問完整的代碼(https://www.analyticsvidhya.com/blog/2016/10/an-introduction-to-implementing-neural-networks-using-tensorflow/?utm_source=dzone&utm_medium=social),並深入瞭解其工作原理。

### set all variables

# number of neurons in each layer

input_num_units = 28*28

hidden_num_units = 500

output_num_units = 10

# define placeholders

x = tf.placeholder(tf.float32, [None, input_num_units])

y = tf.placeholder(tf.float32, [None, output_num_units])

# set remaining variables

epochs = 5

batch_size = 128

learning_rate = 0.01

### define weights and biases of the neural network (refer this article if you don't 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 中可用許多其它優化(參照此處(https://www.tensorflow.org/versions/r0.11/api_docs/python/train.html#optimizers)。

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, input_num_units), y: dense_to_one_hot(val_y)})

predict = tf.argmax(output_layer, 1)

pred = predict.eval({x: test_x.reshape(-1, input_num_units)})

這將是上面代碼的輸出。

Epoch: 1 cost = 8.93566

Epoch: 2 cost = 1.82103

Epoch: 3 cost = 0.98648

Epoch: 4 cost = 0.57141

Epoch: 5 cost = 0.44550

Training 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]) - 49000

print "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 = pred

sample_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官方庫 https://github.com/tensorflow/tensorflow。

Rajat Monga(TensorFlow技術負責人) “TensorFlow為大家” 的視頻https://youtu.be/wmw8Bbb_eIE。

專門的資源列表:https://github.com/jtoy/awesome-tensorflow/#github-projects。

例如,如果是序列生成的問題,則選擇迴圈神經網路是最為合適的,而如果它是一個和圖像相關的問題,那麼你可能就需要做些改變,採用卷積神經網路才是一個合適的選擇。

如何使用神經網路解決問題

神經網路是一種特殊類型的機器學習(ML)演算法。因此,與每個ML演算法一樣,它遵循資料預處理,模型構建和模型評估的通用ML工作流。為了簡明起見,我列出了一個如何處理神經網路問題的待辦事項清單。

•檢查神經網路是否提升了傳統演算法(參考上述章節中的檢查列表)。

•做一項關於哪個神經網路架構最適合亟待解決問題的調查。

•通過你所選擇的語言/庫來定義神經網路架構。

•將資料轉換為正確的格式,並將其分為若干批量。

•根據需要對資料進行預處理。

•添加資料以增加大小並做出更好的訓練模型。

•將批量饋送到神經網路。

•訓練、監測訓練過程中的變化並驗證資料集。

•對模型進行測試並保存以備將來使用。

對於這篇文章,我將重點介紹圖像資料。在深入瞭解TensorFlow之前,需要首先對其有基本瞭解。

理解圖像資料及用以解決問題的流行庫

圖像大部分以三維陣列的形式排列,其中三維是指高度、寬度和顏色信號通道。例如,如果你在此刻拍攝個人電腦的螢幕截圖,則首先將其轉換成三維陣列,然後將其壓縮為PNG或JPG檔案格式。

監管這些圖像對於人類來說是很容易理解的,但對電腦來說就沒有那麼容易了。這種現象被稱為語義鴻溝(semantic gap)。我們的大腦可以在幾秒鐘內看到圖像,並對完整的圖像加以瞭解。而另一方面,電腦則將圖像視為一個陣列。所以問題是,我們該如何將這個圖像向機器加以解釋。

在早期,人們試圖將這種圖像分解為像一個“範本”一樣的機器 “可理解”的格式。例如,一張臉中總有一個特定的結構,它以某種形式在每個人身上保留下來,比如我眼睛和鼻子的位置,或者臉型。但是這種方法將會非常繁瑣,因為當要識別的目標數量增加時,“範本”就不存在了。

到了2012年,深度神經網路架構贏得了ImageNet挑戰賽,這是一個在從自然場景中識別目標領域的很有聲望的挑戰。後來在所有即將到來的ImageNet挑戰中,神經網路都佔據著主導地位,從而證明了其在解決圖像問題的有效性。

那麼人們通常會使用哪些庫/語言來解決圖像識別問題呢?最近的一項調查結果顯示,大多數受歡迎的深度學習庫都有一個Python介面,其次是Lua、Java和Matlab。下面是最受歡迎的庫中的一些代表:

•Caffe(http://caffe.berkeleyvision.org/)

•DeepLearning4j(https://deeplearning4j.org/)

•TensorFlow(https://www.tensorflow.org/)

•Theano(http://www.deeplearning.net/software/theano/)

•Torch(http://torch.ch/)

現在,你應該瞭解圖像是如何存儲的以及常用的公共庫有哪些了吧,下面請查看TensorFlow必須提供的內容有哪些。

什麼是TensorFlow?

下面是官方定義:

TensorFlow是一個開源軟體庫,用於使用資料流程圖形進行數值計算。圖中的節點表徵數學運算,而圖形邊緣表徵的是在它們之間傳遞的多維資料陣列(又稱張量)。靈活的體系結構使得你能夠將計算部署到桌面,伺服器或具有單個API的移動設備中的一個或多個CPU或GPU。

可能這聽起來有點嚇人,但不用擔心。這裡有一個簡單定義,僅需要把TensorFlow看作一種有著一些難點的numpy。如果你以前曾使用過numpy,那理解TensorFlow也只不過是小菜一碟了! numpy和TensorFlow之間的一個主要區別在於TensorFlow遵循懶惰(lazy)的程式設計範式。它首先會構建一個需要完成的所有操作的圖表,然後當“session”被調用時,它將“run”該圖表。它的構建是可擴展的,因為它是通過將內部資料表征更改為張量(也就是多維陣列)來實現的。構建計算圖表可以被認為是TensorFlow的主要成分。要想瞭解更多關於計算圖表的數學構成,請閱讀本文。(http://colah.github.io/posts/2015-08-Backprop/)

將TensorFlow分類為神經網路庫是一件很容易的事情,但它為並不僅僅如此。實質上來講它是被設計成一個強大的神經網路庫。但它所擁有的力量、能夠做的事情遠遠不止如此。你可以在其上構建其他機器學習演算法,如決策樹或k最近鄰演算法。你可以使用它來做一切你經常使用numpy來做的事情!它恰恰稱為“numpy on steroids”。

使用TensorFlow的優點是:

•它有一個直觀的結構,顧名思義,它有一個“張量流”。你可以很容易將圖表的每一部分視覺化。

•輕鬆地在CPU / GPU上進行分散式運算。

•平臺靈活性,你可以隨時隨地運行模型,無論是在移動設備,伺服器還是PC上。

TensorFlow的典型 “流”

每個庫都有自己的“實現細節”,即一種按照編碼範式編寫的方式。例如,當實現scikit-learn時,首先創建所需演算法的物件,然後在訓練集上建立一個模型,並對測試集進行預測,如下所示:

# define hyperparamters of ML algorithm

clf = svm.SVC(gamma=0.001, C=100.)

# train

clf.fit(X, y)

# test

clf.predict(X_test)

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

•建立一個計算圖,任何的數學運算可以使用TensorFlow支撐。

•初始化變數編譯預先定義的變數。

•創建session,這是神奇開始的地方 !

•在session中運行圖形,編譯圖形被傳遞到session,它開始執行操作。

•關閉session,結束這次使用。

TensorFlow 中使用的術語很少。

placeholder: A way to feed data into the graphs

feed_dict: A dictionary to pass numeric values to computational graph

讓我們寫一個小程式來添加兩個數位!

# import tensorflow

import tensorflow as tf

# build computational graph

a = tf.placeholder(tf.int16)

b = tf.placeholder(tf.int16)

addition = tf.add(a, b)

# initialize variables

init = tf.initialize_all_variables()

# create session and run the graph

with tf.Session() as sess:

sess.run(init)

print "Addition: %i" % sess.run(addition, feed_dict={a: 2, b: 3})

# close session

sess.close()

在TensorFlow中實現神經網路

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

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

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

•定義要編譯的神經網路架構

•將資料傳輸到模型

•在引擎蓋下,資料首先分成批次,以便可以獲取。批次首先進行預處理、增強,然後送入神經網路進行訓練。

•然後模型被逐步地訓練。

•顯示特定數量的時間步長的精度。

•訓練後保存模型供將來使用。

•在新資料上測試模型並檢查其執行情況。

在這裡,我們解決深度學習實踐問題,以用來識別數字。讓我們再花一點時間看看問題陳述。

我們的問題是圖像識別,以識別來自給定的 28×28 圖像的數位。 我們有一部分圖像用於訓練,其餘的用於測試模型。首先,下載訓練和測試檔。資料集包含資料集中所有圖像的壓縮檔,train.csv和test.csv都具有相應訓練和測試圖像的名稱。資料集中不提供任何其他功能,只是原始圖像以 “.png” 格式提供。

如你所知,我們將使用TensorFlow來構建神經網路模型。所以,你應該先在系統中安裝TensorFlow。根據你的系統規格,請參閱官方安裝指南(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/g3doc/get_started/os_setup.md)進行安裝。

我們將按照上述範本,使用Python 2.7內核創建Jupyter notebook ,並按照以下步驟操作。

導入所有必需的模組:

%pylab inline

import os

import numpy as np

import pandas as pd

from scipy.misc import imread

from sklearn.metrics import accuracy_score

import tensorflow as tf

設置種子值,以便我們可以控制模型的隨機性:

# To stop potential randomness

seed = 128

rng = 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 existence

os.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,

由於這是一個典型的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_hot

def preproc(unclean_batch_x):

"""Convert values to range 0-1"""

temp_batch = unclean_batch_x / unclean_batch_x.max()

return temp_batch

def 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, input_num_units)

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

現在是主要部分!讓我們來定義我們的神經網路架構。我們定義一個三層神經網路:輸入、隱藏和輸出。輸入和輸出中的神經元數量是固定的,因為輸入是我們的28x28圖像,輸出是代表類的10x1向量。我們在隱藏層中採集500個神經元。這個數位可以根據你的需要而變化。我們還為剩餘的變數賦值。閱讀文章以訪問完整的代碼(https://www.analyticsvidhya.com/blog/2016/10/an-introduction-to-implementing-neural-networks-using-tensorflow/?utm_source=dzone&utm_medium=social),並深入瞭解其工作原理。

### set all variables

# number of neurons in each layer

input_num_units = 28*28

hidden_num_units = 500

output_num_units = 10

# define placeholders

x = tf.placeholder(tf.float32, [None, input_num_units])

y = tf.placeholder(tf.float32, [None, output_num_units])

# set remaining variables

epochs = 5

batch_size = 128

learning_rate = 0.01

### define weights and biases of the neural network (refer this article if you don't 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 中可用許多其它優化(參照此處(https://www.tensorflow.org/versions/r0.11/api_docs/python/train.html#optimizers)。

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, input_num_units), y: dense_to_one_hot(val_y)})

predict = tf.argmax(output_layer, 1)

pred = predict.eval({x: test_x.reshape(-1, input_num_units)})

這將是上面代碼的輸出。

Epoch: 1 cost = 8.93566

Epoch: 2 cost = 1.82103

Epoch: 3 cost = 0.98648

Epoch: 4 cost = 0.57141

Epoch: 5 cost = 0.44550

Training 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]) - 49000

print "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 = pred

sample_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官方庫 https://github.com/tensorflow/tensorflow。

Rajat Monga(TensorFlow技術負責人) “TensorFlow為大家” 的視頻https://youtu.be/wmw8Bbb_eIE。

專門的資源列表:https://github.com/jtoy/awesome-tensorflow/#github-projects。