1. 程式人生 > >Mnist原始碼實現

Mnist原始碼實現

# -*- coding:utf-8 -*-
import os
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

INPUT_NODE = 784  # 輸入層的節點數。對於MNIST資料集,這個就等於圖片的畫素
OUTPUT_NODE = 10  # 輸出層的節點數。這個等於類別的數目。因為在MNIST資料集中
# 需要區分的事0-9這10個數字,所以這裡輸出層點數為10

LAYER1_NODE = 500  # 隱藏層節點數。這裡使用只有一個隱藏層的網路結構作為樣例。
# 這個隱藏層有500個節點
BATCH_SIZE = 100  # 一個訓練batch中的訓練資料個數。數字越小,訓練過程越接近
# 隨機梯度下降;數字越大時,訓練越接近梯度下降

LEARNING_RAEW_BASE = 0.8  # 基礎的學習率
LEARNING_RAEW_DECAY = 0.99  # 學習率的衰減率
REGULARIZATION_RATE = 0.0001  # 描述模型複雜度的正則化項在損失函式中的係數
TRAINING_STEPS = 30000  # 訓練的論述
MOVING_AVERAGE_DECAY = 0.99  # 滑動平均衰減率


# 一個輔助函式,給定神經網路的輸入和所有引數,計算神經網路的前向傳播結果。在這裡
# 定義了一個使用ReLU啟用函式的三層全連線神經網路。通過加入隱藏層實現了多層網路結構,
# 通過ReLU啟用函式實現了去線性化。在這個函式中也支援傳入用於計算引數平均值的類,
# 這樣方便在測試時使用滑動平均模型
def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2):
    # 當沒有提供滑動平均類是,直接使用引數當前的取值。
    if avg_class == None:
        # 計算隱藏層的前向傳播結果,這裡使用了ReLU啟用函式
        layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
        # 計算輸出層的前向傳播結果。因為在計算損失函式時會一併計算softmax函式,
        # 所以這裡不需要加入啟用函式。而且不加入softmax不會影響預測結果。因為預測時
        # 使用的事不同類別的相對大小,有沒有softmax層對最後的分類結果的
        # 計算結果沒有影響。
        return tf.matmul(layer1, weights2) + biases2

    else:
        # 使用avg_class.average函式計算得出變數的滑動平均值
        # 然後再計算相應的神經網路前向傳播結果。
        layer1 = tf.nn.relu(
            tf.matmul(input_tensor, avg_class.average(weights1)) +
            avg_class.average(biases1))
        return tf.matmul(layer1, avg_class.average(weights2) +
                         avg_class.average(biases2))


# 訓練模型的過程。
def train(mnist):
    x = tf.placeholder(tf.float32, [None, INPUT_NODE], name='x-input')
    y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE], name='y-input')

    # 生成隱藏層的引數
    weights1 = tf.Variable(
        tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1))
    biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))
    # 生成輸出層的引數
    weights2 = tf.Variable(
        tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1))
    biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))

    # 計算當前引數下神經網路前向傳播的結果。這裡給出用於計算滑動平均值的類為None,
    # 所以函式不會使用引數的滑動平均值
    y = inference(x, None, weights1, biases1, weights2, biases2)

    # 定義儲存訓練輪數的變數,這個變數不需要計算滑動平均值,所以這裡指定這個變數為
    # 不可訓練的變數(trainable=False)。在使用TensorFlow訓練神經網路時,
    # 一般會將代表訓練輪數可以加快訓練早起變數的更新速度。
    global_step = tf.Variable(0, trainable=False)

    # 給定滑動平均衰減率和訓練輪數的變數,初始化滑動平均類。
    # 給定訓練輪數的變數可以加快訓練早期變數的更新速度
    variable_averages = tf.train.ExponentialMovingAverage(
        MOVING_AVERAGE_DECAY, global_step)

    #
    variables_averages_op = variable_averages.apply(tf.trainable_variables())

    # 計算使用滑動平均之後的前向傳播結果。滑動平均不會改變變數本身的取值,而是會維護一個影子變數來記錄
    # 滑動值,需要呼叫average函式
    average_y = inference(
        x, variable_averages, weights1, biases1, weights2, biases2)

    # 測試值和真實值的差距稱為損失函式
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        logits=y, labels=tf.argmax(y_, 1))
    # 計算在當前batch中所有樣例的交叉熵平均值
    cross_entropy_mean = tf.reduce_mean(cross_entropy)

    # 計算L2正則化損失函式
    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)

    # 計算模型的正則化損失,只計算權重,不計算偏置項
    regularization = regularizer(weights1) + regularizer(weights2)
    # 總損失等於交叉熵損失和正則化損失
    loss = cross_entropy_mean + regularization
    learning_rate = tf.train.exponential_decay(
        LEARNING_RAEW_BASE,
        global_step,  # 當前迭代的輪數
        mnist.train.num_examples / BATCH_SIZE,  # 學習率衰減速度
        LEARNING_RAEW_DECAY)

    # 損失函式包含交叉熵損失和L2正則化損失
    train_step = tf.train.GradientDescentOptimizer(learning_rate) \
        .minimize(loss, global_step=global_step)

    # tf.control_dependencies和tf.group兩種機制,
    # train_op = tf.group(train_step, variables_op)是等價
    with tf.control_dependencies([train_step, variables_averages_op]):
        train_op = tf.no_op(name='train')

        # 正確性檢測
        # tf.argmax(average_y, 1)計算每一個樣例的預算答案,average_y是一個batch_size * 10
        correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1))
        acccuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)
        validata_feed = {x: mnist.validation.images,
                         y_: mnist.validation.labels}

        # 準備測試資料。在真是的應用中,這部分資料在訓練時時不可見的,這個資料只是作為模
        # 型優劣的最後評價標準
        test_feed = {x: mnist.test.images,
                     y_: mnist.test.labels}
        # 開始迭代
        for i in range(TRAINING_STEPS):
            if i % 1000 == 0:
                # 計算滑動平均模型在驗證資料上的結果。因為MNIST資料集比較小,所以一次
                # 可以處理所有的驗證資料。為了計算方便,本樣例程式沒有將驗證資料劃分為更小的batch。
                # 當神經網路比較複雜或者驗證資料比較大時,太大的batch會導致計算時間過長甚至記憶體溢位
                validata_acc = sess.run(acccuracy, feed_dict=validata_feed)
                print(("After %d training step(s), validation accuracy"
                      "using average model is %g" % (i, validata_acc)))
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            sess.run(train_op, feed_dict={x: xs, y_: ys})

        test_acc = sess.run(acccuracy, feed_dict=test_feed)
        print("After %d training step(s), test accuracy using average"" model is %g")\
        % (TRAINING_STEPS, test_acc)


def main(argv=None):
    mnist = input_data.read_data_sets(r"D:\Github\TensorFlow\CH05 MNIST",
                                      one_hot=True)
    train(mnist)


if __name__ == '__main__':
    tf.app.run()

"D:\Program Files\Python3.x\python.exe" "D:/Github/TensorFlow/CH05 MNIST/MNIST_Code5.2.1.py"
Extracting D:\Github\TensorFlow\CH05 MNIST\train-images-idx3-ubyte.gz
Extracting D:\Github\TensorFlow\CH05 MNIST\train-labels-idx1-ubyte.gz
Extracting D:\Github\TensorFlow\CH05 MNIST\t10k-images-idx3-ubyte.gz
Extracting D:\Github\TensorFlow\CH05 MNIST\t10k-labels-idx1-ubyte.gz
After 0 training step(s), validation accuracyusing average model is 0.0802
After 1000 training step(s), validation accuracyusing average model is 0.0924
After 2000 training step(s), validation accuracyusing average model is 0.0924
After 3000 training step(s), test accuracy using average model is 0.0974
不知道問題出在哪裡