Tensorflow實現手寫體分類(含dropout)


一、手寫體分類

1. 數據集

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
config = tf.ConfigProto(allow_soft_placement = True)
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction = 0.33)
config.gpu_options.allow_growth = True

max_steps = 20  # 最大迭代次數
learning_rate = 0.001   # 學習率
dropout = 0.9   # dropout時隨機保留神經元的比例
data_dir = '.\MNIST_DATA'   # 樣本數據存儲的路徑
log_dir = 'E:\MNIST_LOG'    # 輸出日志保存的路徑

# 獲取數據集,並采用采用one_hot熱編碼
mnist = input_data.read_data_sets(data_dir,one_hot = True)
# mnist=input_data.read_data_sets('MNIST_data',one_hot=True)

'''下載數據是直接調用了tensorflow提供的函數read_data_sets,輸入兩個參數,
第一個是下載到數據存儲的路徑,第二個one_hot表示是否要將類別標簽進行獨熱編碼。
它首先回去找制定目錄下有沒有這個數據文件,沒有的話才去下載,有的話就直接讀取。
所以第一次執行這個命令,速度會比較慢。'''

# sess = tf.InteractiveSession(config = config)

 

下面的圖是通過調用 tf.summary.image('input', image_shaped_input, 10)得到的,具體見2.初始化參數

2. 初始化參數

with tf.name_scope('input'):
    x = tf.placeholder(tf.float32, [None, 784], name='x-input')
    y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')

# 保存圖像信息
with tf.name_scope('input_reshape'):
    image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
    tf.summary.image('input', image_shaped_input, 10)

# 初始化權重參數
def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev = 0.1)
    return tf.Variable(initial)

# 初始化偏執參數
def bias_variable(shape):
    initial = tf.constant(0.1, shape = shape)
    return tf.Variable(initial)

# 繪制參數變化
def variable_summaries(var):
    with tf.name_scope('summaries'):
        # 計算參數的均值,並使用tf.summary.scaler記錄
        mean = tf.reduce_mean(var)
 tf.summary.scalar('mean', mean)

        # 計算參數的標准差
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        # 使用tf.summary.scaler記錄下標准差,最大值,最小值
 tf.summary.scalar('stddev', stddev) tf.summary.scalar('max', tf.reduce_max(var)) tf.summary.scalar('min', tf.reduce_min(var))
        # 用直方圖記錄參數的分布
        tf.summary.histogram('histogram', var) 

  

第一層的weight和biases的變化情況

 

 第二層的weight和biases的變化情況

 

 

 3. 構建神經網絡

下面是單層神經網絡模型

# 構建神經網絡
def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
    # 設置命名空間
    with tf.name_scope(layer_name):
        # 調用之前的方法初始化權重w,並且調用參數信息的記錄方法,記錄w的信息
        with tf.name_scope('weights'):
            weights = weight_variable([input_dim, output_dim])
            variable_summaries(weights)
        # 調用之前的方法初始化權重b,並且調用參數信息的記錄方法,記錄b的信息
        with tf.name_scope('biases'):
            biases = bias_variable([output_dim])
            variable_summaries(biases)
        # 執行wx+b的線性計算,並且用直方圖記錄下來
        with tf.name_scope('linear_compute'):
            preactivate = tf.matmul(input_tensor, weights) + biases
            tf.summary.histogram('linear', preactivate)
        # 將線性輸出經過激勵函數,並將輸出也用直方圖記錄下來
        activations = act(preactivate, name='activation')
        tf.summary.histogram('activations', activations)
    # 返回激勵層的最終輸出
    return activations

 

下面要建雙層神經網絡,第一層加dropout

hidden1 = nn_layer(x, 784, 500, 'layer1')

# 創建dropout層
with tf.name_scope('dropout'):
keep_prob = tf.placeholder(tf.float32)
tf.summary.scalar('dropout_keep_probability', keep_prob)
dropped = tf.nn.dropout(hidden1, keep_prob)

y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)  

 

模型圖如下:

 dropout變化如下:

第一層和第二層的weights、bias、未激活前,激活后的值分布如下:

  tf.summary.histogram接受任意大小和形狀的張量,並將該張量壓縮成一個由許多分箱組成的直方圖數據結構,這些分箱有各種寬度和計數。例如,假設我們要將數字 [0.5, 1.1, 1.3, 2.2, 2.9, 2.99] 整理到不同的分箱中,我們可以創建三個分箱: * 一個分箱包含 0 到 1 之間的所有數字(會包含一個元素:0.5), * 一個分箱包含 1 到 2 之間的所有數字(會包含兩個元素:1.1 和 1.3), * 一個分箱包含 2 到 3 之間的所有數字(會包含三個元素:2.2、2.9 和 2.99)。TensorFlow 使用類似的方法創建分箱,但與我們的示例不同,它不創建整數分箱。對於大型稀疏數據集,可能會導致數千個分箱。相反,這些分箱呈指數分布,許多分箱接近 0,有較少的分箱的數值較大。 然而,將指數分布的分箱可視化是非常艱難的。如果將高度用於為計數編碼,那么即使元素數量相同,較寬的分箱所占的空間也越大。反過來推理,如果用面積為計數編碼,則使高度無法比較。因此,直方圖會將數據重新采樣並分配到統一的分箱。很不幸,在某些情況下,這可能會造成假象。

  直方圖可視化工具中的每個切片顯示單個直方圖。切片是按步驟整理的;較早的切片(如,步驟 0)位於較“靠后”的位置,顏色也較深,而較晚的切片則靠近前景,顏色也較淺。右側的 y 軸顯示步驟編號。

舉例:下圖表示時間步驟76,對應的直方圖的分箱位於0.0695附近,分箱中有712個元素

 

切換historm到覆蓋模式

信息中心左側有一個控件,可以將直方圖模式從“偏移”切換到“覆蓋”:在“偏移”模式下,可視化旋轉 45 度,以便各個直方圖切片不再按時間展開,而是全部繪制在相同的 y 軸上。

現在,每個切片都是圖表上的一條單獨線條,y 軸顯示的是每個分箱內的項目數。顏色較深的線條表示較早的步,而顏色較淺的線條表示較晚的步。同樣,可以將鼠標懸停在圖表上以查看其他一些信息。

 

 

 

4. 損失函數+優化器

# 創建損失函數
with tf.name_scope('loss'):
    # 計算交叉熵損失(每個樣本都會有一個損失)
    diff = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_, logits=y)
    with tf.name_scope('total'):
        # 計算所有樣本交叉熵損失的均值
        cross_entropy = tf.reduce_mean(diff)
    tf.summary.scalar('loss', cross_entropy)
    
# 使用AdamOptimizer優化器訓練模型,最小化交叉熵損失
with tf.name_scope('train'):
    train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)

# 計算准確率
with tf.name_scope('accuracy'):
    with tf.name_scope('correct_prediction'):
        # 分別將預測和真實的標簽中取出最大值的索引,弱相同則返回1(true),不同則返回0(false)
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    with tf.name_scope('accuracy'):
        # 求均值即為准確率
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        
tf.summary.scalar('accuracy', accuracy)

5. 訓練

sess = tf.Session()
#summaries合並
merged = tf.summary.merge_all()
# 寫到指定的磁盤路徑中
train_writer = tf.summary.FileWriter(log_dir + '/train', sess.graph)
test_writer = tf.summary.FileWriter(log_dir + '/test',sess.graph)

#運行初始化所有變量
# global_variables_initializer().run()
sess.run(tf.global_variables_initializer())

def feed_dict(train):
    """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
    if train:
        xs, ys = mnist.train.next_batch(10)
        k = dropout
    else:
        xs, ys = mnist.test.images[:100], mnist.test.labels[:100]
        k = 1.0
    return {x: xs, y_: ys, keep_prob: k}

for i in range(100):
    if i % 10 == 0:  #記錄測試集的summary與accuracy
        summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
        test_writer.add_summary(summary, i)
        print('Accuracy at step %s: %s' % (i, acc))
    else:  # 記錄訓練集的summary
        summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
        train_writer.add_summary(summary, i)

train_writer.close()
test_writer.close()

  

准確率:

損失函數:

 

 參考文獻:

【1】莫煩Python

【2】TensorBoard 直方圖信息中心


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM