Tensorflow-MNIST-手寫數(shù)字圖像識別案例-翻譯整理

本篇文章主要介紹如何創(chuàng)建卷積神經(jīng)網(wǎng)絡(CNN:Convolutional Neural Network)用來訓練模型,識別手寫數(shù)字圖片。

Tensorflow的layer模型可以幫助我們方便的構建神經(jīng)網(wǎng)絡,包括密集層dense layer layer(full-connected layer全連接層)或卷積層convolutional layer。


下載數(shù)據(jù)集

這個數(shù)據(jù)集包含了6000個訓練樣本和1000個測試樣本,都是手寫數(shù)字0~9,灰度圖片28像素x28像素。

MNIST dataset 手寫數(shù)字集圖片官方地址
百度網(wǎng)盤下載,密碼:w0sk


代碼框架

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

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

tf.logging.set_verbosity(tf.logging.INFO) #設定輸出日志的模式

#我們的程序代碼將放在這里

#這個文件能夠直接運行,也可以作為模塊被其他文件載入
if __name__ == "__main__":
  tf.app.run()

關于卷積神經(jīng)網(wǎng)絡

卷積神經(jīng)網(wǎng)絡Convolutional neural networks (CNNs) 是目前圖像識別領域最先進的模型結構。CNNs對圖像應用各種過濾并從中學習得到高級結構,進而實現(xiàn)圖像分類。

卷積神經(jīng)網(wǎng)絡包含3個組成部分:

  • Convolutional layers卷積層 對圖像應用特定數(shù)量的卷積過濾。對于每個子區(qū)域,神經(jīng)層都會在輸出特征映射中產(chǎn)生單個值,卷積層通常會將一個ReLU(Rectified Linear Units修正線性單元)激活函數(shù)應用到輸出,進而在模型內(nèi)產(chǎn)生一個非線性的結果。

修正線性單元 (ReLU, Rectified Linear Unit),一種激活函數(shù),?(x)=max(0,x),其規(guī)則如下:如果輸入為負數(shù)或 0,則輸出 0;如果輸入為正數(shù),則輸出等于輸入。ReLU屬于非飽和算法non-saturating neurons,就是說沒有把輸出值限定在某個特定區(qū)間,與它對應的飽和算法有sigmod:?(x)=(1+e-x)-1;tanh:?(x)=|tanh(x)|,?(x)=tanh(x);

激活函數(shù) (activation function),一種函數(shù)(例如ReLUS型函數(shù)),用于對上一層的所有輸入求加權和,然后生成一個輸出值(通常為非線性值),并將其傳遞給下一層。

  • Pooling layers池化層,對卷積層提取的圖像數(shù)據(jù)進行向下采樣,減少特征維度,加快處理速度。常用的池化算法是最大化池化max pooling,它把輸入的圖像分成不重疊的子矩形區(qū)域,對每個子區(qū)域,保留最大值,忽略其他值,也控制了整體的過采樣。理論基礎是特征之間的關聯(lián)比局部特征更加重要。

  • Dense layer密集層(full-connected layer全連接層),基于卷積層提取的特征和池化層的向下采樣,進行分類classification。

    RoI pooling to size 2x2. In this example region proposal (an input parameter) has size 7x5.

標準意義上講,CNN網(wǎng)絡是組合堆疊多個卷機模塊,進行特征提取。每個卷積模塊包含一個卷積層以及跟隨其后的池化層。最后的卷積模塊跟隨著一個或多個密集層以進行分類。CNN網(wǎng)絡中最后的密集層為每個可能的分類設定了一個節(jié)點,并對這每個節(jié)點使用sigmod函數(shù)輸出0~1之間的值,表示該圖形屬于某個分類的可能性。


構建CNN MNIST分類器

  1. Convolutional Layer卷積層 #1: 應用 32 5x5 濾鏡提取5x5像素子區(qū)域,使用ReLU激活函數(shù)
  2. Pooling Layer池化層 #1: 執(zhí)行最大化池化2x2濾鏡,步幅stride=2確保區(qū)域不重疊
  3. Convolutional Layer卷積層 #2: 應用64 5x5過濾,使用ReLU激活函數(shù)
  4. Pooling Layer池化層 #2: Again, performs max pooling with a 執(zhí)行最大池化2x2過濾,步幅2
  5. Dense Layer密集層 #1: 1,024個神經(jīng)元, 丟棄正則率0.4 (訓練過程中可能性低于0.4的元素將被丟棄)
  6. Dense Layer密集層 #2 (Logits Layer邏輯層): 10個神經(jīng)元, 對應0~9數(shù)字

tf.layers對象包含了創(chuàng)建以上三種神經(jīng)層的方法:

  • conv2d(),創(chuàng)建2維的卷積層,參數(shù)包含:過濾數(shù)量,過濾核心尺寸,填充padding,激活函數(shù)。
  • max_pooling2d(), 使用最大化算法創(chuàng)建一個2維池化層。參數(shù)包含:過濾尺寸、步幅。
  • dense(),創(chuàng)建密集層,參數(shù)包含:神經(jīng)元數(shù)量、激活函數(shù)。

這些方法都接收一個張量tensor作為輸入,然后經(jīng)過變換再輸出一個新的張量,這樣就可以一環(huán)一環(huán)相連起來。

接下來我們向代碼結構文件中添加cnn_model_fn(features, labels, mode)函數(shù),它接收MNIST數(shù)據(jù)的特征、標簽和mode(TRAIN,EVAL,PREDICT),返回train訓練、loss損失函數(shù)、predict預測三個方法。這是Tensorflow Estimator的標準接口。

更多自定義Estimator的詳情請看Tensorflow-Estimator-自定義估算器以及Tensorflow-Estimator-估算器-翻譯整理兩篇文章。

添加后的代碼如下:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

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

tf.logging.set_verbosity(tf.logging.INFO) #設定輸出日志的模式

#我們的程序代碼將放在這里
def cnn_model_fn(features, labels, mode):
    #輸入層,-1表示自動計算,這里是圖片批次大小,寬高各28,最后1表示顏色單色
    input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

    #1號卷積層,過濾32次,核心區(qū)域5x5,激活函數(shù)relu
    conv1 = tf.layers.conv2d(
        inputs=input_layer,#接收上面創(chuàng)建的輸入層輸出的張量
        filters=32,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    #1號池化層,接收1號卷積層輸出的張量
    pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

    #2號卷積層
    conv2 = tf.layers.conv2d(
        inputs=pool1,#繼續(xù)1號池化層的輸出
        filters=64,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)
    
    #2號池化層
    pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

    #對2號池化層的輸入變換張量形狀
    pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
    
    #密度層
    dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
    
    #丟棄層進行簡化
    dropout = tf.layers.dropout(
      inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

    #使用密度層作為最終輸出,unit可能的分類數(shù)量
    logits = tf.layers.dense(inputs=dropout, units=10)
    
    #預測和評價使用的輸出數(shù)據(jù)內(nèi)容
    predictions = {
      #產(chǎn)生預測,argmax輸出第一個軸向的最大數(shù)值
      "classes": tf.argmax(input=logits, axis=1),
      #輸出可能性
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

    #以下是根據(jù)mode切換的三個不同的方法,都返回tf.estimator.EstimatorSpec對象
  
    #預測
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    #損失函數(shù)(訓練與評價使用),稀疏柔性最大值交叉熵
    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

    #訓練,使用梯度下降優(yōu)化器,
    if mode == tf.estimator.ModeKeys.TRAIN:
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(
            loss=loss,
            global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

    #評價函數(shù)(上面兩個mode之外else)添加評價度量(for EVAL mode)
    eval_metric_ops = {
        "accuracy": tf.metrics.accuracy(
            labels=labels, predictions=predictions["classes"])}
    return tf.estimator.EstimatorSpec(
        mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)



#這個文件能夠直接運行,也可以作為模塊被其他文件載入
if __name__ == "__main__":
  tf.app.run()

這時候以上代碼還不能運行。以下將逐個代碼塊詳細解說。


Input Layer輸入層

tf.layers中創(chuàng)建神經(jīng)層的方法參數(shù)格式是:
[batch_size,imgage_width,imgage_height,channels]

  • batch_size批次尺寸,在訓練過程中梯度下降所使用的樣本子集的大小。
  • image_width和image_height,圖像的寬高。
  • channels通道,圖片像素的顏色通道數(shù),一般是3(RGB),在這里是黑白圖片只有1個顏色。

MNIST的圖片是28x28單色,[batch_size,28,28,1],我們用-1表示依靠features['x']數(shù)量動態(tài)計算得到這個數(shù)值,那么把它變換一下:

input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

在這里batch_size作為一個超參數(shù)hyperparameters,如果我們使用batch_size=5,那么input_layers的形狀就是[5,28,28,1],它將包含5x28x28x1=3920個值,每個值表示一個顏色,每784個值表示一張圖,5張為一批次。


Convolutional layer #1卷積層1號

conv1 = tf.layers.conv2d(
    inputs=input_layer,
    filters=32,
    kernel_size=[5, 5],
    padding="same",
    activation=tf.nn.relu)

我們使用了32次5x5像素過濾filters,使用ReLU作為激活函數(shù)。由于承接了input_layer的輸出,所以進入的張量形狀是[batch_size,28,28,1].
padding參數(shù)有兩個可選,默認的"valid"或"same",為了保持輸出的寬高不變,我們選擇了"same",Tensorflow會自動用0補齊以確保圖像是28x28像素。(如果不使用padding,那么在28x28個網(wǎng)格中只有24x24的區(qū)域可以放置5x5的面片,如下圖所示黃色區(qū)域,也就是會產(chǎn)生24x24的張量。)

激活函數(shù)ReLU將應用在卷積輸出的張量上。最終從conv2d層輸出的張量形狀是[batch_size,28,28,32],這里的32是指我們進行了32次過濾產(chǎn)生的不同結果。


Pooling Layer #1池化層1號

pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

conv1作為輸入層,將會輸入的張量形狀是[batch_size,28,28,32]。
pool_size設定了最大池化過濾的尺寸[width,height]就是[2,2]。
stredes表示過濾的步長,我們這里設定了stredes=2,表示濾鏡對子區(qū)域subregions進行提取是按照寬高分別間隔2像素進行的,由于過濾尺寸也是[2,2],所以不會產(chǎn)生重疊也不會產(chǎn)生丟失。



max_pooling層pool1輸出的張量形狀是[batch_size,14,14,32],因為2x2過濾把寬高減少了一半。


Convolutional layer #2 & Pooling layer #2卷積層2號和池化層2號

conv2 = tf.layers.conv2d(
    inputs=pool1,
    filters=64,
    kernel_size=[5, 5],
    padding="same",
    activation=tf.nn.relu)

pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

2號卷積層我們使用了64次5x5區(qū)域的過濾,仍然是ReLU激活函數(shù)。而2號池化層我們?nèi)匀皇褂昧薣2,2]區(qū)域2步幅間隔的設定。

注意2號卷積層設定了padding="same"且64次過濾,所以輸出的張量形狀是[batch_size,14,14,64]。
池化層2號則再次把維度降低到[batch_size,7,7,64]。


Dense layer密集層

接下來我們將添加一個1024神經(jīng)元ReLU激活的密集層(全連接層),基于上面卷積層和池化層得到的結果進行分類。

首先,我們把上面pool2池化層得到的特征映射features map([batch_size,7,7,64])展開,轉(zhuǎn)換到[batch_size,features]。

pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])

-1表示這個維度根據(jù)計算得到,在這里我們將得到一個[batch_size,3136]的張量(7764=3136)。

然后我們再把這個結果傳遞到密集層Dense layer:

dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)

為了改進我們模型的結果,增加一個dropout丟棄規(guī)則,

dropout = tf.layers.dropout(
    inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

這里rate=0.4表示在訓練過程中,40%的元素會被隨機丟棄。注意training參數(shù)限定了盡在訓練模式下才執(zhí)行隨機丟棄,預測和評價時候不丟棄。

最終,由于使用了1024個神經(jīng)元,dropout輸出的張量形狀是[batch_size,1024]。


Logits layer邏輯層

邏輯層是我們神經(jīng)網(wǎng)絡的最后一層,他將輸出預測的原始數(shù)據(jù)。我們使用dense創(chuàng)建了10個神經(jīng)元的密集層,表示0~9個數(shù)字,使用默認的linear線性激活函數(shù)。

logits = tf.layers.dense(inputs=dropout, units=10)

這樣,我們的CNN卷積神經(jīng)網(wǎng)絡最后輸出的張量形狀就是[batch_size,10]。


生成預測函數(shù)

以上,邏輯層生成的張量是[batch_size,10]。我們用兩個函數(shù)將這個原始數(shù)據(jù)轉(zhuǎn)為兩個不同的格式,作為最終的預測結果:

  • 每個樣本的預測分類predicted class,0~9中的一個數(shù)字。
  • 每個樣本屬于每個分類的可能性probabilities,樣本可能是0,可能是1,可能是2,可能是...

tf.argmax(input=logits, axis=1)

對于我們這個案例,每個樣本的預測分類,就是邏輯層輸出張量中對應行中值最高的元素。我們使用argmax方法取得它:

tf.argmax(input=logits, axis=1)

注意這里axis等于1而不是0,因為我們從邏輯層獲得的張量形狀是[batch_size,10],也就是10對應的列中每個元素,選取值最大的元素返回。

我們把預測結果封裝到一個字典,放入EstimatorSpec對象:

predictions = {
    "classes": tf.argmax(input=logits, axis=1),
    "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
}
if mode == tf.estimator.ModeKeys.PREDICT:
  return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

Calculate loss計算損失函數(shù)

對于訓練和預測,我們需要定義一個損失函數(shù)loss function來評估我們的模型預測的有多么準確。對于多個類別的分類問題,交叉熵算法是最常用的測量標準。

onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=10)
loss = tf.losses.softmax_cross_entropy(
    onehot_labels=onehot_labels, logits=logits)

這里cast是轉(zhuǎn)變數(shù)據(jù)類型的方法,labels的數(shù)據(jù)類似[1, 9, 6,7,3...],我們把它轉(zhuǎn)為one_hot獨熱格式的張量:

[[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
 ...]

tf.one_hot帶有兩個參數(shù):

  • indices索引,獨熱數(shù)組哪一個熱,比如上面第一行對應的labels是1,就是第1個是1(其他都是0);
  • depth深度,獨熱數(shù)組有多少個元素,在這里就是有多少個分類。

然后,我們計算onehot_labels和邏輯層輸出的張量[batch_size,10]的這兩者的柔性最大交叉熵。

loss = tf.losses.softmax_cross_entropy(
    onehot_labels=onehot_labels, logits=logits)

tf.losses.softmax_cross_entropy方法返回一個標量scalar張量。


設置訓練操作Configure the training Op

在以上,我們定義了loss函數(shù)用于評估我們預測模型最終logits層輸出的結果與實際標簽labels的差異度,下面讓我們的模型在訓練的時候反復優(yōu)化這個差異度,讓模型達到最佳。
我們使用隨機梯度下降函數(shù)stochastic gradient desent作為優(yōu)化算法,使用學習率learning_rate=0.1:

if mode == tf.estimator.ModeKeys.TRAIN:
  optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
  train_op = optimizer.minimize(
      loss=loss,
      global_step=tf.train.get_global_step())
  return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

在這里,我們看到,所謂的訓練操作train_op就是優(yōu)化函數(shù)optimizer根據(jù)損失函數(shù)loss,一步一步嘗試構造更好的模型結構。


添加評價度量Evaluation metrics

eval_metric_ops = {
    "accuracy": tf.metrics.accuracy(
        labels=labels, predictions=predictions["classes"])}
return tf.estimator.EstimatorSpec(
    mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)

訓練和評價CNN MNIST分類器

上面我們已經(jīng)完成了CNN MNIST模型函數(shù)的編寫,下面我們繼續(xù)實現(xiàn)模型的訓練和預測。


載入訓練和測試數(shù)據(jù)

首先從把從百度網(wǎng)盤(密碼:w0sk)下載的MNIST_data文件夾(包含四個文件)放在和我們的代碼相同目錄下。

然后我們添加main主函數(shù),代碼載入數(shù)據(jù)集

dir_path = os.path.dirname(os.path.realpath(__file__))
data_path=os.path.join(dir_path,'MNIST_data')
def main(args):
    #載入訓練和測試數(shù)據(jù)
    mnist = input_data.read_data_sets(data_path)
    train_data = mnist.train.images #得到np.array
    train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
    eval_data = mnist.test.images #得到np.array
    eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)

你也可以參照 這篇文章 自己手工從官方下載這個數(shù)據(jù)集。


創(chuàng)建估算器Estimator

Estimator是Tensorflow的一個高級接口high-level API,專門用來對模型進行訓練、和評估和預測的。

在main里面添加下面的代碼

    #創(chuàng)建估算器
    mnist_classifier = tf.estimator.Estimator(
        model_fn=cnn_model_fn, model_dir="/tmp/mnist_convnet_model")

這里使用的兩個參數(shù):

  • model_fn,我們在上面創(chuàng)建神經(jīng)網(wǎng)絡CNN的主要函數(shù),里面實現(xiàn)了訓練、評價和預測功能。
  • model_dir,這是設置我們訓練出來的模型存儲的目錄,只要這里設置一次,以后Tensorflow都會自動從這里讀取我們訓練好的模型,不需要我們添加任何其他代碼。當然也可以再訓練,會覆蓋更新。

設置日志鉤子logging hook

CNN訓練需要花一點時間,呆看屏幕沒有任何反應等待會很難熬,我們可以讓Tensorflow在訓練的時候輸出一些有用的日志信息。

    #設置輸出預測的日志
    tensors_to_log = {"probabilities": "softmax_tensor"}
    logging_hook = tf.train.LoggingTensorHook(
        tensors=tensors_to_log, every_n_iter=50)

我們在這里用tensors_to_log字典來存儲需要打印出來的數(shù)據(jù),注意這里的softmax_tensor,實際是我們在上面定義過的名稱(實際上我們在編寫整個計算模型時候定義的張量name都可以):

predictions = {
      "classes": tf.argmax(input=logits, axis=1),
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

然后,我們創(chuàng)建了鉤子函數(shù)LoggingTensorHook,并關聯(lián)到我們的需要輸出的張量,每50次迭代打印一次。


訓練模型

為了訓練模型,我們必須創(chuàng)建一個喂食數(shù)據(jù)的函數(shù)train_input_fn,向main函數(shù)添加以下代碼:

    #訓練喂食函數(shù)
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": train_data},
        y=train_labels,
        batch_size=100,
        num_epochs=None,
        shuffle=True)

我們使用了numpy_input_fn方法,它的參數(shù)里面xy對應了我們的訓練特征數(shù)據(jù)和訓練標簽數(shù)據(jù),batch_size表示每步數(shù)step最少訓練100個樣本,num_epochs=None周期數(shù)不設定表示我們一直訓練直到到達指定步數(shù)為止(訓練時候設定)。shuffle=true洗牌為真表示我們將隨機調(diào)整樣品順序。

我們再向main函數(shù)添加代碼啟動訓練:

    #啟動訓練
    mnist_classifier.train(
        input_fn=train_input_fn,
        steps=20000,
        hooks=[logging_hook])

在這里我們設定了步數(shù)20000,并且把日志鉤子logging_hook傳遞進去。

不要著急,我們先繼續(xù)添加一些其他內(nèi)容。


評價模型Evaluate model

訓練完成后,我們希望使用測試數(shù)據(jù)集來評估一下我們的模型的精確度,看它是否足夠好。繼續(xù)向main函數(shù)添加下面的代碼:

    #評價喂食函數(shù)
    eval_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": eval_data},
        y=eval_labels,
        num_epochs=1,
        shuffle=False)
    
    #啟動評價并輸出結果
    eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)
    print(eval_results)

同樣,我們也需要一個評價喂食函數(shù),不斷把需要評價的圖片數(shù)據(jù)輸入到模型,然后再把模型輸出的預測結果和我們真實的標簽對比,這樣就能知道我們的模型是不是足夠準確。
注意在這里我沒設置周期是1,不進行反復訓練;設置shuffle=False也不隨機調(diào)整順序。


運行吧!

整個過程可能需要一些時間,不要著急,訓練20000步數(shù)會很慢,請耐心等候。

續(xù),十多分鐘過去了,目前才到step3000多...求祝福,求光環(huán)...
續(xù),我也不知道最終用了多久,大概1個多小時,這是運行后的結果,精度接近97%:

INFO:tensorflow:Saving dict for global step 20004: accuracy = 0.9691, global_step = 20004, loss = 0.10082044
{'accuracy': 0.9691, 'loss': 0.10082044, 'global_step': 20004}

下面是完整代碼,如果你的代碼運行中出現(xiàn)問題,可以復制它:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

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

tf.logging.set_verbosity(tf.logging.INFO) #設定輸出日志的模式

#我們的程序代碼將放在這里
def cnn_model_fn(features, labels, mode):
    #輸入層,-1表示自動計算,這里是圖片批次大小,寬高各28,最后1表示顏色單色
    input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

    #1號卷積層,過濾32次,核心區(qū)域5x5,激活函數(shù)relu
    conv1 = tf.layers.conv2d(
        inputs=input_layer,#接收上面創(chuàng)建的輸入層輸出的張量
        filters=32,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    #1號池化層,接收1號卷積層輸出的張量
    pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

    #2號卷積層
    conv2 = tf.layers.conv2d(
        inputs=pool1,#繼續(xù)1號池化層的輸出
        filters=64,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)
    
    #2號池化層
    pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

    #對2號池化層的輸入變換張量形狀
    pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
    
    #密度層
    dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
    
    #丟棄層進行簡化
    dropout = tf.layers.dropout(
      inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

    #使用密度層作為最終輸出,unit可能的分類數(shù)量
    logits = tf.layers.dense(inputs=dropout, units=10)
    
    #預測和評價使用的輸出數(shù)據(jù)內(nèi)容
    predictions = {
      #產(chǎn)生預測,argmax輸出第一個軸向的最大數(shù)值
      "classes": tf.argmax(input=logits, axis=1),
      #輸出可能性
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

    #以下是根據(jù)mode切換的三個不同的方法,都返回tf.estimator.EstimatorSpec對象
  
    #預測
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    #損失函數(shù)(訓練與評價使用),稀疏柔性最大值交叉熵
    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

    #訓練,使用梯度下降優(yōu)化器,
    if mode == tf.estimator.ModeKeys.TRAIN:
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(
            loss=loss,
            global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

    #評價函數(shù)(上面兩個mode之外else)添加評價度量(for EVAL mode)
    eval_metric_ops = {
        "accuracy": tf.metrics.accuracy(
            labels=labels, predictions=predictions["classes"])}
    return tf.estimator.EstimatorSpec(
        mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)



dir_path = os.path.dirname(os.path.realpath(__file__))
data_path=os.path.join(dir_path,'MNIST_data')
def main(args):
  #載入訓練和測試數(shù)據(jù)
    mnist = input_data.read_data_sets(data_path)
    train_data = mnist.train.images #得到np.array
    train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
    eval_data = mnist.test.images #得到np.array
    eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)
    
    #創(chuàng)建估算器
    mnist_classifier = tf.estimator.Estimator(
        model_fn=cnn_model_fn, model_dir="/tmp/mnist_convnet_model")
    
    #設置輸出預測的日志
    tensors_to_log = {"probabilities": "softmax_tensor"}
    logging_hook = tf.train.LoggingTensorHook(
        tensors=tensors_to_log, every_n_iter=50)
    
    #訓練喂食函數(shù)
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": train_data},
        y=train_labels,
        batch_size=100,
        num_epochs=None,
        shuffle=True)
    
    #啟動訓練
    mnist_classifier.train(
        input_fn=train_input_fn,
        steps=20000,
        hooks=[logging_hook])
    
    #評價喂食函數(shù)
    eval_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": eval_data},
        y=eval_labels,
        num_epochs=1,
        shuffle=False)
    
    #啟動評價并輸出結果
    eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)
    print(eval_results)    


#這個文件能夠直接運行,也可以作為模塊被其他文件載入
if __name__== "__main__":
    tf.app.run()

探索人工智能的新邊界

如果您發(fā)現(xiàn)文章錯誤,請不吝留言指正;
如果您覺得有用,請點喜歡;
如果您覺得很有用,感謝轉(zhuǎn)發(fā)~


END

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容