MNIST数字识别


准备工作

变量管理

# get_variable
#根据变量名称直接获取,如果不存在就创建一个新的
emb = tf.get_variab1e(name="emb"#变量名称(必填)
                                            shape #词向量维度
                                            initializer) # 词向量矩阵, 训练好的
# Variable
#创建一个新的变量,用具体的值初始化,变量名称可选
emb = tf.Variable(initializer,#词向量矩阵,训练好的
                                    name="emb" #变量名称(可选)

tf.Variable + tf. name_ scope通过组合可以简化命名参数,合理组织参数,在Tensorboard可视化展示过程中更加清晰结构逻辑
tf.get_variable + tf.variab1e_scope主要用于实现参数共享

Variable+name_ scope

#在conv1命名空间下定义变量
with tf.name_scope('conv1') as scope:
            weights1 = tf.Variable([1.0, 2.0] , name= 'weights')
            bias1 = tf.Variable([0.3], name='bias')
#在conv2命名空间下定义变量
with tf . name_ scoрe(' conv2') as scope :
            weights2 = tf.Variable([4.0, 2.0], name= 'weights')
            bias2 = tf.Variable([0.33], name='bias')
print (weights1.name) # conv1/wei ghts
print (weights2.name) # conv2/wei ghts

get_variable +variable_scope

#根据变量名称直接获取,如果不存在就创建一个新的
with tf.variable_scope(“s1"):
V = get_variab1e(“V", shape1, initializer1)
#创建失败,由于变量名“V”已经存在
v1 = get_variab1e(“v", shape1)
#如果已经存在,直接返回当前变量
with tf.variab1e_scope(“s1", reuse=True):
v2 = get_variab1e(“V", shape1)
#输出True, 都是s1/v
print (V==v2)

#変量空囘s1下創建変量v
with tf.variab1e_scope("s1"):
v = get_variab1e(“v", shape1, initializer1)
print (V) #輸出s1/v:0

#変量空囘s2下創建変量v
with tf.variab1e_scope("s2"):
v = get_variab1e(“v", shape1)
print (V) #輸出s2/v:0

#変量空囘s2下創建変量v
V = get_variab1e(“s1/v", shape1)

variable_scope VS . name_scope

#在name_scope下凋用get_variable
with tf.name_scope(“s1"):
            v = get_variable(“v", shape1, initializer1)
print (V) #輸出v:0
#在variable_scope下凋用Variable
with tf.variab1e_scope(“s2"):
v = tf.Variab1e(“v", shape1)
print (v) #輸出s2/v:0

get_variable是不受name_scope的限制

持久化管理

保存

# 前续TensorFlow代码
......
#用于保存模型参数
saver = tf.train.Saver()
With tf.Session() as sess:
          ......
            #保存模型到制定路径下
            saver.save(sess, "path/to/model/model.ckpt")

生成三个文件:

  1. model.ckpt.meta 计算图结构,模型结构
  2. model.ckpt 模型参数
  3. checkpoint 所有模型文件列表

部分保存

# 前续TensorFlow代码
......
#用于保存模型参数,通过词典给出要保存的参数列表
saver = tf.train.Saver({"v1":v1, "v2":v2})
With tf.Session() as sess:
          ......
            #保存模型到制定路径下
            saver.save(sess, "path/to/model/model.ckpt")

导入

# 前续TensorFlow代码
......
#用于保存模型参数
saver = tf.train.Saver()
With tf.Session() as sess:
          ......
            #导入指定路径下的模型
            saver.restore(sess, "path/to/model/model.ckpt")
--------------------------------------------------------   
#直接加载计算结构图
saver = tf. train. import_meta_graph("path/to/model/model.ckpt/mode1.ckpt.meta")
With tf.Session() as sess:
          ......
            #导入指定路径下的模型
            saver.restore(sess, "path/to/model/model.ckpt")

滑动平均模型

滑动平均模型可以使模型在测试数据上更健壮,适合基于梯度下降算法训练神经网络的过程。在TensorFlow中提供了该模型: tf.train.ExponentialMovingAverage

#定义一个变量
v1 = tf.Variab1e(0, dtype=tf.f1oat32)
# num_updates变量更新次数
step = tf.variab1e(0, trainab1e=Fa1se)
#定义一个滑动平均模型,给出decay和num_updates
ema=tf.train.Exponentia1MovingAverage(0.99,step)
#定义一个滑动平均计算操作,给出要维护的变量列表
maintain_averages_op = ema.app1y([v1])
With tf.Session() as sess:
            .......
            sess. run(maintain_averages_op) # 运行滑动平均模型

学习速率衰减

训练前期使用较大的学习率加速,让模型快速收敛,训练过程中主键减小学习速率,到训练后期使用较小的学习率,使模型在训练后期更稳定。

# TensorFlow支持的学习速率衰减策略
exponential_decay
tf.train.exponential_decay(learning_rate,# 初始学习率
                          global_step,# 当前迭代次数
                          decay_steps,# 衰减速度,在迭代到该次数时衰减
                          decay_rate# 学习率衰减系数,通常介于0-1之间)
inverse_time_decay
natural_exp_decay
piecewise_constant
polynomial_decay

多目标优化

有时需要同时维护多套参数。例如,使用滑动平均模型时除了模型参数,还需要维护模型参数对应的影子变量。这个时候可以通过group和control_ dependencies完成。

# group
tf.group(train_part1, train_part2)
# control_denendencies
With tf.control_dependencies([train_p1, train_p2]) :
            train_op = tf.no_op (name="train")

MNIST数字识别程序构成

mnist_inference.py 前馈计算,定义神经网络模型结构。
mnist_train.py 模型训练,定义神经网络的训练过程。
mnist_eval.py 模型评价,定义程序测试过程。

前馈计算

  • 导入Mnist数据集
  • 设置神经网络结构相关的参数
  • 定义获取变量函数
  • 定义神经网络的前向传播过程

MNIST数据集

MNIST是一个手写体数字识别数据集,它的训练数据集包含60000张图片,测试数据集包含10000张图片,其中每一-张图片都代表0~9中的一个数字。

手写数字识别数据集

1、导入Mnist数据集

# -*- coding: utf-8 -*
# 从Tensorflow里边加载MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
# 载入MBNIST数据集,如果之前没有下载过,则会自动下载到相应的目录
mnist = input_data.read_data_sets('./path/MNIST_data', one_hot=True)
# 打印training_data_size: 55000
print('training_data_size:', mnist.train.num_examples)
# 打印Example training data
print('Example training data:', mnist.train.images[0])

输出结果

training_data_size: 55000
Example training data: [0.         0.         0.         ...  0.3803922  0.37647063 0.3019608
0.81568635 0.7803922  0.7803922  0.7803922  ....
 0.         0.        ]

代码中的one hot=True ,表示将样本标签转化为one hot 编码。
举例来解释one_hot 编码: 假如一共10 类。0 的one_hot 为1000000000,1 的one_hot为0100000000 , 2 的one hot 为0010000000 , 3 的one hot 为0001000000 ..…·依此类推。只有一个位为1 , 1 所在的位置就代表着第几类。

2、设置神经网络结构相关的参数

# 输入层的节点数。对于MNIST数据集,这个等于图片的总像素=28*28
INPUT_NODE = 784
# 输出层的节点数。在MNIST数据集中有0~9这10个数字类别
OUTPUT_NODE = 10
# 神经网络隐藏节点数
LAYERl_NODE = 500

3、定义获取变量函数

def get_weight_variable(shape, regularizer):
    # shape是变量的大小,regularizer是正则化函数。
    # tf.truncated_normal_initializer是正态分布初始化函数
    weights = tf.get_variable("weights", shape, initializer=tf.truncated_normal_initializer(stddev=0.1))
    # tf.add_to_collections 将当前变量的正则化损失加入名字为1osses的集合
    if regularizer != None:
        tf.add_to_col1ections('losses', regularizer(weights))
    return weights

4、定义神经网络的前向传播过程

def inference(input_tensor, regularizer):
    # 声明第一层神经网络的名 命空间'layer1'及相关变量,并完成前向传播过程
    with tf.variable_scope("layer1"):
        weights = get_weight_variable([INPUT_NODE, LAYERl_NODE], regularizer)
        biases = tf.get_variab1e("biases", [LAYERl_NODE], initializer=tf.constant_initializer(0.0))
        output1 = tf.matmul(input_tensor, weights) + biases
        # 使用relu激活函数
        layer1 = tf.nn.relu(output1)
        # 声明第二层神经网络的名命空间'layer2’及相关变量,并完成前向传播过程
    with tf.variable_scope('layer2'):
        weights = get_weight_variable([LAYERl_NODE, OUTPUT_NODE], regularizer)
        biases = tf.get_variable('biases', [OUTPUT_NODE], initializer=tf.constant_initializer(0.0))
        layer2 = tf.matmul(layer1, weights) + biases
    # 返回前向传播的结果
    return layer2

模型训练

  • 配置训练参数
  • 定义训练模型
  • 进行训练

配置训练参数

# 一个训练batch中的训练数据个数
BATCH_SIZE = 100
# 基础学习率
LEARNING_RATE_BASE = 0.8
# 学习率的衰减率
LEARNING_RATE_DECAY = 0.99
# 正则化项在损失函数里的系数
REGULARAZTION_RATE = 0.0001
# 训练轮数
TRAINING_STEPS = 30000
# 滑动平均衰减率
MOVING_AVERAGE_DECAY = 0.99

# 配置神经网络参数
MODEL_SAVE_PATH = "/path/to/model"
MODEL_NAME ="model.ckpt"

定义训练模型

# 定义训练模型
def train(mnist):
    # 定义输入输出的placeholder
    x = tf.placeholder(tf.f1oat32, [NONE, mnist_inference.INPUT_NODE], name='x-input')
    y_ = tf.placeholder(tf.f1oat32, [NONE, mnist_inference.OUTPUT_NODE], name='y-input')
    # 并定义正则化方法(tensorflow中的12正则化法)
    regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    # 直接调用mnist_inference.py中定义的前向传播过程
    y = mnist_inference.inference(x, regularizer)
    # 定义迭代次数变量,一般会将训练轮数的变量指定为不可训练的参数
    global_step = tf.Variable(0, trainable=False)
    # 滑动平均模型定义滑动平均操作,提升模型对数据对鲁棒性
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    # 使用tf.trainable_variables可以获得神经网络中所有trainable=True的变量
    variable_averages_op = variable_averages.apply(tf.trainable_variables())
    # 定义模型预测值与真实标签的交叉熵
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=y_)
    # 求一个batch的平均交叉熵
    cross_entropy_mean = tf.reduce_mean(cross_entropy)
    # 定义损失函数,包含预测标签与实际标签的损失和正则化损失
    loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    # 定义指数衰减学习率,训练前期使用较大的学习率加速,训练后期使用较小的学习率,使模型在训练后期更稳定
    learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,  # 基础学习率
                                               global_step,   # 当前迭代轮数
                                               mnist.train.num_examples/BATCH_SIZE,  # 所有训练数据需要迭代的轮数
                                               LEARNING_RATE_DECAY)  # 学习率衰减速度
    # 定义优化函数,使用tensorflow的梯度下降优化器
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
    # 训练时,每过一遍数据,需要更新参数以及每个参数的滑动平均值,使用tf.group()
    train_op = tf.group(train_step, variable_averages_op)
    # 初始化Tensorflow持久化类
    saver = tf.train.Saver()
    with tf.Session() as sess:
        # 初始化全局的变量
        tf.global_variables_initializer().run()
        for i in range(TRAINING_STEPS):
            # 自动获取一个batch的数据
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y: ys})
            # 每1000轮保存一次模型
            if i % 1000 == 0:
                # 输出当前训练情况,并保存当前模型
                print("After %d training step(s), loss on training batch is %g" % (step, loss_value))
                saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)

进行训练

# 执行训练
def main():
    mnist = mnist_inference.mnist
    train(mnist)
if __name__ == '__main__':
    main()

模型评价

import time

import tensorflow as tf
from tftest import mnist_inference
from tftest import mnist_train

# 每10秒加载一次最新模型。并进行一次测试
EVAL_INTERVAL_SEC = 10

def evaluate(mnist):
    with tf.Graph().as_default() as g:
        # 定义输入输出格式
        x = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
        y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')
        # 5000个验证集导入
        validate_feed = {x: mnist.validation.images,
                         y_: mnist.validation.labels}
        # 调用封装好的函数计算前向传播结果,测试时不关注正则化损失的值
        y = mnist_inference.inference(x, None)
        # 使用tf.argmax(y, 1)得到输入样例的预测类别,判断预测和真实标签是否相等
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        # 计算预测的精确率
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

        variable_averages = tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DECAY)
        # variables_to_restore是Tensorflow为滑动模型提供
        # 可以指定载入的是对应的影子变量
        variables_to_restore = variable_averages.variables_to_restore()
        # 直接用影子变量的参数赋值给inference的变量
        saver = tf.train.Saver(variables_to_restore)
        # 每隔10秒调用一次正确率的过程,观察训练过程中的正确率变化
        while True:
            with tf.Session() as sess:
                # 通过checkpoint文件自动找到目录中最新模型的文件名
                ckpt = tf.train.get_checkpoint_state(mnist_train.MODEL_SAVE_PATH)
                if ckpt and ckpt.model_checkpoint_path:
                    # 加载模型
                    saver.restore(sess, ckpt.model_checkpoint_path)
                    # 从模型保存文件里得到模型保存时的迭代轮数
                    global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]

                    accuracy_score = sess.run(accuracy, feed_dict=validate_feed)
                    print("After %s training step(s), validation accuracy=%g" % (global_step, accuracy_score))
                else:
                    # 说明并没有保存已经训练好的模型参数存储文件
                    print("No checkpoint file found")
                    return
            # 程序休眠10秒
            time.sleep(EVAL_INTERVAL_SEC)

def main():
    mnist = mnist_inference.mnist
    evaluate(mnist)

if __name__ == '__main__':
   main()

遇到的问题

1、编码问题

SyntaxError: Non-ASCII character '\xe4' in file mnist_inference.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

解决方法

在文件头追加:
    # -*- coding: utf-8 -*

2、没有对应的模型输出

ImportError: No module named tutorials.mnist

我的电脑在(tensorflow) cyh@chenyonghuandeMacBook-Pro  ~/tensorflow/lib/python2.7/site-packages目录下有文件夹tensorflow, tensorflow_core, tensorflow_estimator等文件夹。进入tensorflow_core文件夹,里面发现一个examples文件夹,但是文件夹下只有saved_model这个文件,没有找到tutorials。

解决方法

进入 tensorflow主页 下载缺失的tutorials文件。我是直接把整个下载下来,然后在下载文件的路径tensorflow-master\tensorflow\examples\这里找到了tutorials,把tutorials整个文件夹拷贝到上文中提到的tensorflow_core\examples\文件夹下。

3、使用TensorFlow 从网上下载数据集到本地时,pycharm 没有写入权限

tensorflow.python.framework.errors_impl.PermissionDeniedError: /path; Read-only file system

解决方法

#使用终端 进入到编辑的项目
cd /Users/cyh/doc/code/VGG16/tftest
#使用命令 
sudo python mnist_inference.py

评论
评论
  目录