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官网

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