1. 程式人生 > >Tensorflow案例4:Mnist手寫數字識別(線性神經網路)及其侷限性

Tensorflow案例4:Mnist手寫數字識別(線性神經網路)及其侷限性

學習目標

  • 目標
    • 應用matmul實現全連線層的計算
    • 說明準確率的計算
    • 應用softmax_cross_entropy_with_logits實現softamx以及交叉熵損失計算
    • 說明全連線層在神經網路的作用
    • 應用全連線神經網路實現影象識別
  • 應用
    • Mnist手寫數字勢識別

1、 資料集介紹

在這裡插入圖片描述

檔案說明:

  • train-images-idx3-ubyte.gz: training set images (9912422 bytes)
  • train-labels-idx1-ubyte.gz: training set labels (28881 bytes)
  • t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
  • t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)

網址:http://yann.lecun.com/exdb/mnist/

1.1 特徵值

在這裡插入圖片描述

在這裡插入圖片描述

1.2 目標值

在這裡插入圖片描述

1.3 獲取介面

TensorFlow框架自帶了獲取這個資料集的介面,所以不需要自行讀取。

  • from tensorflow.examples.tutorials.mnist import input_data
    • mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
      • mnist.train.next_batch(100)(提供批量獲取功能)
      • mnist.train.images、labels
      • mnist.test.images、labels

2、 實戰:Mnist手寫數字識別

2.1 網路設計

我們採取只有一層,最後一個輸出層的神經網路。也稱之為全連線(full connected)層神經網路。
在這裡插入圖片描述

2.1.1 全連線層計算

  • tf.matmul(a, b,name=None)+bias
    • return:全連線結果,供交叉損失運算

2.2 流程

1、準備資料

2、全連線結果計算

3、損失優化

4、模型評估(計算準確性)

mnist = input_data.read_data_sets("./data/mnist/input_data/", one_hot=True)

    # 1、準備資料
    # x [None, 784] y_true [None. 10]
    with tf.variable_scope("mnist_data"):

        x = tf.placeholder(tf.float32, [None, 784])

        y_true = tf.placeholder(tf.int32, [None, 10])

    # 2、全連線層神經網路計算
    # 類別:10個類別  全連線層:10個神經元
    # 引數w: [784, 10]   b:[10]
    # 全連線層神經網路的計算公式:[None, 784] * [784, 10] + [10] = [None, 10]
    # 隨機初始化權重偏置引數,這些是優化的引數,必須使用變數op去定義
    with tf.variable_scope("fc_model"):
        weight = tf.Variable(tf.random_normal([784, 10], mean=0.0, stddev=1.0), name="w")

        bias = tf.Variable(tf.random_normal([10], mean=0.0, stddev=1.0), name="b")

        # fc層的計算
        # y_predict [None, 10]輸出結果,提供給softmax使用
        y_predict = tf.matmul(x, weight) + bias

    # 3、softmax迴歸以及交叉熵損失計算
    with tf.variable_scope("softmax_crossentropy"):

        # labels:真實值 [None, 10]  one_hot
        # logits:全臉層的輸出[None,10]
        # 返回每個樣本的損失組成的列表
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true,
                                                                      logits=y_predict))

    # 4、梯度下降損失優化
    with tf.variable_scope("optimizer"):

        # 學習率
        train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

2.3 完善模型功能

  • 1、增加準確率計算
  • 2、增加變數tensorboard顯示
  • 3、增加模型儲存載入
  • 4、增加模型預測結果輸出

2.3.1 如何計算準確率

在這裡插入圖片描述

  • equal_list = tf.equal(tf.argmax(y, 1), tf.argmax(y_label, 1))
  • accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))

完整程式碼

# -*- coding=utf-8 -*-
import os
# os.environ["TF_CPP_MIN_LOG_LEVEL"]='1' # 這是預設的顯示等級,顯示所有資訊  
# os.environ["TF_CPP_MIN_LOG_LEVEL"]='2' # 只顯示 warning 和 Error   
# os.environ["TF_CPP_MIN_LOG_LEVEL"]='3' # 只顯示 Error
import time

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data

# 定義一個是否訓練/預測的標誌
tf.app.flags.DEFINE_integer("is_train", 1, "訓練or預測")
# 訓練步數
tf.app.flags.DEFINE_integer("train_step", 0, "訓練模型的步數")
# 定義模型的路徑
tf.app.flags.DEFINE_string("model_dir", " ", "模型儲存的路徑+模型名字")
FLAGS = tf.app.flags.FLAGS


# 此模型終端的執行方法
# python3 day02_05nn_mnist_FullDemo.py --is_train=1 --train_step=2000  # 訓練
# python3 day02_05nn_mnist_FullDemo.py --is_train=0  # 預測

# tensorboard 終端檢視
# tensorboard --logdir="./temp/summary/"


def full_connected_nn():
    """
    全連線層神經網路進行Mnist手寫數字識別訓練
    :return:
    """
    mnist = input_data.read_data_sets("../data/mnist/input_data", one_hot=True)

    # 1、獲得資料,定義特徵值和目標值張量
    with tf.variable_scope("data"):
        # 定義特徵值佔位符
        x = tf.placeholder(tf.float32, [None, 784], name="feature")

        # 定義目標值佔位符
        y_true = tf.placeholder(tf.int32, [None, 10], name="label")

    # 2、根據識別的類別數、建立全連線層網路
    # 手寫數字10個類別
    # 設計了一層的神經網路,最後一層,10個神經元
    # 確定網路的引數weight [784, 10], bias [10]
    # 要進行全連線層的矩陣運算 [None, 784] * [784, 10] + [10] = [None, 10]
    with tf.variable_scope("fc_model"):
        # 隨機初始化權重和偏置引數,要使用變數OP 定義
        weights = tf.Variable(tf.random_normal([784, 10], mean=0, stddev=0.1), name="weights")
        bias = tf.Variable(tf.random_normal([10], mean=0, stddev=1.0), name="bias")

        # 全連線層運算  10個神經元  y_predict=[None, 10]
        y_predict = tf.matmul(x, weights) + bias

    # 3、根據輸出結果與真實結果建立softmax、交叉熵損失計算
    with tf.variable_scope("soft_cross"):
        # 先進行網路輸出的值的概率計算softmax,再進行交叉熵損失計算
        all_loss = tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_predict, name="compute_loss")

        # 求出平均損失
        loss = tf.reduce_mean(all_loss)

    # 4、定義梯度下降優化器進行優化
    with tf.variable_scope("GD"):
        train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

    # 5、求出每次訓練的準確率為
    with tf.variable_scope("accuracy"):
        # 求出每個樣本是否相等的一個列表
        equal_list = tf.equal(tf.argmax(y_true, 1), tf.argmax(y_predict, 1))

        # 計算相等的樣本的比例
        accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))

    # 6、tensorflowboard展示的資料
    # 1)收集要在tensorflowboard觀察的張量值
    # 數值型  --> scalar 準確率, 損失值
    tf.summary.scalar("loss", loss)
    tf.summary.scalar("accuracy", accuracy)

    # 維度高的張量值
    tf.summary.histogram("w", weights)
    tf.summary.histogram("b", bias)

    # 2)合併變數
    merged = tf.summary.merge_all()

    # 7、建立儲存模型的OP
    saver = tf.train.Saver()

    # 8、開啟會話進行訓練
    with tf.Session() as sess:
        # 初始化變數OP
        sess.run(tf.global_variables_initializer())

        # 建立tensorboard的events檔案
        filte_writer = tf.summary.FileWriter("./temp/summary/", graph=sess.graph)

        # 9、載入本地模型繼續訓練或者拿來進行預測測試集
        checkoutpoint = tf.train.latest_checkpoint("./temp/model/fc_nn_model")
        # 判斷模型是否存在
        if checkoutpoint:
            saver.restore(sess, checkoutpoint)

        # 判斷是訓練還是預測
        if FLAGS.is_train == 1:
            # 迴圈訓練
            # for i in range(FLAGS.train_step):
            for i in range(2000):
                # 每批次給50個樣本
                mnist_x, mnist_y = mnist.train.next_batch(50)

                # 檢視資料的尺寸
                # print(mnist_x.shape)

                _, loss_run, accuracy_run, summary = sess.run([train_op, loss, accuracy, merged],
                                                              feed_dict={x: mnist_x, y_true: mnist_y})

                # 列印每步訓練的效果
                print("第{0}步的50個樣本損失為:{1}, 準確率為:{2}".format(i, loss_run, accuracy_run))

                # 3) 寫入執行的結果到檔案當中
                filte_writer.add_summary(summary, i)

                # 每隔100步儲存一次模型的引數
                if i % 100 == 0:
                    # saver.save(sess, FLAGS.model_dir)
                    saver.save(sess, save_path="./temp/fc_nn_model/fc_nn_model")
        else:
            # 進行預測
            # 匯入模型
            # 載入模型,從模型當中找出與當前訓練的模型程式碼當中(名字一樣的OP操作),覆蓋原來的值
            checkoutpoint = tf.train.latest_checkpoint("./temp/fc_nn_model/")
            # 判斷模型是否存在
            if checkoutpoint:
                saver.restore(sess, checkoutpoint)

                # 預測100個樣本
                N = 200
                a = 0
                for i in range(N):
                    image, label = mnist.test.next_batch(1)

                    # 真實的圖片數字
                    result_true = tf.argmax(label, 1).eval()

                    # 神經網路預測的數字
                    result_predict = tf.argmax(sess.run(y_predict, feed_dict={x: image, y_true: label}), 1).eval()

                    # 直接執行網路的輸出預測結果
                    print("第{0}樣本,真實的圖片數字為:{1}, 神經網路預測的數字為:{2}".format(
                        i,
                        result_true,
                        result_predict)
                    )
                    if result_true == result_predict:
                        a += 1

                test_accuracy = (a / N) * 100

                print("測試正確率:", test_accuracy, "%")
            else:
                print("模型不存在,checkoutpoint 請輸出入正確的模型路徑")

    return None


if __name__ == '__main__':
    start_time = time.time()
    full_connected_nn()
    end_time = time.time()
    all_time = end_time - start_time
    print("time:{:.2f} s" .format (all_time))

3、線性神經網路侷限性

任意多個隱層的神經網路和單層的神經網路都沒有區別,而且都是線性的,而且線性模型的能夠解決的問題也是有限的

1、 更復雜抽象的資料

一個單隱含層有更多的神經元,你就能捕捉更多的特徵。而且有更多隱層,意味著你能從資料集中提取更多複雜的結構。
在這裡插入圖片描述

1.1 增加網路深度

在這裡插入圖片描述

1.2 使用非線性啟用函式

在這裡插入圖片描述

2、神經網路更多特性

2.1黑盒子特點

  • 增加網路的深度的確能夠達到效果,但是增加多少?這是一個不確定的問題,或者可以改變神經元的一些特點,改變結構同時增加網路深度,這些都有很多結構進行了嘗試。
  • 不清楚網路內部每個神經元到底在什麼事情

2.2 更多發展

更多神經元 + 更深的網路 = 更復雜的抽象。這也是簡單的神經元如何變得更聰明,並在影象識別、圍棋這些特定問題上表現如此之好的原因。

2.2.1 神經網路拓展介紹

  • 神經網路的種類
    • 基礎神經網路:線性神經網路,BP神經網路,Hopfield神經網路等
    • 進階神經網路:玻爾茲曼機,受限玻爾茲曼機,遞迴神經網路等
    • 深度神經網路:深度置信網路,卷積神經網路,迴圈神經網路,LSTM網路等

在這裡插入圖片描述

Inception:谷歌公開的一個影象識別模型

2.3 兩大挑戰:計算能力和訓練資料

在此文章中,我們看到了一些 TensorFolw Playground 演示解釋了神經網路的機制和能力。就像你看到的那樣,這一技術的基礎非常簡單。每一個神經元只將一個數據點分類成兩個類別中的一個。然而,通過有更多的神經元和深度層,一個神經網路能提取出訓練資料集中隱藏的見解和複雜模式,並且建立抽象的層級結構。

接下來的問題是,為什麼如今還不是每個人都在使用這一偉大的技術?這是因為神經網路還有兩大挑戰。

  • 第一個是訓練深度神經網路需要大量的算力。
  • 第二,它們需要大量的訓練資料集。一個強力的 GPU 伺服器可能要花費數天、甚至數週的時間,才能使用數百萬張影象的資料集訓練出一個深度網路。

而且,為了得到最好的訓練結果,需要結合不同的網路設計與演算法,並進行大量的試錯。如今,一些研究者會使用幾十個 GPU 伺服器,甚至超級計算機來進行大規模分散式的訓練。但在不久的將來,全面管理的分散式訓練與預測服務——比如谷歌 TensorFlow 雲機器學習平臺——可能會解決這些問題,為大家提供成本合理的基於雲的 CPU 和 GPU,而且也可能會把大型的或深度的神經網路的能力開放給每一個人。