【TensorFlow篇】--DNN初始和應用

LHBlog發表於2018-03-28

一、前述

ANN人工神經網路有兩個或兩個以上隱藏層,稱為DNN

只有一個隱藏層是多層感知機

沒有隱藏層是感知機

二、反向傳播應用舉例

舉例:

 

正向傳播,反向傳播是一次迭代,

正向傳播:在開始的每一層上都有一個引數值w,初始的時候是隨機的,前向帶入的是每一個樣本值。

反向傳播:然後反過來求所有的梯度值。如果是BGD則再根據公式wt=wt-1-ag進行調整所有w值。

然後再正向傳播,迭代,以此類推。

softmax通常用於最後一層的啟用函式

前面層用relu函式

三、啟用函式之Relu

公式:

解釋:

Rectified Linear Units
ReLU計算線性函式為非線性,如果大於0就是結果,否則就是0
生物神經元的反應看起來其實很像Sigmoid啟用函式,所有專家在Sigmoid上卡了很長時間,但是後
來發現ReLU才更適合人工神經網路,這是一個模擬生物的誤解

如果w為0,反過來梯度下降求導的時候每根線上的梯度都一樣。

程式碼:

import tensorflow as tf


def relu(X):
    w_shape = (int(X.get_shape()[1]), 1)
    w = tf.Variable(tf.random_uniform(w_shape), name='weights')
    b = tf.Variable(0.0, name='bias')
    z = tf.add(tf.matmul(X, w), b, name='z')
    return tf.maximum(z, 0., name='relu')


n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name='X')
relus = [relu(X) for i in range(5)]#list生成器
output = tf.add_n(relus, name='output')#將集合中的元素加和在一起

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    result = output.eval(feed_dict={X: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]})#把裡面placehoder的值傳進來
    print(result)

 四、啟用函式和導數

 五、DNN程式碼

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
from tensorflow.contrib.layers import fully_connected


# 構建圖階段
n_inputs = 28*28#輸入節點
n_hidden1 = 300#第一個隱藏層300個節點 對第一個隱藏層前面有784*300跟線去算
n_hidden2 = 100#第二個隱藏層100個節點 對第二個隱藏層300*300根線
n_outputs = 10#輸出節點

X = tf.placeholder(tf.float32, shape=(None, n_inputs), name='X')
y = tf.placeholder(tf.int64, shape=(None), name='y')

#自己手寫的實現邏輯
# 構建神經網路層,我們這裡兩個隱藏層,基本一樣,除了輸入inputs到每個神經元的連線不同
# 和神經元個數不同
# 輸出層也非常相似,只是啟用函式從ReLU變成了Softmax而已
# def neuron_layer(X, n_neurons, name, activation=None):# X是輸入,n_neurons是這一層神經元個數,當前隱藏層名稱,最後一個引數是加不加啟用函式
#     # 包含所有計算節點對於這一層,name_scope可寫可不寫
#     with tf.name_scope(name):#with讓程式碼看起來更加優雅一些
#         # 取輸入矩陣的維度作為層的輸入連線個數
#         n_inputs = int(X.get_shape()[1])
#         stddev = 2 / np.sqrt(n_inputs)#求標準方差
#         # 這層裡面的w可以看成是二維陣列,每個神經元對於一組w引數
#         # truncated normal distribution(調整後的正態分佈) 比 regular normal distribution(正態分佈)的值小
#         # 不會出現任何大的權重值,確保慢慢的穩健的訓練
#         # 使用這種標準方差會讓收斂快
#         # w引數需要隨機,不能為0,否則輸出為0,最後調整都是一個幅度沒意義
#         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')#b可以全為0
#         # 向量表達的使用比一條一條加和要高效
#         z = tf.matmul(X, w) + b
#         if activation == "relu":
#             return tf.nn.relu(z)
#         else:
#             return z
#自己手寫的實現邏輯
'''
with tf.name_scope("dnn"):
    hidden1 = neuron_layer(X, n_hidden1, "hidden1", activation="relu")
    hidden2 = neuron_layer(hidden1, n_hidden2, "hidden2", activation="relu")
    # 進入到softmax之前的結果
    logits = neuron_layer(hidden2, n_outputs, "outputs")
'''
#用Tensorflow封裝的函式
with tf.name_scope("dnn"):
    # tensorflow使用這個函式幫助我們使用合適的初始化w和b的策略,預設使用ReLU啟用函式
    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)#構建輸出層 #注意輸出層啟用函式不需要

with tf.name_scope("loss"):
    # 定義交叉熵損失函式,並且求個樣本平均
    # 函式等價於先使用softmax損失函式,再接著計算交叉熵,並且更有效率
    # 類似的softmax_cross_entropy_with_logits只會給one-hot編碼,我們使用的會給0-9分類號
    xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)#封裝好了損失函式
    #把真實的Y值做onehot編碼
    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"):#評估
    # 獲取logits裡面最大的那1位和y比較類別好是否相同,返回True或者False一組值
    correct = tf.nn.in_top_k(logits, y, 1)#logits返回是類別號 y也是類別號
    accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))#轉成1.0 0.0

init = tf.global_variables_initializer()
saver = tf.train.Saver()

# 計算圖階段
mnist = input_data.read_data_sets("MNIST_data_bak/")
n_epochs = 400 #執行400次
batch_size = 50 #每一批次執行50個

with tf.Session() as sess:
    init.run()
    for epoch in range(n_epochs):
        for iterationo 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_dnn_model_final.ckpt")

# 使用模型預測
with tf.Session as sess:
    saver.restore(sess, "./my_dnn_model_final.ckpt")
    X_new_scaled = [...]
    Z = logits.eval(feed_dict={X: X_new_scaled})
    y_pred = np.argmax(Z, axis=1)  # 檢視最大的類別是哪個

 

 

相關文章