[譯]TensorFlow Tutorial #01 Simple Linear Model

原文地址git

本教程演示了使用TensorFlow和簡單線性模型的基本工做流程。 在使用手寫數字圖像加載所謂的MNIST數據集以後,咱們在TensorFlow中定義並優化了一個簡單的數學模型。 而後繪製並討論結果。github

您應該熟悉基本的線性代數,Python和Jupyter Notebook編輯器。 若是您對機器學習和分類有基本的瞭解,它也會有所幫助。數組

#Importsbash

%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
from sklearn.metrics import confusion_matrix
複製代碼

#Load Datasession

MNIST數據集大約爲12 MB,若是它不在給定路徑中,將自動下載。dom

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編碼數組加載。 這意味着類號已從單個整數轉換爲長度等於可能類數的向量。 向量的全部元素都是零,除了i'元素是1而且意味着類是i。 例如,測試集中前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列的矩陣,其中i'行和j'列的元素估計i'輸入圖像是多少多是j'。

然而,這些估計有點粗糙且難以解釋,由於數字可能很是小或很大,所以咱們但願對它們進行歸一化,使得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()
複製代碼
相關文章
相關標籤/搜索