其中,step(z)爲階躍函數,最多見的在感知器中使用的階躍函數是 Heaviside 階躍函數。有時使用符號函數代替。git
單一的 LTU 可被用做簡單線性二元分類。它計算輸入的線性組合,若是結果超過閾值,它輸出正類或者輸出負類(就像一個邏輯迴歸分類或線性 SVM)。圖 10-5 表示具備兩個輸入和三個輸出的感知器。該感知器能夠將實例同時分類爲三個不一樣的二進制類,這使得它是一個多輸出分類器算法
感知器的權重進行以下調整:網絡
$$W_{i,j}^{Next}=W_{i,j}+\eta(\widehat{y}_j-y_j)x_i$$架構
每一個輸出神經元的決策邊界是線性的,所以感知機不能學習複雜的模式.klearn 提供了一個感知器類,它實現了一個 LTU 網絡。它能夠像你所指望的那樣使用,例如在 iris 數據集dom
import numpy as np from sklearn.datasets import load_iris from sklearn.linear_model import Perceptron iris = load_iris() X = iris.data[:, (2, 3)] # 花瓣長度,寬度 y = (iris.target == 0).astype(np.int) per_clf = Perceptron(random_state=42) # Perceptron爲感知器模型 per_clf.fit(X, y) y_pred = per_clf.predict([[2, 0.5]])
您可能已經認識到,感知器學習算法相似於隨機梯度降低。事實上,sklearn 的感知器類至關於使用具備如下超參數的 SGD 分類器:loss="perceptron",learning_rate="constant"(學習率),eta0=1,penalty=None(無正則化)。ide
事實證實,感知器的一些侷限性能夠經過堆疊多個感知器來消除。由此產生的人工神經網絡被稱爲多層感知器(MLP)。特別地,MLP 能夠解決 XOR異或問題函數
MLP 由一個(經過)輸入層、一個或多個稱爲隱藏層的 LTU 組成,一個最終層 LTU 稱爲輸出層。除了輸出層以外的每一層包括偏置神經元,而且全鏈接到下一層。當人工神經網絡有兩個或多個隱含層時,稱爲深度神經網絡(DNN)性能
爲了使算法可以正常工做,做者對 MLP 的體系結構進行了一個關鍵性的改變:改變了階躍函數,如下是經常使用的階躍激活函數學習
這些流行的激活函數及其衍生物如圖所示測試
MLP 一般用於分類,每一個輸出對應於不一樣的二進制類(例如,垃圾郵件/正常郵件,緊急/非緊急,等等)。當類是多類的(例如,0 到 9 的數字圖像分類)時,輸出層一般經過用共享的 softmax 函數替換單獨的激活函數來修改。
與 TensorFlow 一塊兒訓練 MLP 最簡單的方法是使用高級 API TF.Learn,這與 sklearn 的 API 很是類似。DNNClassifier能夠很容易訓練具備任意數量隱層的深度神經網絡,而 softmax 輸出層輸出估計的類機率。例如,下面的代碼訓練兩個隱藏層的 DNN(一個具備 300 個神經元,另外一個具備 100 個神經元)和一個具備 10 個神經元的 SOFTMax 輸出層進行分類:
import tensorflow as tf feature_columns = tf.contrib.learn.infer_real_valued_columns_from_input(X_train) # 構造數值類型的特徵列 dnn_clf = tf.contrib.learn.DNNClassifier(hidden_units=[300, 100], n_classes=10, feature_columns=feature_column) dnn_clf.fit(x=X_train, y=y_train, batch_size=50, steps=40000)
若是你在 MNIST 數據集上運行這個代碼(在縮放它以後,例如,經過使用 skLearn 的StandardScaler),你實際上能夠獲得一個在測試集上達到 98.1% 以上精度的模型!這比咱們在以前訓練的最好的模型都要好:
>>> from sklearn.metrics import accuracy_score >>> y_pred = list(dnn_clf.predict(X_test)) >>> accuracy_score(y_test, y_pred) 0.98180000000000001
TF.Learn 學習庫也爲評估模型提供了一些方便的功能:
>>> dnn_clf.evaluate(X_test, y_test) {'accuracy': 0.98180002, 'global_step': 40000, 'loss': 0.073678359}
NNClassifier基於 Relu 激活函數建立全部神經元層(咱們能夠經過設置超參數activation_fn來改變激活函數)。輸出層基於 SoftMax 函數,損失函數是交叉熵。
若是您想要更好地控制網絡架構,您可能更喜歡使用 TensorFlow 的較低級別的 Python API。在本節中,咱們將使用與以前的 API 相同的模型,咱們將實施 Minibatch 梯度降低來在 MNIST 數據集上進行訓練。 第一步是建設階段,構建 TensorFlow 圖。 第二步是執行階段,您實際運行計算圖譜來訓練模型。
構造階段:
首先咱們須要導入tensorflow庫。 而後咱們必須指定輸入和輸出的數量,並設置每一個層中隱藏的神經元數量:
import tensorflow as tf n_inputs = 28*28 # MNIST n_hidden1 = 300 n_hidden2 = 100 n_outputs = 10
接下來,可使用佔位符節點來表示訓練數據和目標。X的形狀僅有部分被定義。 咱們知道它將是一個 2D 張量(即一個矩陣),沿着第一個維度的實例和第二個維度的特徵,咱們知道特徵的數量將是28×28(每像素一個特徵) 可是咱們不知道每一個訓練批次將包含多少個實例。 因此X的形狀是(None, n_inputs)。 一樣,咱們知道y將是一個 1D 張量,每一個實例有一個入口,可是咱們再次不知道在這一點上訓練批次的大小,因此形狀(None)。
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X") y = tf.placeholder(tf.int64, shape=(None), name="y")
如今讓咱們建立一個實際的神經網絡。 佔位符X將做爲輸入層; 在執行階段,它將一次更換一個訓練批次(注意訓練批中的全部實例將由神經網絡同時處理)。 如今您須要建立兩個隱藏層和輸出層。 兩個隱藏的層幾乎相同:它們只是它們所鏈接的輸入和它們包含的神經元的數量不一樣。 輸出層也很是類似,但它使用 softmax 激活函數而不是 ReLU 激活函數。 因此讓咱們建立一個neuron_layer()函數,咱們將一次建立一個圖層。 它將須要參數來指定輸入,神經元數量,激活函數和圖層的名稱:
def neuron_layer(X, n_neurons, name, activation=None): # 輸入、神經元數量、圖層名稱、激活函數 with tf.name_scope(name): n_inputs = int(X.get_shape()[1]) # 輸入數量 stddev = 2 / np.sqrt(n_inputs) init = tf.truncated_normal((n_inputs, n_neurons), stddev=stddev) W = tf.Variable(init, name="weights") b = tf.Variable(tf.zeros([n_neurons]), name="biases") z = tf.matmul(X, W) + b if activation == "relu": return tf.nn.relu(z) else: return z
咱們逐行瀏覽這個代碼:
好了,如今你有一個很好的函數來建立一個神經元層。 讓咱們用它來建立深層神經網絡! 第一個隱藏層以X爲輸入。 第二個將第一個隱藏層的輸出做爲其輸入。 最後,輸出層將第二個隱藏層的輸出做爲其輸入。
with tf.name_scope("dnn"): hidden1 = neuron_layer(X, n_hidden1, "hidden1", activation="relu") hidden2 = neuron_layer(hidden1, n_hidden2, "hidden2", activation="relu") logits = neuron_layer(hidden2, n_outputs, "outputs")
請注意,爲了清楚起見,咱們再次使用名稱範圍。 還要注意,logit 是在經過 softmax 激活函數以前神經網絡的輸出:爲了優化,咱們稍後將處理 softmax 計算。
正如你所指望的,TensorFlow 有許多方便的功能來建立標準的神經網絡層,因此一般不須要像咱們剛纔那樣定義你本身的neuron_layer()函數。 例如,TensorFlow 的fully_connected()函數建立一個徹底鏈接的層,其中全部輸入都鏈接到圖層中的全部神經元。 它使用正確的初始化策略來負責建立權重和偏置變量,而且默認狀況下使用 ReLU 激活函數(咱們可使用activate_fn參數來更改它)咱們來調整上面的代碼來使用fully_connected()函數,而不是咱們的neuron_layer()函數。 只需導入該功能,並使用如下代碼替換 dnn 構建部分:
from tensorflow.contrib.layers import fully_connected with tf.name_scope("dnn"): hidden1 = fully_connected(X, n_hidden1, scope="hidden1") hidden2 = fully_connected(hidden1, n_hidden2, scope="hidden2") logits = fully_connected(hidden2, n_outputs, scope="outputs", activation_fn=None)
tensorflow.contrib包包含許多有用的功能,但它是一個還沒有分級成爲主要 TensorFlow API 一部分的實驗代碼的地方。 所以,full_connected()函數(和任何其餘contrib代碼)可能會在未來更改或移動。
如今咱們已經有了神經網絡模型,咱們須要定義咱們用來訓練的損失函數。TensorFlow 提供了幾種計算交叉熵的功能。 咱們將使用sparse_softmax_cross_entropy_with_logits()。 而後,咱們可使用 TensorFlow 的reduce_mean()函數來計算全部實例的平均交叉熵。
with tf.name_scope("loss"): xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits) loss = tf.reduce_mean(xentropy, name="loss")
該sparse_softmax_cross_entropy_with_logits()函數等同於應用 SOFTMAX 激活函數,而後計算交叉熵,但它更高效,它妥善照顧的邊界狀況下,好比 logits 等於 0,這就是爲何咱們沒有較早的應用 SOFTMAX 激活函數。 還有稱爲softmax_cross_entropy_with_logits()的另外一個函數,該函數在標籤單熱載體的形式(而不是整數 0 至類的數目減 1)
咱們有神經網絡模型,咱們有損失函數,如今咱們須要定義一個GradientDescentOptimizer來調整模型參數以最小化損失函數
learning_rate = 0.01 with tf.name_scope("train"): optimizer = tf.train.GradientDescentOptimizer(learning_rate) training_op = optimizer.minimize(loss)
建模階段的最後一個重要步驟是指定如何評估模型。 咱們將簡單地將精度用做咱們的績效指標。 首先,對於每一個實例,經過檢查最高 logit 是否對應於目標類別來肯定神經網絡的預測是否正確。 爲此,您可使用in_top_k()函數。 這返回一個充滿布爾值的 1D 張量,所以咱們須要將這些布爾值轉換爲浮點數,而後計算平均值。 這將給咱們網絡的總體準確性.
with tf.name_scope("eval"): correct = tf.nn.in_top_k(logits, y, 1) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
並且,像往常同樣,咱們須要建立一個初始化全部變量的節點,咱們還將建立一個Saver來將咱們訓練有素的模型參數保存到磁盤中:
init = tf.global_variables_initializer() saver = tf.train.Saver()
建模階段結束。 這是不到 40 行代碼,但至關激烈:咱們爲輸入和目標建立佔位符,咱們建立了一個構建神經元層的函數,咱們用它來建立 DNN,咱們定義了損失函數,咱們 建立了一個優化器,最後定義了性能指標。 如今到執行階段。
執行階段
這部分要短得多,更簡單。 首先,咱們加載 MNIST。 咱們能夠像以前的章節那樣使用 ScikitLearn,可是 TensorFlow 提供了本身的助手來獲取數據,將其縮放(0 到 1 之間),將它洗牌,並提供一個簡單的功能來一次加載一個小批量:
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("/tmp/data/")
如今咱們定義咱們要運行的迭代數,以及小批量的大小:
n_epochs = 10001 batch_size = 50
如今咱們去訓練模型:
with tf.Session() as sess: init.run() for epoch in range(n_epochs): for iteration in range(mnist.train.num_examples // batch_size): X_batch, y_batch = mnist.train.next_batch(batch_size) sess.run(training_op, feed_dict={X: X_batch, y: y_batch}) acc_train = accuracy.eval(feed_dict={X: X_batch, y: y_batch}) acc_test = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels}) print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test) save_path = saver.save(sess, "./my_model_final.ckpt")
該代碼打開一個 TensorFlow 會話,並運行初始化全部變量的init節點。 而後它運行的主要訓練循環:在每一個時期,經過一些小批次的對應於訓練集的大小的代碼進行迭代。 每一個小批量經過next_batch()方法獲取,而後代碼簡單地運行訓練操做,爲當前的小批量輸入數據和目標提供。 接下來,在每一個時期結束時,代碼評估最後一個小批量和完整訓練集上的模型,並打印出結果。 最後,模型參數保存到磁盤。
如今神經網絡被訓練了,你能夠用它進行預測。 爲此,您能夠重複使用相同的建模階段,可是更改執行階段,以下所示:
with tf.Session() as sess: saver.restore(sess, "./my_model_final.ckpt") # or better, use save_path X_new_scaled = mnist.test.images[:20] Z = logits.eval(feed_dict={X: X_new_scaled}) y_pred = np.argmax(Z, axis=1)
首先,代碼從磁盤加載模型參數。 而後加載一些您想要分類的新圖像。 記住應用與訓練數據相同的特徵縮放(在這種狀況下,將其從 0 縮放到 1)。 而後代碼評估對數點節點。 若是您想知道全部估計的類機率,則須要將softmax()函數應用於對數,但若是您只想預測一個類,則能夠簡單地選擇具備最高 logit 值的類(使用argmax()函數作的伎倆)。
注意隱藏層數量,每層隱藏層的神經元數量,激活函數的選擇
完整代碼:
from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf from sklearn.metrics import accuracy_score import numpy as np if __name__ == '__main__': n_inputs = 28 * 28 n_hidden1 = 300 n_hidden2 = 100 n_outputs = 10 mnist = input_data.read_data_sets("/tmp/data/") X_train = mnist.train.images X_test = mnist.test.images y_train = mnist.train.labels.astype("int") y_test = mnist.test.labels.astype("int") X = tf.placeholder(tf.float32, shape= (None, n_inputs), name='X') y = tf.placeholder(tf.int64, shape=(None), name = 'y') with tf.name_scope('dnn'): hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu ,name= 'hidden1') hidden2 = tf.layers.dense(hidden1, n_hidden2, name='hidden2', activation= tf.nn.relu) logits = tf.layers.dense(hidden2, n_outputs, name='outputs') with tf.name_scope('loss'): xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels = y, logits = logits) loss = tf.reduce_mean(xentropy, name='loss')#全部值求平均 learning_rate = 0.01 with tf.name_scope('train'): optimizer = tf.train.GradientDescentOptimizer(learning_rate) training_op = optimizer.minimize(loss) with tf.name_scope('eval'): correct = tf.nn.in_top_k(logits ,y ,1)#是否與真值一致 返回布爾值 accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) #tf.cast將數據轉化爲0,1序列 init = tf.global_variables_initializer() n_epochs = 20 batch_size = 50 with tf.Session() as sess: init.run() for epoch in range(n_epochs): for iteration in range(mnist.train.num_examples // batch_size): X_batch, y_batch = mnist.train.next_batch(batch_size) sess.run(training_op,feed_dict={X:X_batch, y: y_batch}) acc_train = accuracy.eval(feed_dict={X:X_batch, y: y_batch}) acc_test = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels}) print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test)