代码来源:convolutional_network.py
from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets("./data",one_hot=False)
import tensorflow as tf
learning_rate=0.001
num_steps=2000
batch_size=128
num_input=784
num_classes=10
dropout=0.25 # Dropout,probability to drop a unit
# create the neural network
def conv_net(x_dict,n_classes,dropout,reuse,is_training):
# define a scope for reusing the variables
# tf.variable_scope(): 可以让变量有相同的命名,包括tf.get_variable得到的变量,
# 还有tf.Variable变量.可变范围允许创建新的variable并分享已创建的variable,
# 同时提供检查,不会意外创建或共享。
# tf.variable_scope(name_or_scope, string或VariableScope:要打开的范围
# default_name=None, 如果name_or_scope参数为None,
# 则将使用默认名称,此名称将被唯一。
# 如果提供了name_or_scope,它将不会被使用,
# 因此它不是必需的,可以是None。
# values=None, 值:传递给op函数的Tensor参数列表。
# initializer=None, 初始化器:此范围内的变量的默认初始化程序。
# regularizer=None, 此范围内的变量的默认正则符。
# caching_device=None, 此范围内的变量的默认缓存设备
# partitioner=None, 此范围内变量的默认分区。
# custom_getter=None, 此范围内变量的默认定制getter。
# reuse=None, True或None 如果是,我们进入该范围以及所有子范围的重用模式;
# 如果没有,我们只是继承父范围重用。
# dtype=None) 在此范围中创建的变量类型(默认为传递范围中的类型,或从父范围继承)
with tf.variable_scope('ConvNet',reuse=reuse):
x=x_dict['images']
x=tf.reshape(x,shape=[-1,28,28,1])
# convolution layer with 32 filters and a kernel size of 5
conv1=tf.layers.conv2d(x,32,5,activation=tf.nn.relu)
# max pooling (down-sampling) with strides of 2 and kernel size of 2
# 在卷积神经网络中,卷积层之间往往会加上一个池化层。
# 池化层可以非常有效地缩小参数矩阵的尺寸,从而减少最后全连层中的参数数量。
# 使用池化层即可以加快计算速度也有防止过拟合的作用,一般是放在卷积层之后
# max_pooling2d(
# inputs, 进行池化的数据。
# pool_size, 池化的核大小(pool_height, pool_width),
# 如[3,3]. 如果长宽相等,也可以直接设置为一个数,如pool_size=3.
# strides, 池化的滑动步长。可以设置为[1,1]这样的两个整数. 也可以直接设置为一个数,如strides=2
# padding='valid', 边缘填充,'same' 和'valid‘选其一。默认为valid
# data_format='channels_last', 输入数据格式,默认为channels_last ,即 (batch, height, width, channels),
# 也可以设置为channels_first 对应 (batch, channels, height, width).
# name=None 层的名字。
# )
conv1=tf.layers.max_pooling2d(conv1,2,2)
# conv2d(inputs, Tensor 输入
# filters, 整数,表示输出空间的维数(即卷积过滤器的数量)
# kernel_size, 一个整数,或者包含了两个整数的元组/队列,表示卷积窗的高和宽。
# 如果是一个整数,则宽高相等
# strides=(1, 1), 一个整数,或者包含了两个整数的元组/队列,
# 表示卷积的纵向和横向的步长。如果是一个整数,则横纵步长相等。
# 另外, strides 不等于1 和 dilation_rate 不等于1
# 这两种情况不能同时存在。
# padding='valid', "valid" 或者 "same"(不区分大小写)。
# "valid" 表示不够卷积核大小的块就丢弃,
# "same"表示不够卷积核大小的块就补0。 "valid" 的输出形状为输入的 size(高或宽),
# 为 filter 的 size, 为 strides 的大小, 为向上取整。
# data_format='channels_last', channels_last 或者 channels_first,表示输入维度的排序。
# `channels_last` corresponds to inputs with shape;
# `(batch, height, width, channels)` while `channels_first` corresponds to inputs with shape `(batch, channels, height, width)`.
# dilation_rate=(1, 1), 一个整数,或者包含了两个整数的元组/队列,
# 表示使用扩张卷积时的扩张率。如果是一个整数,
# 则所有方向的扩张率相等。另外, strides 不等于1 和
# dilation_rate 不等于1 这两种情况不能同时存在。
# activation=None, 激活函数。如果是None则为线性函数。
# use_bias=True, Boolean类型,表示是否使用偏差向量。
# kernel_initializer=None, 卷积核的初始化。
# bias_initializer=, 卷积核的初始化。
# kernel_regularizer=None, 映射函数,当核被Optimizer更新后应用到核上。
# Optimizer 用来实现对权重矩阵的范数约束或者值约束。
# 映射函数必须将未被影射的变量作为输入,
# 且一定输出映射后的变量(有相同的大小)。
# 做异步的分布式训练时,使用约束可能是不安全的。
# bias_regularizer=None, 映射函数,当偏差向量被Optimizer更新后应用到偏差向量上。
# activity_regularizer=None,
# kernel_constraint=None,
# bias_constraint=None,
# trainable=True, Boolean类型。
# name=None, 字符串,层的名字。
# reuse=None) Boolean类型,表示是否可以重复使用具有相同名字的前一层的权重。
conv2=tf.layers.conv2d(conv1,64,3,activation=tf.nn.relu)
conv2=tf.layers.max_pooling2d(conv2,2,2)
# flatten the data to a 1-D vector for the fully connected layer
# flatten(P)这个函数就是把P保留第一个维度,把第一个维度包含的每一子张量展开成一个行向量,
# 返回张量是一个二维的, shape=(batch_size,….),一般用于卷积神经网络全链接层前的预处理
fc1=tf.contrib.layers.flatten(conv2)
# fully connected layer(in tf contrib folder for now)
# tf.layers.dense(
# inputs, 输入该网络层的数据
# units, 输出的维度大小,改变inputs的最后一维
# activation=None, 激活函数,即神经网络的非线性变化
# use_bias=True, 使用bias为True(默认使用),不用bias改成False即可,是否使用偏置项
# kernel_initializer=None, 卷积核的初始化器
# bias_initializer=tf.zeros_initializer(), 偏置项的初始化器,默认初始化为0
# kernel_regularizer=None, 卷积核的正则化,可选
# bias_regularizer=None, 偏置项的正则化,可选
# activity_regularizer=None, 输出的正则化函数
# kernel_constraint=None,
# bias_constraint=None,
# trainable=True, 表明该层的参数是否参与训练。如果为真则变量加入到图集合中
# name=None, 层的名字
# reuse=None 是否重复使用参数
fc1=tf.layers.dense(fc1,1024)
# apply dropout (if is_training is false, dropout is not applied)
# dropout 是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃,
# 可以用来防止过拟合,layers模块中提供了tf.layers.dropout()方法来实现这一操作,
# dropout( inputs, 即输入数据。
# rate=0.5, 可选,默认为0.5,即dropout rate,如设置为0.1,则意味着会丢弃10%的神经元。
# noise_shape=None, 可选,默认为 None,int32 类型的一维 Tensor,
# 它代表了dropout mask的shape,dropout mask会与inputs相乘对inputs做转换,
# 例如inputs的shape为(batch_size,timesteps,features),
# 但我们想要droput mask在所有timesteps都是相同的,
# 我们可以设置noise_shape=[batch_size,1, features]。
# seed=None, 可选,默认为 None,即产生随机熟的种子值。
# training=False, 可选,默认为 False,布尔类型,即代表了是否标志位 training 模式。
# name=None) 可选,默认为 None,dropout 层的名称。
fc1=tf.layers.dropout(fc1,rate=dropout,training=is_training)
out= tf.layers.dense(fc1,n_classes)
return out
# define the model function(following tf estimator template)
def model_fn(features,labels,mode):
# because dropout have different behavior at training and prediction time,we
# need to create 2 distinct computation graphs that still share the same weight.
logits_train=conv_net(features,num_classes,dropout,reuse=False,is_training=True)
logits_test=conv_net(features,num_classes,dropout,reuse=True,is_training=False)
# predictions
# tf.argmax(vector, 1):返回的是vector中的最大值的索引号,
# 如果vector是一个向量,那就返回一个值,如果是一个矩阵,
# 那就返回一个向量,这个向量的每一个维度都是相对应矩阵行的最大值元素的索引号。
pred_classes=tf.argmax(logits_test,axis=1)
# 通过Softmax回归,将logistic的预测二分类的概率的问题推广到了n分类的概率的问题。
# tf.nn.softmax(
# logits, 一个非空张量,必须是以下类型之一:half, float32, float64
# axis=None, 将被执行的softmax维度,默认值是-1,表示最后一个维度。
# name=None, 操作的名称(可选)。
# dim=None
# )
pred_probas=tf.nn.softmax(logits_test)
# if prediction mode,early,return
if mode==tf.estimator.ModeKeys.PREDICT:
return tf.estimator.EstimatorSpec(mode,predictions=pred_classes)
# define loss and optimizer
# tf.reduce_mean函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,
# 主要用作降维或者计算tensor(图像)的平均值。
# reduce_mean(input_tensor, 输入的待降维的tensor;
# axis=None, 指定的轴,如果不指定,则计算所有元素的均值;
# keep_dims=False, 是否降维度,设置为True,输出的结果保持输入tensor的形状,
# 设置为False,输出结果会降低维度;
# name=None, 操作的名称;
# reduction_indices=None) 在以前版本中用来指定轴,已弃用;
# tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels, name=None)
# 计算logits和labels之间的稀疏softmax交叉熵度量在离散分类任务中的错误率,
# 这些类之间是相互排斥的(每个输入只能对应唯一确定的一个类).举例来说,
# 每个CIFAR-10 图片只能被标记为唯一的一个标签:一张图片可能是一只狗或一辆卡车,而不能两者都是。
loss_op=tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits_train,labels=tf.cast(labels,dtype=tf.int32)))
optimizer=tf.train.AdamOptimizer(learning_rate=learning_rate)
# global_step经常在滑动平均,学习速率变化的时候需要用到,这个参数在tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_steps)里面有,系统会自动更新这个参数的值,从1开始。
# tf.train.get_global_step 获得全局步长张量,全局步长张数必须是整数变量。我们首先尝试在集合GLOBAL_STEP中或通过名称找到它global_step:0。
# 返回:全局步骤变量,或者None如果没有找到
train_op=optimizer.minimize(loss_op,global_step=tf.train.get_global_step())
acc_op=tf.metrics.accuracy(labels=labels,predictions=pred_classes)
# 是一个class(类),是定义在model_fn中的,
# 并且model_fn返回的也是它的一个实例,这个实例是用来初始化Estimator类的
# TF Estimators requires to return a EstimatorSpec, that specify
# the different ops for training, evaluating, ...
estim_specs=tf.estimator.EstimatorSpec(
mode=mode,
predictions=pred_classes,
loss=loss_op,
train_op=train_op,
eval_metric_ops={'accuracy':acc_op}
)
return estim_specs
# class Estimator(builtins.object)
# 对象包含了一个模型 model_fn,这个模型给定输入和参数,会返回训练、验证或者预测等所需要的操作节点。
# 所有的输出(检查点、事件文件等)会写入到 model_dir,或者其子文件夹中。如果 model_dir 为空,
# 则默认为临时目录。
model=tf.estimator.Estimator(model_fn)
# tf.estimator.inputs.numpy_input_fn(
# x, numpy数组对象或numpy数组对象的dict。如果是数组,则该数组将被视为单个特征。
# y=None, numpy数组对象或numpy数组对象的dict。None如果没有。
# batch_size=128, 整数,返回的批次大小。
# num_epochs=1, 整数,迭代数据的时期数。如果None将永远运行。
# shuffle=None, 如果为True,则对队列进行洗牌。在预测时避免随机播放。
# queue_capacity=1000, 整数,要累积的队列大小。
# num_threads=1 整数,用于读取和排队的线程数。为了具有预测和可重复的阅读和排队顺序,
# 例如在预测和评估模式中,num_threads应该是1。
# ) 返回将numpy数组的dict输入模型的输入函数。
# define the input function for training
input_fn=tf.estimator.inputs.numpy_input_fn(
x={'images':mnist.train.images},y=mnist.train.labels,
batch_size=batch_size,num_epochs=None,shuffle=True)
# train the model
model.train(input_fn, steps=num_steps)
# evaluate the model
# define the input function for evaluation
input_fn=tf.estimator.inputs.numpy_input_fn(
x={'images':mnist.test.images},y=mnist.test.labels,batch_size=batch_size,
shuffle=False)
# Use the Estimator 'evaluate' method
e=model.evaluate(input_fn)
print('Testing Accuracy:',e['accuracy'])