MNIST手写数字识别 Tensorflow实现

def conv2d(x, W):

  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

1. strides在官方定义中是一个一维具有四个元素的张量,其规定前后必须为1,所以我们可以改的是中间两个数,中间两个数分别代表了水平滑动和垂直滑动步长值。

在卷积核移动逐渐扫描整体图时候,因为步长的设置问题,可能导致剩下未扫描的空间不足以提供给卷积核的,大小扫描 比如有图大小为5*5,卷积核为2*2,步长为2,卷积核扫描了两次后,剩下一个元素,不够卷积核扫描了,这个时候就在后面补零,补完后满足卷积核的扫描,这种方式就是same。如果说把刚才不足以扫描的元素位置抛弃掉,就是valid方式。

如果padding = ‘VALID’ ,卷积后的特征图长和宽计算公式如下:

new_height = new_width = (W – F + 1) / S (结果向上取整)

如果padding = ‘SAME’

new_height = new_width = W / S (结果向上取整)

2  tf.nn.conv2d 和 tf.layers.conv2d 的区别

tf.layers.conv2d(inputs, filters, kernel_size, strides=(1,1),
                            padding='valid', data_format='channels_last',
                    dilation_rate=(1,1), activation=None,
                    use_bias=True, kernel_initializer=None,
                    bias_initializer=init_ops.zeros_initializer(),
                    kernel_regularizer=None,
                    bias_regularizer=None,
                    activity_regularizer=None, trainable=True,
                    name=None, reuse=None)
 
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)
 
2D 卷积层的函数接口
这个层创建了一个卷积核,将输入进行卷积来输出一个 tensor。如果 use_bias 是 True(且提供了 bias_initializer),则一个偏差向量会被加到输出中。最后,如果 activation 不是 None,激活函数也会被应用到输出中。

参数:
inputs:Tensor 输入
filters:整数,表示输出空间的维数(即卷积过滤器的数量)
kernel_size:一个整数,或者包含了两个整数的元组/队列,表示卷积窗的高和宽。如果是一个整数,则宽高相等。
strides:一个整数,或者包含了两个整数的元组/队列,表示卷积的纵向和横向的步长。如果是一个整数,则横纵步长相等。另外, strides 不等于1 和 dilation_rate 不等于1 这两种情况不能同时存在。
padding:"valid" 或者 "same"(不区分大小写)。"valid" 表示不够卷积核大小的块就丢弃,"same"表示不够卷积核大小的块就补0。
"valid" 的输出形状为

 

"same" 的输出形状为

其中,L 为输入的 size(高或宽),F为 filter 的 size,S 为 strides 的大小,ceil()为向上取整。
data_format:channels_last 或者 channels_first,表示输入维度的排序。

dilation_rate:一个整数,或者包含了两个整数的元组/队列,表示使用扩张卷积时的扩张率。如果是一个整数,则所有方向的扩张率相等。另外, strides 不等于1 和 dilation_rate 不等于1 这两种情况不能同时存在。
activation:激活函数。如果是None则为线性函数。
use_bias:Boolean类型,表示是否使用偏差向量。
kernel_initializer:卷积核的初始化。
bias_initializer:偏差向量的初始化。如果是None,则使用默认的初始值。
kernel_regularizer:卷积核的正则项
bias_regularizer:偏差向量的正则项
activity_regularizer:输出的正则函数
kernel_constraint:映射函数,当核被Optimizer更新后应用到核上。Optimizer 用来实现对权重矩阵的范数约束或者值约束。映射函数必须将未被影射的变量作为输入,且一定输出映射后的变量(有相同的大小)。做异步的分布式训练时,使用约束可能是不安全的。
bias_constraint:映射函数,当偏差向量被Optimizer更新后应用到偏差向量上。
trainable:Boolean类型。
name:字符串,层的名字。
reuse:Boolean类型,表示是否可以重复使用具有相同名字的前一层的权重。
##返回值
输出 Tensor
##异常抛出
ValueError:if eager execution is enabled.
 
对于卷积来说,作用是一样的。tf.layers.conv2d 使用tf.nn.convolution作为后端。
一个参数要注意一下:
filter: 是一个4维张量,其type必须和输入一样,
    [filter_height, filter_width, in_channels, out_channels]
filters:  一个整数,输出空间的维度,也就是卷积核的数量。

tf.layers.conv2d参数丰富,一般用于从头训练一个模型。
tf.nn.conv2d,一般在下载预训练好的模型时使用。
 
3.  tf.placeholder(dtype, shape=None, name=None)
TensorFlow中的占位符,用于传入外部数据。
参数:
dtype:数据类型。
shape:数据的维度。默认为None,表示没有限制
name:名称
返回类型:Tensor
TensorFlow中加载图片的维度为[batch, height, width, channels]
 
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
#加载数据集
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

#以交互式方式启动session
#如果不使用交互式session,则在启动session前必须
# 构建整个计算图,才能启动该计算图
sess = tf.InteractiveSession()

"""构建计算图"""
#通过占位符来为输入图像和目标输出类别创建节点
#shape参数是可选的,有了它tensorflow可以自动捕获维度不一致导致的错误
x = tf.placeholder("float", shape=[None, 784]) #原始输入
y_ = tf.placeholder("float", shape=[None, 10]) #目标值

#为了不在建立模型的时候反复做初始化操作,
# 我们定义两个函数用于初始化
def weight_variable(shape):
    #截尾正态分布,stddev是正态分布的标准偏差
    initial = tf.truncated_normal(shape=shape, stddev=0.1)
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

#卷积核池化,步长为1,0边距
def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                          strides=[1, 2, 2, 1], padding='SAME')

"""第一层卷积"""
#由一个卷积和一个最大池化组成。滤波器5x5中算出32个特征,是因为使用32个滤波器进行卷积
#卷积的权重张量形状是[5, 5, 1, 32],1是输入通道的个数,32是输出通道个数
W_conv1 = weight_variable([5, 5, 1, 32])
#每一个输出通道都有一个偏置量
b_conv1 = bias_variable([32])

#位了使用卷积,必须将输入转换成4维向量,2、3维表示图片的宽、高
#最后一维表示图片的颜色通道(因为是灰度图像所以通道数维1,RGB图像通道数为3)
x_image = tf.reshape(x, [-1, 28, 28, 1])

#第一层的卷积结果,使用Relu作为激活函数
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1))
#第一层卷积后的池化结果
h_pool1 = max_pool_2x2(h_conv1)

"""第二层卷积"""
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

"""全连接层"""
#图片尺寸减小到7*7,加入一个有1024个神经元的全连接层
W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
#将最后的池化层输出张量reshape成一维向量
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减少过拟合"""
#使用placeholder占位符来表示神经元的输出在dropout中保持不变的概率
#在训练的过程中启用dropout,在测试过程中关闭dropout
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

"""输出层"""
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))

#模型训练,使用AdamOptimizer来做梯度最速下降
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

#正确预测,得到True或False的List
correct_prediction = tf.equal(tf.argmax(y_, 1), tf.argmax(y_conv, 1))
#将布尔值转化成浮点数,取平均值作为精确度
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

#在session中先初始化变量才能在session中调用
sess.run(tf.initialize_all_variables())

#迭代优化模型
for i in range(20000):
    #每次取50个样本进行训练
    batch = mnist.train.next_batch(50)
    if i%100 == 0:
        train_accuracy = accuracy.eval(feed_dict={
            x: batch[0], y_:batch[1], keep_prob:1.0}) #模型中间不使用dropout
        print("step %d, training accuracy %g" % (i, train_accuracy))
    train_step.run(feed_dict={x:batch[0], y_:batch[1], keep_prob:0.5})
print("test accuracy %g" % accuracy.eval(feed_dict={
            x:mnist.test.images, y_:mnist.test.labels, keep_prob:1.0}))

 

1、启动session

  (1)交互方式启动session

    sess = tf.InteractiveSession()

  (2)一般方式启动session

    sess = tf.Session()

  ps: 使用交互方式不用提前构建计算图,而使用一般方式必须提前构建好计算图才能启动session

 

2、权重和偏置初始化

  权重初始化的原则:应该加入少量的噪声来打破对称性并且要避免0梯度(初始化为0)

  权重初始化一般选择均匀分布或是正态分布

  定义权重初始化方法

   def weight_variable(shape):
    #截尾正态分布,stddev是正态分布的标准偏差
    initial = tf.truncated_normal(shape=shape, stddev=0.1)
    return tf.Variable(initial)

  定义偏置初始化方法

  def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

 3.  Tensorflow 将list转换为Tensor

两种方法:

tf.convert_to_tensor([np.nan, 1, 1, 64])
tf.TensorShape([None, 1, 1, 64])

这两种方法我都试过,第二种好用。

 

posted @ 2019-04-19 16:29  爱学英语的程序媛  阅读(434)  评论(0编辑  收藏  举报