TensorFlow安裝與入門: 使用CNN訓練MNIST

上學期鑽研了下Python3人工神經網絡,如多層感知器、卷積神經網絡等算法原理,這學期要在此基礎上使用深度學習研究運動狀態識別的問題。這兩天看了下TensorFlow這個框架,官網的文檔寫的非常詳細,Google大法好啊!在這裏記錄下遇到的小問題,以及參考官網的說明寫的使用CNN訓練MNIST的Python代碼。

TensorFlow安裝

TensorFlow是一個使用數據流圖進行數值計算的開源軟件庫。圖中的節點代表數學運算, 而圖中的邊則代表在這些節點之間傳遞的多維數組(張量)。這種靈活的架構可讓您使用一個 API 將計算工作部署到桌面設備、服務器或者移動設備中的一個或多個 CPU 或 GPU。

按照官網的說明,安裝Tensorflow(GPU版,Windows平臺)需要安裝以下軟件:

  • NVIDIA一塊計算能力大於3的顯卡
  • CUDA® Toolkit 8.0
  • cuDNN v6.1
  • Python 3.5

我臺式機顯卡是GeForce GTX 750,對應的計算能力爲5.0,就湊合着先用。上述環境安裝好後可以直接使用Python自帶的pip3工具安裝Tensorflow:

pip3 install --upgrade tensorflow-gpu

完畢後運行下面的Python腳本已測試是否安裝成功:

import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))

如果能順利運行並且輸出 Hello, TensorFlow! ,那麼就安裝完成了。
安裝的時候要注意添加環境變量(官網上也提示了)。但最終,我的代碼並沒有輸出 Hello, TensorFlow! ,而是提示了什麼DLL錯誤,網上也有很多人遇到了這種錯誤,解決辦法就是 將cuDNN安裝文件夾下的 bin/cudnn64_6.dll文件拷貝到CUDA® Toolkit 8.0安裝目錄的CUDA/v8.0/bin目錄下。

在看官網文檔的時候剛開始沒弄明白Tensor Ranks, Shapes是啥回事,後來看了幾段代碼才整明白。張量的Ranks有點像矩陣的維度,指表示一個值的位置時所需要的座標數量,而shape我的理解是度量了張量各個rank方向上的長度。
比如張量[[1,2],[3,4]]的rank等於2,shape爲[2,2];張量[[1,2],[3,4],[5,6]]的rank等於2,shape爲[3,2]。

使用CNN訓練MNIST

Tensorflow官網給了一個訓練MNIST的詳細步驟:[Deep MNIST for Experts](https://www.tensorflow.org/get_started/mnist/pros)
我在此基礎上將其封裝成了一個類,就當是在熟悉Tensorflow和Python3 :

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

import gzip
import os
import tempfile

import numpy
from six.moves import urllib
from six.moves import xrange

import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets


class Mnist():

    # 第一層卷積輸出特徵數量
    out_features1 = 12
    # 第二層卷積輸出特徵數量
    out_features2 = 24
    # 全連接層神經元數量
    con_neurons = 512

    def __init__(self, path):
        self.sess = tf.Session()
        self.data = read_data_sets(path, one_hot=True)

    """權重初始化函數"""
    def weight_variable(self, shape):
        # 輸出的隨機數滿足 截尾正態分佈
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    """偏置初始化函數"""
    def bias_variable(self, shape):
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial)

    """二維卷積函數"""
    def conv2d(self, x, W):
        # input : 輸入數據[batch, in_height, in_width, in_channels]
        # filter : 卷積窗口[filter_height, filter_width, in_channels, out_channels]
        # strides: 卷積核每次移動步數,對應着輸入的維度方向
        # padding='SAME' : 輸入和輸出的張量形狀相同
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    """池化函數"""
    def max_pool_2x2(self, x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    """構建卷積層"""
    def create_conv_layer(self, input, input_features, out_features):
        W_conv = self.weight_variable([5, 5, input_features, out_features])
        b_conv = self.bias_variable([out_features])
        h_conv = tf.nn.relu(self.conv2d(input, W_conv) + b_conv)
        h_pool = self.max_pool_2x2(h_conv)
        return h_pool

    """構建密集連接層"""
    def create_con_layer(self, h_pool_flat, input_freatures, con_neurons):
        W_fc = self.weight_variable([input_freatures, con_neurons])
        b_fc = self.bias_variable([con_neurons])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool_flat, W_fc) + b_fc)
        return h_fc1

    """神經網絡構建"""
    def build(self):
        # 輸入
        self.x = tf.placeholder(tf.float32, shape=[None, 784])
        x_image = tf.reshape(self.x, [-1, 28, 28, 1])
        # 輸出
        self.y_ = tf.placeholder(tf.float32, shape=[None, 10])

        # 第一層
        h_pool1 = self.create_conv_layer(x_image, 1, self.out_features1)
        # 第二層
        h_pool2 = self.create_conv_layer(h_pool1, self.out_features1, self.out_features2)

        # 密集連接層
        h_pool2_flat_freatures = 7*7*self.out_features2
        h_pool2_flat = tf.reshape(h_pool2, [-1, h_pool2_flat_freatures])
        h_fc = self.create_con_layer(h_pool2_flat, h_pool2_flat_freatures, self.con_neurons)

        # Dropout
        self.keep_prob = tf.placeholder("float")
        h_fc1_drop = tf.nn.dropout(h_fc, self.keep_prob)

        # 輸出層
        W_fc = self.weight_variable([self.con_neurons, 10])
        b_fc = self.bias_variable([10])
        y_conv = tf.matmul(h_fc1_drop, W_fc) + b_fc

        # 評價
        correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(self.y_, 1))
        self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

        # 訓練方法
        cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=self.y_, logits=y_conv))
        self.train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

    """訓練"""
    def train(self):
        self.sess.run(tf.global_variables_initializer())
        for i in range(2000):
            batch = self.data.train.next_batch(50)
            if i % 100 == 0:
                print('Training step %d:' % i)
                self.eval(batch[0], batch[1], 1.0)
            self.sess.run(self.train_step, {self.x: batch[0], self.y_: batch[1], self.keep_prob: 0.5})

    """評價"""
    def eval(self, x, y, keep_prob):
        train_accuracy = self.sess.run(self.accuracy, {self.x: x, self.y_: y, self.keep_prob: keep_prob})
        print('     accuracy %g' % train_accuracy)
        return train_accuracy

    """關閉會話"""
    def close(self):
        self.sess.close()


""" START """
mnist = Mnist('MNIST_data/')
mnist.build()
mnist.train()
print('\n----- Test -----')
mnist.eval(mnist.data.test.images, mnist.data.test.labels, 1.0)
mnist.close()

這段代碼應該能直接運行,但是參數和官網有所區別(顯卡太渣了,按照官網的參數跑會報OOM錯誤),最後的測試準確率也就0.9683(只迭代了2000次,調成20000次後會更接近於官網的結果)。不過這段代碼涉及到了很多Tensorflow的基本知識,比如會話、佔位符、圖、構建圖、Feed等等。

總之要繼續努力,室友警告這一塊是個大坑。。。萬一畢不了業怎麼辦-_-||

參考鏈接:
Tensorflow官網

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章