點擊上方「CVer」,選擇「置頂公眾號」
重磅乾貨,第一時間送達
[TensorFlow從入門到精通] 01 簡單線性模型(上)介紹了TensorFlow如何加載MNIST、定義數據維度、TensorFlow圖、佔位符變量和One-Hot Encoding等知識點.
作者: Magnus Erik Hvass Pedersen
編輯: Amusi
校稿: Amusi
前些天,Amusi整理了一份重磅 | TensorFlow學習資料最全集錦,裡面包含TensorFlow相關的書籍、視頻和在線學習網站等資料。
其中,Amusi很喜歡 Magnus Erik Hvass Pedersen大佬製作的TensorFlow Tutorials 課程。該課程提供視頻教程(在YouTube上,需要翻牆觀看),並在github上發布了源碼。為此,Amusi決定推出【TensorFlow從入門到精通】系列文章,詳情請看TensorFlow從入門到精通 | 預告篇Amusi 曾經也學過一點 TensorFlow的知識,但覺得不夠系統,所以覺得按部就班的將TensorFlow Tutorials學習一遍。日常整理的翻譯和筆記都會同步發布到 TensorFlow-From-Zero-to-One 上。點擊文末的「閱讀全文」,即可查看。介紹
本教程介紹了使用TensorFlow實現簡單線性模型的workflow。在加載MNISIT(手寫字符圖像數據集)後,我們使用TensorFlow定義並優化一個簡單的數學模型。然後繪製並討論結果。
你應該熟悉基本的線性代數,Python,Jupyter Notebook編輯器。如果你對機器學習和分類有基本的了解,這也會幫助到你。
導入必要庫(Imports)
1%matplotlib inline
2import matplotlib.pyplot as plt
3import tensorflow as tf
4import numpy as np
5from sklearn.metrics import confusion_matrix
6}
大家可能會對上述代碼中的第一句 %matplotlib inline有所好奇,該語句怎麼是這樣的?其作用是什麼?
這裡Amusi引出兩種介紹,第一種是根本性解釋,第二種是適用於此代碼的解釋。
第一種解釋[1]:
%matplotlib inline 是一個魔法函數(Magic Functions)。官方給出的定義是:IPython有一組預先定義好的所謂的魔法函數(Magic Functions),你可以通過命令行的語法形式來訪問它們。可見「%matplotlib inline」就是模仿命令行來訪問magic函數的在IPython中獨有的形式。
magic函數分兩種:一種是面向行的,另一種是面向單元型的。
行magic函數是用前綴「%」標註的,很像我們在系統中使用命令行時的形式,例如在Mac中就是你的用戶名後面跟著「$」。「%」後面就是magic函數的參數了,但是它的參數是沒有被寫在括號或者引號中來傳值的。
單元型magic函數是由兩個「%%」做前綴的,它的參數不僅是當前「%%」行後面的內容,也包括了在當前行以下的行。
注意:既然是IPython的內置magic函數,那麼在Pycharm中是不會支持的。
總結:%matplotlib inline 可以在Ipython編譯器裡直接使用,功能是可以內嵌繪圖,並且可以省略掉plt.show()這一步。
第二種解釋[2]:
%matplotlib inline比較奇怪,而且無論你是用哪個python的IDE如spyder或者pycharm,這個地方都會報錯,顯示是invalid syntax(無效語法)。那為什麼代碼裡面還是會有這一句呢?原來是這樣的。 %matplotlib作用
是在使用jupyter notebook 或者 jupyter qtconsole的時候,才會經常用到%matplotlib,也就是說那一份代碼可能就是別人使用jupyter notebook 或者 jupyter qtconsole進行編輯的。關於jupyter notebook是什麼,可以參考這個連結:[Jupyter Notebook介紹、安裝及使用教程][1] 而%matplotlib具體作用是當你調用matplotlib.pyplot的繪圖函數plot()進行繪圖的時候,或者生成一個figure畫布的時候,可以直接在你的python console裡面生成圖像。 而我們在spyder或者pycharm實際運行代碼的時候,可以直接注釋掉這一句,也是可以運行成功的。如下示例:
Amusi 總結:
為了在Jupyter Notebook中使用matplotlib.pyplot的plot函數,即實現內嵌繪圖,而需要加上%matplotlib inline
參考:
[1]:https://blog.csdn.net/liangzuojiayi/article/details/78183783?locationNum=8&fps=1
[2]:https://www.jianshu.com/p/2dda5bb8ce7d
加載數據(Load Data)
如果在給定路徑下,沒有MNIST數據集,那麼程序會自動下載該數據集(大約11MB)
The MNIST data-set is about 11 MB and will be downloaded automatically if it is not located in the given path.
1from tensorflow.examples.tutorials.mnist import input_data
2data = input_data.read_data_sets("data/MNIST/", one_hot=True)
現在 MNIST數據集已經加載好,該數據集包含70,000幅圖像和標籤(即圖像的類別)。數據集被分成3個互不交叉的子集(訓練集、測試集和驗證集),在本教程中,我們將只使用訓練集和測試集。
其中:
1print("Size of:")
2print("- Training-set:\t\t{}".format(len(data.train.labels)))
3print("- Test-set:\t\t{}".format(len(data.test.labels)))
4print("- Validation-set:\t{}".format(len(data.validation.labels)))
Size of:- Training-set: 55000- Test-set: 10000- Validation-set: 5000
獨熱編碼(One-Hot Encoding)MNIST數據集由One-hot encoding方式加載。這意味著標籤由單個數字(類別)轉換成一個向量,其長度等價於可能類別數量(如有10類,則長度為10)。向量的所有元素除了第i個元素為 1之外(因為該標籤的類別是i),其它元素都為0。
1
2data.test.labels[0:5, :]
輸出:
array([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])
我們還需要將類(classes)作為單個數字進行各種比較和性能測量,因此我們通過獲取最高元素(其值為1)的索引來將One-Hot編碼向量轉換為單個數字。請注意,'class'這個詞是Python中使用的關鍵字,因此我們需要使用名稱'cls'。
1
2data.test.cls = np.array([label.argmax() for label in data.test.labels])
上面代碼,我們使用了numpy的argmax()函數。該函數的作用是:Returns the indices of the maximum values along an axis。因為類別向量中只有1是最大值,而1所在的索引位置就是我們所要的值。argmax()正好完美適用!
現在我們可以知道測試集中前5幅圖像的類別。你可以將其與上述One-Hot編碼向量進行比較。例如,第一幅圖像的類是7,其對應於One-Hot編碼向量中索引為7的元素,該元素值為1。
輸出:
array([7, 2, 1, 0, 4], dtype=int64)
數據維度會在下面的代碼中被使用。在計算機編程中,最好使用使用變量(variables)和常量(constants),而不是每次使用該編號時候都必須對特定數字進行硬編碼(hard-code)。這意味著數字只需要在一個地方被修改。理想情況下,這些數據可以從已經讀取的數據中推斷(inferred)出來,但在這裡我們只是寫出數字。
1
2img_size = 28
3
4
5img_size_flat = img_size * img_size
6
7
8img_shape = (img_size, img_size)
9
10
11num_classes = 10
函數使用3x3網格繪製9幅圖像,並在每幅圖像下面顯示真實正確的類別和預測的類別。
1def plot_images(images, cls_true, cls_pred=None):
2
3 assert len(images) == len(cls_true) == 9
4
5
6 fig, axes = plt.subplots(3, 3)
7 fig.subplots_adjust(hspace=0.3, wspace=0.3)
8
9 for i, ax in enumerate(axes.flat):
10
11 ax.imshow(images[i].reshape(img_shape), cmap='binary')
12
13
14 if cls_pred is None:
15 xlabel = "True: {0}".format(cls_true[i])
16 else:
17 xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i])
18
19 ax.set_xlabel(xlabel)
20
21
22 ax.set_xticks([])
23 ax.set_yticks([])
24
25
26 plt.show()
1
2images = data.test.images[0:9]
3
4
5cls_true = data.test.cls[0:9]
6
7
8plot_images(images=images, cls_true=cls_true)
TensorFlow 的目的是實現一個計算圖(computational graph),與直接在Python中執行的計算相比,其可以更有效的執行。TensorFlow可以比Numpy更有效,因為TensorFlow知道必須執行的整個計算圖,而Numpy一次只知道單個數學運算的計算。
TensorFlow 還可以自動計算優化圖中變量所需的梯度,以使得模型更好地運行。這是因為圖(Graph)是簡單數學表達式的組合,因此可以使用微分(derivatives)的鏈式法則(chain-rule)來計算整個圖的梯度。
TensorFlow 還可以利用多核CPU和GPU的,而且Google甚至為TensorFlow研發了專用晶片,稱為TPU(Tensor Processing Units),甚至比GPU更快。
TensorFlow圖由以下部分組成,將在下面詳述:
佔位符(Placeholder)變量用於改變圖的輸入
模型變量將進行優化,以使模型表現更好
模型本質上是數學函數,它很具佔位符變量和模型變量的輸入計算一些輸出
一種指導變量優化的代價度量(cost measure)
一種更新模型變量的優化方法
此外,TensorFlow圖還可以包含各種調試語句,例如:可以由TensorBoard可視化的日誌數據(本教程沒有介紹)
佔位符變量(Placeholder variables)佔位符變量(Placeholder variables)作為圖的輸入,我們可以在每次執行圖的時候進行更改。我們稱之為 餵(feeding)佔位符變量,並在下面進一步說明。
首先,我們定義輸入圖像的佔位符變量『x』。這允許我們改變輸入到TensorFlow圖的圖像。這是一個所謂的張量(tensor),這意味著它是一個多維向量或矩陣。該佔位符的數據類型設置成『float32』,形狀設置成『[None, img_size_flat]』,其中『None』表示張量可以存儲(hold)任意數量的圖像,每個圖像是長度為『img_size_flat』的向量。
1x = tf.placeholder(tf.float32, [None, img_size_flat])
接下來,我們定義佔位符變量『y_true』,其是存放與佔位符『x』中輸入圖像相關聯的真實標籤。該佔位符變量的數據類型設置成『float32』,形狀是『[None, num_classes]』,這意味著它可以包含任意數量的標籤,每個標籤是長度為『num_classes』的向量,在這種情況下為10。
1y_true = tf.placeholder(tf.float32, [None, num_classes])
最後,我們定義佔位符變量『y_true_cls』,其實存放與佔位符『x』中輸入圖像相關的類別。該佔位符的數據類型設置成『int64』,形狀設置為『[None]』,這意味著該佔位符變量是任意長度的一維向量。
1y_true_cls = tf.placeholder(tf.int64, [None])
除了上面定義用作將輸入數據輸入到模型中的佔位符變量之外,還有一些模型變量必須由TensorFlow進行更改,以使模型在訓練數據上表現更好。
必須優化的第一個變量稱為「權重(weights)」,在這裡定義為TensorFlow變量,必須用零初始化,形狀為[img_size_flat,num_classes],因此它是具有img_size_flat行和num_classes列的二維張量(或矩陣) 。
1
2weights = tf.Variable(tf.zeros([img_size_flat, num_classes]))
第二個必須要優化的變量稱為「偏置(biases)」,其實長度為『num_classes』的一維度張量(或向量)。這裡也初始化為零。
1biasesbiases == tftf..VariableVariable(tf.zeros([num_classes]))
簡單的數學模型是將佔位符變量『x』乘以權重『weights』,並加上偏置『biases』
根據矩陣性質,輸出結果是形狀為『[num_images, num_classes]』的矩陣。因為『x』的形狀為『[num_images, img_size_flat]』,『weights』的形狀為『[img_size_flat, num_classes]』,所以這兩個矩陣相乘的結果是形狀為『[num_images, num_classes]』的矩陣。然後將『biases』向量加到矩陣的每一行上(利用廣播的特性)。
注意:名稱『logits』是典型的TensorFlow術語(terminogy),但你也可以叫做其它變量。
1logits = tf.matmul(x, weights) + biases
現在logits是一個帶有num_images行和num_classes列的矩陣,其中第 i 行和第 j 列的元素是對第 i 幅輸入圖像估計為第 j 類的可能性(概率值)。
然而,這些估計是大概的(rough)值且難以解釋,因為這些數字可能非常小或很大,所以我們想對它們進行歸一化處理,以使logits矩陣的每一行總和為1(因為概率值和為1),並且每個元素被限制在[0,1]。這是使用所謂的softmax函數(又稱歸一化指數函數)計算的,結果存儲在y_pred中。
註:附上Softmax相關資源(點擊閱讀全文即可查看)
[1] Softmax function wiki
[2] Softmax 函數的特點和作用是什麼?
[3] Softmax回歸
1y_pred = tf.nn.softmax(logits)
可以通過獲取 y_pred矩陣中每行中最大元素的索引計算預測的類別 y_pred_cls。
1y_pred_cls = tf.argmax(y_pred, axis=1)
限於篇幅過大,便將【TensorFlow從入門到精通】01 簡單線性模型內容分成上篇和下篇來介紹。
預告下篇將介紹代價函數、優化器、衡量指標、TensorFlow會話(Session)、變量初始化等知識點。
若大家對 底部廣告 不反感的話
歡迎主動點擊一下文末的廣告,
這是對Amusi 最大的鼓勵!
若喜歡Amusi推送的文章,請掃描下方二維碼關注CVer公眾號!
若大家對 底部廣告 不反感的話
歡迎主動點擊一下文末的廣告,
這是對Amusi 最大的鼓勵!