您的位置:首页 > 理论基础 > 计算机网络

卷积神经网络(tf.layers / estimator api)使用TensorFlow'layers'和'estimator'API构建卷积神经网络以对MNIST数字数据集进行分类。

2019-03-02 21:15 585 查看

代码来源:convolutional_network.py

[code]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=<tensorflow.python.ops.init_ops.Zeros object at 0x000002596A1FD898>, 卷积核的初始化。
#     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'])

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐