2021-05-12 14:32:11
使用TensorFlow實現DNN
這一節使用TF實現一個多層神經網路模型來對MNIST
資料集進行分類,這裡我們設計一個含有兩個隱藏層的神經網路,在輸出部分使用softmax對結果進行預測。
使用高階API實現多層神經網路
這裡我們使用tensorflow.contrib
包,這是一個高度封裝的包,裡面包含了許多類似seq2seq、keras
一些實用的方法。
先引入資料
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./") #自動下載資料到這個目錄
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_train
array([[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
...,
[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
>>len(X_train)
55000
>>len(X_train[0])
784
>>X_train[0]
array([ 0., 0., 0., ..., 0., 0., 0.], dtype=float32)
>>y_test
array([7, 2, 1, ..., 4, 5, 6])
模型的主要程式碼
features_cols = 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=features_cols)
dnn_clf.fit(X_train, y_train, batch_size=50, steps=10000)
from sklearn.metrics import accuracy_score
y_pred = dnn_clf.predict(X_test)
print(accuracy_score(y_test, list(y_pred)))
其中infer_real_valued_columns_from_input
這個方法根據名字可以看出,它是根據輸入的資料來推算出資料的型別,該例子中features_cols
的值為[_RealValuedColumn(column_name='', dimension=784, default_value=None, dtype=tf.float32, normalizer=None)]
,短短幾行程式碼就實現了一個多層神經網路模型。並且可能會發現上面這些與之前介紹的有些不同,不需要對變數進行初始化,不需要建立session
,使用起來十分的簡單。
使用TF實現多層神經網路
高度封裝的API呼叫起來固然很爽,但是自己不了解內部的原理使用起來就不是那麼的踏實,下面就使用TF實現同樣的模型,程式碼主要分為兩部分,構建TF計算流圖和執行計算圖。希望讀者能夠對比上面的程式碼來看接下來的部分。
構建TF計算流圖
首先我們需要根據輸入的資料來設定輸入的引數,使用的資料集MNIST為28*28的矩陣,整個神經網路包含兩個隱藏層
n_inputs = 28 * 28
n_hidden1 = 300
n_hidden2 = 100
n_output = 10
X = tf.placeholder(tf.float32,shape=(None,n_inputs),name='X')
y = tf.placeholder(tf.int64,shape=(None),name='y')#注意資料型別
上面使用預留位置的方法來宣告模型的輸入X和y,需要注意的是預留位置的資料型別
,在執行階段,預留位置會被輸入的資料所替代。接下來我們需要建立模型的兩個隱藏層和輸出層,兩個隱藏使用Relu
作為啟用函數,輸出層使用softmax。每一層需要指定節點的個數。
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='weight')
b = tf.Variable(tf.zeros([n_neurons]),name='baise')
z = tf.matmul(X,W) + b
if activation == "relu":
return tf.nn.relu(z)
else:
return z
我將逐行的對上面程式碼進行解釋:
- 1.為了方便在TensorBoard上面檢視,每一層的神經網路都建立一個
name_scope
。這一步是可選操作,如果不需要在TensorBoard檢視那就可以忽略掉。 - 2.根據輸入的資料的形狀來獲取資料的特徵個數(第二個維度)
-
3.接下來的程式碼是建立權重矩陣
W
和偏置b
,權重W
不能使用0進行初始化,這樣會導致所有的神經元的輸出為0,出現對稱失效問題,這裡使用truncated normal分布(Gaussian)來初始化權重,
通過指定均值和標準方差來生成正態分布,拋棄那些大於2倍stddev的值。這樣將有助於加快訓練速度。在初始化tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
b
的時候,每一層只有一個偏置,我們全部設定為0,這樣並不會出現對稱失效問題。 - 4.下面的是在每一個神經元中的操作y=X⋅W+b y=X·W+b ,使用向量化運算計算輸入與權重的和運算
-
5.最後就是啟用函數的選擇了
下面我們就開始像搭建積木一樣建立我們的神經網路了,每一層的輸入為上一層的輸出:
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_output,"output")
上面這一段程式碼的輸出層並沒有經過softmax
啟用函數,這是考慮到後續優化求解原因,在後續工作中單獨做處理。上面這段程式碼就是一個神經網路全連線的簡化版本,當然TF的contrib模組也提供了全連線的函數fully_connected
。
from tensorflow.contrib.layers import fully_connected
with tf.name_scope("dnn"):
hidden1 = fully_connected(X, n_hidden1, scope="hidden1")#啟用函數預設為relu
hidden2 = fully_connected(hidden1, n_hidden2, scope="hidden2")
logits = fully_connected(hidden2, n_outputs, scope="outputs",activation_fn=None)
現在,模型已經有了。接下來套路就是設計損失函數,優化損失函數求解引數。輸出層softmax輸出的為在各個類別上面的得分,損失函數使用交叉熵
−∑y ′ log(y ′ ) −∑y′log(y′) 。在這裡我們使用TF提供的tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)
來計算損失函數,該方法先計算softmax再計算cross entropy,主要有兩個引數需要考慮
- 1.labels:輸入的為標籤的index,例如本例子有10個類別,取值範圍為0-9
- 2.logits:為輸入到softmax啟用函數之前的模型的輸出
最後再使用reduce_mean()
計算loss。
with tf.name_scope("loss"):
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y,logits=logits)#labels允許的資料型別有int32, int64
loss = tf.reduce_mean(xentropy,name="loss")
note:TF還提供了softmax_cross_entropy_with_logits()
,和上面方法的區別該方法輸入的label為一個one-hot向量。
到這裡我們的模型和損失函數已經都有了,就到了優化階段,本文使用梯度下降方法
learning_rate = 0.01
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
training_op = optimizer.minimize(loss)
模型有了結果,就需要對得到的模型進行衡量。簡單起見,這裡使用accuracy
作為評估指標,判斷模型輸出結果的最高值的index是否和label的index相等
with tf.name_scope("eval"):
correct = tf.nn.in_top_k(logits,y,1) #取值最高的一位
accuracy = tf.reduce_mean(tf.cast(correct,tf.float32)) #結果boolean轉為0,1
模型構建階段最後一個工作就是初始化裡面的變數
init = tf.global_variables_initializer()
saver = tf.train.Saver()
執行計算流圖
這一部分相對前面工作要簡單很多,
n_epoch = 400
batch_size = 50
with tf.Session() as sess:
init.run()
for epoch in range(n_epoch):
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,mnist.test.labels})
print (epoch,"Train accuracy", acc_train,"Test accuracy",acc_test)
saver.save(sess, "./my_model.pk")
上面這段程式碼使用的是mini-batch方法訓練神經網路,最後將模型持久化到本地。後續的使用
with tf.Session() as sess:
saver.restore(sess, "./my_model.pk") #載入
X_new_scaled = mnist.test.images[:20]
Z = logits.eval(feed_dict={X: X_new_scaled}) #模型
y_pred = np.argmax(Z, axis=1)
總結
本文介紹了TF在實際資料集MNIST上面的使用,為input和target建立預留位置,建立神經網路的layer,得到一個DNN,並為整個模型設定損失函數,對損失函數進行優化求解,最後對模型進行評估。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2017-12/149553.htm
相關文章