【Tensorflow学习笔记】1:注解MNIST手写数字分类

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/82973698

跟着官方文档敲了MNIST手写数字识别的两个TF程序,没接触之前还以为底层计算也是使用的Python,原来Python只是用来描述计算图和何时计算的。

虽然Tensor翻译过来就是张量,但目前还是不理解它和我们认知的张量有什么关系,暂且理解成一个数据容器,可以存储多维的数据,还有一些TF中特殊的操作。

Placeholder就是用于数据输入的位置,先占位才构建出整个图来。Variable用来创建模型中变化的参数,TF可以自动用BP来调整它。而那些超参数才是使用TF的程序员需要关心的。

Softmax回归

from tensorflow.examples.tutorials.mnist import input_data  # Tensorflow自带的MNIST数据集的读取模块
import tensorflow as tf

# 忽略CPU扩展,我的CPU支持AVX扩展
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# 用这个读取模块读入MNIST数据集,指定存储位置,指定将28x28图像方阵转为一维向量(1x784)
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# 占位符,在TF运行计算时再输入其具体的值,数据元素的类型是float,格式是任意行784列,即每行表示一个图像的展开向量
x = tf.placeholder("float", [None, 784])

# 初始化模型参数,模型参数在训练中是用TF的变量来初始化
W = tf.Variable(tf.zeros([784, 10]))  # 权重矩阵,将任意行784列的输入x转换成这么多行10列的带偏结果
b = tf.Variable(tf.zeros([10]))  # 偏置,xW乘完的结果每行都加上这个偏置

# 模型的实现,这里y是预测值
y = tf.nn.softmax(tf.matmul(x, W) + b)  # 预测值y=softmax函数(xW+b)

# 用于存储真实值的占位符,这里y_对应公式里的y'
y_ = tf.placeholder("float", [None, 10])

# 计算交叉熵,公式是-sum(y'*log(y)),衡量预测用于描述真相的低效性
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))  # 这里tf.reduce_sum计算张量的所有元素的总和

# 指定优化算法,在定义的计算图内增加计算操作,TF会自动实现BP来调整模型参数
# 用梯度下降算法以0.01的学习速率最小化交叉熵
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

# 要初始化所有创建的tf.Variable变量
init = tf.global_variables_initializer()
# 创建一个TF的会话
session = tf.Session()
# 在这个会话中启动模型,初始化变量
session.run(init)

# 开始训练模型,让模型循环1000次
# (这里是随机梯度下降训练,既可以减少计算开销,又可以最大化地学习到数据集的总体特性)
for i in range(1000):
    # 每次随机抓取训练集中的100个数据及其标签
    batch_xs, batch_ys = mnist.train.next_batch(100)
    # 用这些数据替换到之前定义的placeholder中,来运行前面定义的优化算法train_step以做训练
    session.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})  # 注意y_才是真实标签占位符

# ---------------下面是测试部分---------------

# tf.argmax(TF对象,维度数),返回该TF对象在这一维度上最大值所在的下标位置
# 预测结果,或者原始数据的标签都是1x10的向量,预测的结果正是其在第1维(即列)上数字最大的那个位置
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))  # 得到的是一组是否相等的布尔值
# 将布尔值转换成浮点数,即True变1.0而False变0.0,然后再取平均,就得到了精度(accuracy)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

# 计算在测试数据集上的accuracy
print(session.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

输出:

0.91

DCNN

这个在我的CPU上运行起来太慢了。

from tensorflow.examples.tutorials.mnist import input_data  # Tensorflow自带的MNIST数据集的读取模块
import tensorflow as tf

# 用这个读取模块读入MNIST数据集,指定存储位置,指定将28x28图像方阵转为一维向量(1x784)
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# 占位符,在TF运行计算时再输入其具体的值,数据元素的类型是float,格式是任意行784列,即每行表示一个图像的展开向量
x = tf.placeholder("float", [None, 784])
# 把图像变成4d向量,-1表示自动计算,宽,高,通道数
x_image = tf.reshape(x, [-1, 28, 28, 1])

# 用于存储真实值的占位符,这里y_对应公式里的y'
y_ = tf.placeholder("float", [None, 10])


# 权重的初始化
def weight_variable(shape):
    # 生成正态分布的tensor,shape表示维度,mean为均值(默认是0),stddev是标准差
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)  # 模型参数以变量的形式存在


# 偏置的初始化
def bias_variable(shape):
    # 生成以某常量值填充的指定维度的tensor
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)  # 模型参数以变量的形式存在


# 卷积
def conv2d(x, W):
    # input:输入图像,filter:卷积核,strides:卷积时图像在每一维的步长,padding:卷积方式
    return tf.nn.conv2d(input=x, filter=W, strides=[1, 1, 1, 1], padding='SAME')


# 池化
def max_pool_2x2(x):
    # value:池化层输入,ksize:池化窗口大小,strides:窗口在每一个维度上滑动的步长,padding:池化方式
    return tf.nn.max_pool(value=x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')


########## 第一层卷积
# 获取卷积的权重张量,5*5的patch,1个输入,32个输出
W_conv1 = weight_variable([5, 5, 1, 32])
# 因为前面输出是32,这里偏置就也是32
b_conv1 = bias_variable([32])

# 变换后的图像和权向量进行卷积,然后加上偏置再送入ReLU激活
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
# 进行max_pooling
h_pool1 = max_pool_2x2(h_conv1)

########## 第二层卷积
# 5*5的patch,32个输入,64个输出
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

# 上一层的输出和这一层的权向量进行卷积,然后加上偏置再送入ReLU激活
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
# 进行max_pooling
h_pool2 = max_pool_2x2(h_conv2)

########## 全连接层
# 图片尺寸减小到了7*7,上一层的输出是64个,该层是和1024个神经元的fullyconnected层
W_fc1 = weight_variable([7 * 7 * 64, 1024])
# 1024个神经元,所以是1024长度的偏置
b_fc1 = bias_variable([1024])
# 调整上一层输出的形状
h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
# 在这个全连接层上的处理
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

########## Dropout层防止过拟合
# 这个占位符表示神经元的输出在Dropout层保持不变的概率
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

########## softmax层作输出层,转成10阶的向量
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

########## 训练和评估模型
# 交叉熵损失
cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv))
# 以1e-4的速率最小化交叉熵
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
# True/False列表
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
# 精度,bool变1/0在取平均
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
# 创建一个TF的会话
session = tf.Session()
# 在这个会话中启动模型,初始化变量
session.run(tf.global_variables_initializer())

# 模型循环20000次
for i in range(20000):
    # 每次随机抓取训练集中的50个数据及其标签
    batch_xs, batch_ys = mnist.train.next_batch(100)
    # 每100次迭代输出一次日志
    if i % 100 == 0:
        train_accuracy = accuracy.eval(feed_dict={x: batch_xs, y_: batch_ys, keep_prob: 1.0}, session=session)
        print("step %d, training accuracy %g" % (i, train_accuracy))
    train_step.run(feed_dict={x: batch_xs, y_: batch_ys, keep_prob: 0.5}, session=session)

# 测试错误率
print("Test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.lables, keep_prob: 1.0},
                                         session=session))

输出:

step 0, training accuracy 0.08
step 100, training accuracy 0.89
step 200, training accuracy 0.9
step 300, training accuracy 0.93
step 400, training accuracy 0.95
step 500, training accuracy 0.97
step 600, training accuracy 0.94
step 700, training accuracy 0.99
step 800, training accuracy 0.95
step 900, training accuracy 0.97
...

猜你喜欢

转载自blog.csdn.net/SHU15121856/article/details/82973698