[譯]TensorFlow Tutorial #01 Simple Linear Model
TensorFlow-Tutorials%2Fblob%2Fmaster%2F01_Simple_Linear_Model.ipynb" rel="nofollow,noindex">原文地址
本教程演示了使用TensorFlow和簡單線性模型的基本工作流程。 在使用手寫數字影象載入所謂的MNIST資料集之後,我們在TensorFlow中定義並優化了一個簡單的數學模型。 然後繪製並討論結果。
您應該熟悉基本的線性代數,Python和Jupyter Notebook編輯器。 如果您對機器學習和分類有基本的瞭解,它也會有所幫助。
#Imports
%matplotlib inline import matplotlib.pyplot as plt import tensorflow as tf import numpy as np from sklearn.metrics import confusion_matrix 複製程式碼
#Load Data
MNIST資料集大約為12 MB,如果它不在給定路徑中,將自動下載。
from mnist import MNIST data = MNIST(data_dir="data/MNIST/") 複製程式碼
MNIST資料集現已載入,由70,000個影象和影象的類號組成。 資料集被分成3個互斥的子集。 我們將僅使用本教程中的培訓和測試集。
print("Size of:") print("- Training-set:\t\t{}".format(data.num_train)) print("- Validation-set:\t{}".format(data.num_val)) print("- Test-set:\t\t{}".format(data.num_test)) Size of: - Training-set:55000 - Validation-set:5000 - Test-set:10000 複製程式碼
為方便起見,複製一些資料維度。
# The images are stored in one-dimensional arrays of this length. img_size_flat = data.img_size_flat # Tuple with height and width of images used to reshape arrays. img_shape = data.img_shape # Number of classes, one class for each of 10 digits. num_classes = data.num_classes 複製程式碼
#One-Hot Encoding
輸出資料作為整數類數和所謂的One-Hot編碼陣列載入。 這意味著類號已從單個整數轉換為長度等於可能類數的向量。 向量的所有元素都是零,除了 '元素是1並且意味著類是 。 例如,測試集中前5個影象的One-Hot編碼標籤是:
data.y_test[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.]]) 複製程式碼
我們還需要將類作為整數進行各種比較和效能測量。 通過使用np.argmax()函式獲取最高元素的索引,可以從One-Hot編碼陣列中找到這些資料。 但是在載入資料集時我們已經完成了這項工作,因此我們可以看到測試集中前五個影象的類編號。 將它們與上面的One-Hot編碼陣列進行比較。
data.y_test_cls[0:5] array([7, 2, 1, 0, 4]) 複製程式碼
接下來做一個小例子: 在3x3網格中繪製9個影象,並在每個影象下面寫入真實和預測類的函式。
def plot_images(images, cls_true, cls_pred=None): assert len(images) == len(cls_true) == 9 # Create figure with 3x3 sub-plots. fig, axes = plt.subplots(3, 3) fig.subplots_adjust(hspace=0.3, wspace=0.3) for i, ax in enumerate(axes.flat): # Plot image. ax.imshow(images[i].reshape(img_shape), cmap='binary') # Show true and predicted classes. if cls_pred is None: xlabel = "True: {0}".format(cls_true[i]) else: xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i]) ax.set_xlabel(xlabel) # Remove ticks from the plot. ax.set_xticks([]) ax.set_yticks([]) # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 複製程式碼
輸出影象看看
# Get the first images from the test-set. images = data.x_test[0:9] # Get the true classes for those images. cls_true = data.y_test_cls[0:9] # Plot the images and labels using our helper-function above. plot_images(images=images, cls_true=cls_true) 複製程式碼

#TensorFlow Graph
TensorFlow的全部目的是擁有一個所謂的計算圖,與直接在Python中執行相同的計算相比,它可以更有效地執行。 TensorFlow可以比NumPy更有效,因為TensorFlow知道必須執行的整個計算圖,而NumPy一次只知道一個數學運算的計算 TensorFlow還可以自動計算優化圖形變數所需的梯度,以使模型更好地執行。 這是因為圖是簡單數學表示式的組合,因此可以使用衍生的鏈規則計算整個圖的梯度。 TensorFlow還可以利用多核CPU和GPU - 而Google甚至為TensorFlow構建了專用晶片,稱為TPU(Tensor Processing Units)甚至比GPU更快。
TensorFlow圖由以下部分組成,將在下面詳述:
佔位符變數用於將輸入提供給圖表。 模型變數將進行優化,以使模型更好地執行。 該模型本質上只是一個數學函式,它根據佔位符變數和模型變數中的輸入計算一些輸出。 可用於指導變數優化的成本度量。 一種更新模型變數的優化方法。 複製程式碼
此外,TensorFlow圖還可以包含各種除錯語句,例如: 用於記錄使用TensorBoard顯示的資料,本教程未介紹。
#Placeholder variables
佔位符變數用作圖形的輸入,我們可以在每次執行圖形時更改這些輸入。 我們稱之為佔位符變數,並在下面進一步說明。
首先,我們為輸入影象定義佔位符變數。 這允許我們更改輸入到TensorFlow圖形的影象。 這是一個所謂的張量,這意味著它是一個多維向量或矩陣。 資料型別設定為float32,形狀設定為[None,img_size_flat],其中None表示張量可以保持任意數量的影象,每個影象是長度為img_size_flat的向量。
x = tf.placeholder(tf.float32, [None, img_size_flat]) 複製程式碼
接下來,我們有佔位符變數,用於與佔位符變數x中輸入的影象相關聯的真實標籤。 此佔位符變數的形狀為[None,num_classes],這意味著它可以包含任意數量的標籤,每個標籤是長度為num_classes的向量,在這種情況下為10。
y_true = tf.placeholder(tf.float32, [None, num_classes]) 複製程式碼
最後,我們在佔位符變數x中為每個影象的真實類提供佔位符變數。 這些是整數,此佔位符變數的維度設定為[None],這意味著佔位符變數是任意長度的一維向量。
y_true_cls = tf.placeholder(tf.int64, [None]) 複製程式碼
#Variables to be optimized
除了上面定義的佔位符變數以及用作將輸入資料輸入到模型中之外,還有一些模型變數必須由TensorFlow更改,以使模型在訓練資料上表現更好。
必須優化的第一個變數稱為權重,在此定義為TensorFlow變數,必須用零初始化並且其形狀為[img_size_flat,num_classes],因此它是具有img_size_flat行的二維張量(或矩陣)和 num_classes列。
weights = tf.Variable(tf.zeros([img_size_flat, num_classes])) 複製程式碼
必須優化的第二個變數稱為偏差,並定義為長度為num_classes的1維張量(或向量)。
biases = tf.Variable(tf.zeros([num_classes])) 複製程式碼
#Model
這個簡單的數學模型將佔位符變數x中的影象與權重相乘,然後新增偏差。
結果是形狀[num_images,num_classes]的矩陣,因為x具有形狀[num_images,img_size_flat]並且權重具有形狀[img_size_flat,num_classes],因此這兩個矩陣的乘法是具有形狀[num_images,num_classes]的矩陣然後 偏差向量被新增到該矩陣的每一行。
請注意,名稱logits是典型的TensorFlow術語,但其他人可能會將變數稱為其他內容。
logits = tf.matmul(x, weights) + biases 複製程式碼
現在logits是一個包含num_images行和num_classes列的矩陣,其中 '行和 '列的元素估計 '輸入影象是多少可能是 '。
然而,這些估計有點粗糙且難以解釋,因為數字可能非常小或很大,因此我們希望對它們進行歸一化,使得logits矩陣的每一行總和為1,並且每個元素限制在0和1之間。 這是使用所謂的softmax函式計算的,結果儲存在y_pred中。
y_pred = tf.nn.softmax(logits) 複製程式碼
可以通過獲取每行中最大元素的索引從y_pred矩陣計算預測類。
y_pred_cls = tf.argmax(y_pred, axis=1) 複製程式碼
#Cost-function to be optimized
為了使模型更好地對輸入影象進行分類,我們必須以某種方式更改權重和偏差的變數。 為此,我們首先需要通過將模型y_pred的預測輸出與期望輸出y_true進行比較來了解模型當前的執行情況。
交叉熵是用於分類的效能度量。 交叉熵是一個始終為正的連續函式,如果模型的預測輸出與期望輸出完全匹配,則交叉熵等於零。 因此,優化的目標是最小化交叉熵,使其通過改變模型的權重和偏差儘可能接近零。
TensorFlow具有用於計算交叉熵的內建函式。 請注意,它使用logits的值,因為它還在內部計算softmax。
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=y_true) 複製程式碼
我們現在已經計算了每個影象分類的交叉熵,因此我們可以測量模型對每個影象的單獨執行情況。 但是為了使用交叉熵來指導模型變數的優化,我們需要一個標量值,因此我們只需要對所有影象分類採用交叉熵的平均值。
cost = tf.reduce_mean(cross_entropy) 複製程式碼
#Optimization method
現在我們有一個必須最小化的成本度量,然後我們可以建立一個優化器。 在這種情況下,它是漸變下降的基本形式,其中步長設定為0.5。
請注意,此時不執行優化。 事實上,根本沒有計算任何東西,我們只需將optimizer-object新增到TensorFlow圖中以便以後執行。
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(cost) 複製程式碼
#Performance measures
我們還需要一些效能指標來向用戶顯示進度。 這是布林的向量,無論預測的等級是否等於每個影象的真實等級。
correct_prediction = tf.equal(y_pred_cls, y_true_cls) 複製程式碼
這通過首先將布林值的向量型別轉換為浮點數來計算分類精度,使得False變為0並且True變為1,然後計算這些數字的平均值。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 複製程式碼
#TensorFlow Run 一旦建立了TensorFlow圖,我們就必須建立一個用於執行圖的TensorFlow會話。
session = tf.Session() 複製程式碼
在我們開始優化之前,必須初始化權重和偏差的變數。
session.run(tf.global_variables_initializer()) 複製程式碼
訓練集中有55,000個影象。 使用所有這些影象計算模型的梯度需要很長時間。 因此,我們使用Stochastic Gradient Descent,它只在優化器的每次迭代中使用一小批影象。
batch_size = 100 複製程式碼
用於執行多個優化迭代的功能,以便逐漸改善模型的權重和偏差。 在每次迭代中,從訓練集中選擇一批新資料,然後TensorFlow使用這些訓練樣本執行優化程式。
def optimize(num_iterations): for i in range(num_iterations): # Get a batch of training examples. # x_batch now holds a batch of images and # y_true_batch are the true labels for those images. x_batch, y_true_batch, _ = data.random_batch(batch_size=batch_size) # Put the batch into a dict with the proper names # for placeholder variables in the TensorFlow graph. # Note that the placeholder for y_true_cls is not set # because it is not used during training. feed_dict_train = {x: x_batch, y_true: y_true_batch} # Run the optimizer using this batch of training data. # TensorFlow assigns the variables in feed_dict_train # to the placeholder variables and then runs the optimizer. session.run(optimizer, feed_dict=feed_dict_train) 複製程式碼
#Helper-functions to show performance 使用測試集資料進行Dict,以用作TensorFlow圖的輸入。 請注意,我們必須在TensorFlow圖中使用佔位符變數的正確名稱。
feed_dict_test = {x: data.x_test, y_true: data.y_test, y_true_cls: data.y_test_cls} 複製程式碼
用於在測試集上列印分類精度的功能。
def print_accuracy(): # Use TensorFlow to compute the accuracy. acc = session.run(accuracy, feed_dict=feed_dict_test) # Print the accuracy. print("Accuracy on test-set: {0:.1%}".format(acc)) 複製程式碼
使用scikit-learn列印和繪製混淆矩陣的功能。
def print_confusion_matrix(): # Get the true classifications for the test-set. cls_true = data.y_test_cls # Get the predicted classifications for the test-set. cls_pred = session.run(y_pred_cls, feed_dict=feed_dict_test) # Get the confusion matrix using sklearn. cm = confusion_matrix(y_true=cls_true, y_pred=cls_pred) # Print the confusion matrix as text. print(cm) # Plot the confusion matrix as an image. plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues) # Make various adjustments to the plot. plt.tight_layout() plt.colorbar() tick_marks = np.arange(num_classes) plt.xticks(tick_marks, range(num_classes)) plt.yticks(tick_marks, range(num_classes)) plt.xlabel('Predicted') plt.ylabel('True') # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 複製程式碼
用於繪製來自測試集的影象的錯誤分類的示例的功能。
def plot_example_errors(): # Use TensorFlow to get a list of boolean values # whether each test-image has been correctly classified, # and a list for the predicted class of each image. correct, cls_pred = session.run([correct_prediction, y_pred_cls], feed_dict=feed_dict_test) # Negate the boolean array. incorrect = (correct == False) # Get the images from the test-set that have been # incorrectly classified. images = data.x_test[incorrect] # Get the predicted classes for those images. cls_pred = cls_pred[incorrect] # Get the true classes for those images. cls_true = data.y_test_cls[incorrect] # Plot the first 9 images. plot_images(images=images[0:9], cls_true=cls_true[0:9], cls_pred=cls_pred[0:9]) 複製程式碼
#Helper-function to plot the model weights 用於繪製模型權重的函式。 繪製10個影象,每個數字一個,模型被訓練識別。
def plot_weights(): # Get the values for the weights from the TensorFlow variable. w = session.run(weights) # Get the lowest and highest values for the weights. # This is used to correct the colour intensity across # the images so they can be compared with each other. w_min = np.min(w) w_max = np.max(w) # Create figure with 3x4 sub-plots, # where the last 2 sub-plots are unused. fig, axes = plt.subplots(3, 4) fig.subplots_adjust(hspace=0.3, wspace=0.3) for i, ax in enumerate(axes.flat): # Only use the weights for the first 10 sub-plots. if i<10: # Get the weights for the i'th digit and reshape it. # Note that w.shape == (img_size_flat, 10) image = w[:, i].reshape(img_shape) # Set the label for the sub-plot. ax.set_xlabel("Weights: {0}".format(i)) # Plot the image. ax.imshow(image, vmin=w_min, vmax=w_max, cmap='seismic') # Remove ticks from each sub-plot. ax.set_xticks([]) ax.set_yticks([]) # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 複製程式碼
#Performance before any optimization 測試集的準確度為9.8%。 這是因為模型只是初始化而根本沒有優化,因此它總是預測影象顯示零位數,如下圖所示,結果發現測試集中9.8%的影象發生了 為零位數。
print_accuracy() Accuracy on test-set: 9.8% plot_example_errors() 複製程式碼

Performance after 1 optimization iteration(1次優化迭代後的效能)
optimize(num_iterations=1) print_accuracy() Accuracy on test-set: 15.9% plot_example_errors() 複製程式碼

權重也可以如下所示繪製。 正權重為紅色,負權重為藍色。 這些權重可以直觀地理解為影象過濾器。
例如,用於確定影象是否顯示零位的權重對圓的影象具有正反應(紅色),並且對具有在圓的中心的內容的影象具有負反應(藍色)。
類似地,用於確定影象是否顯示一位數的權重對影象中心的垂直線呈正(紅色)反應,並且對具有圍繞該線的內容的影象作出負反應(藍色)。
請注意,權重大多看起來像是他們應該識別的數字。 這是因為僅執行了一次優化迭代,因此權重僅在100個影象上進行訓練。 在對數千個影象進行訓練之後,權重變得更難以解釋,因為它們必須識別數字如何被寫入的許多變化。
plot_weights() 複製程式碼

Performance after 10 optimization iterations(10次優化迭代後的效能)
optimize(num_iterations=9) print_accuracy() Accuracy on test-set: 66.2% plot_example_errors() 複製程式碼

plot_weights() 複製程式碼

Performance after 1000 optimization iterations(1000次優化迭代後的效能) 在1000次優化迭代之後,模型僅對大約十分之一的影象進行錯誤分類。 如下所示,一些誤分類是合理的,因為即使對於人類來說,影象也很難確定,而其他影象非常明顯,應該通過一個好的模型正確分類。 但是這種簡單的模型無法達到更好的效能,因此需要更復雜的模型。
optimize(num_iterations=990) print_accuracy() Accuracy on test-set: 91.5% plot_example_errors() 複製程式碼

該模型現已經過1000次優化迭代的訓練,每次迭代使用來自訓練集的100個影象。 由於影象種類繁多,權重現在變得難以解釋,我們可能會懷疑模型是否真正理解數字是如何由線條組成的,或者模型是否只記憶了許多不同的畫素變化。
plot_weights() 複製程式碼

我們還可以列印和繪製所謂的混淆矩陣,讓我們可以看到有關錯誤分類的更多細節。 例如,它顯示實際描繪5的影象有時被錯誤分類為所有其他可能的數字,但大多數為6或8。
print_confusion_matrix() 複製程式碼
[[ 956 0 3 1 1 4 11 3 1 0] [ 0 1114 2 2 1 2 4 2 8 0] [ 6 8 925 23 11 3 13 12 26 5] [ 3 1 19 928 0 34 2 10 5 8] [ 1 3 4 2 918 2 11 2 6 33] [ 8 3 7 36 8 781 15 6 20 8] [ 9 3 5 1 14 12 912 1 1 0] [ 2 11 24 10 6 1 0 941 1 32] [ 8 13 11 44 11 52 13 14 797 11] [ 11 7 2 14 50 10 0 30 4 881]]

我們現在使用TensorFlow完成,因此我們關閉會話以釋放其資源。
# This has been commented out in case you want to modify and experiment # with the Notebook without having to restart it. # session.close() 複製程式碼