import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
data_from_file=input_data.read_data_sets('MNIST_data',one_hot=True)
batch_size=100
n_batch=data_from_file.train.num_examples//batch_size
def weight_init(shape_value):
'''
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
shape: 输出数据的shape
mean: 正态分布的均值
stddev: 正态分布的标准差
dtype: 输出数据的类型
seed: 一个整数,当赋值后,每次生成的随机数相同
name: 赋予该操作一个名字
'''
return tf.Variable(tf.truncated_normal(shape_value,stddev=0.1))
def bias_init(shape_value):
return tf.constant(0,shape=shape_value,dtype=tf.float32)
def conv2d_func(X,W):
'''
tf.nn.con2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
input: 指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
filter: 相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
strides: 卷积时在图像每一维的步长,这是一个一维的向量,长度4
padding: string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式
use_cudnn_on_gpu: 是否使用cudnn加速,默认为True, NVIDIA cuDNN是一个GPU加速深层神经网络原语库。
name: 指定该操作的名称
via: http://www.cnblogs.com/welhzh/p/6607581.html
'''
return tf.nn.conv2d(X,W,strides=[1,1,1,1],padding='SAME')
def max_pool_func(X):
'''
tf.nn.max_pool(value, ksize, strides, padding, name=None)
value: 需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape
ksize: 池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1 ([1,x,y,1])
strides: 和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
padding: 和卷积类似,可以取'VALID' 或者'SAME'
name: 指定该操作的名称
via: https://blog.csdn.net/coder_xiaohui/article/details/78025379
'''
return tf.nn.max_pool(X,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
X=tf.placeholder(tf.float32,[None,784])
y=tf.placeholder(tf.float32,[None,10])
X_4d=tf.reshape(X,[-1,28,28,1])
W_conv1=weight_init([5,5,1,32])
b_conv1=bias_init([32])
h_conv1=tf.nn.relu(conv2d_func(X_4d,W_conv1)+b_conv1)
h_pool1=max_pool_func(h_conv1)
W_conv2=weight_init([5,5,32,64])
b_conv2=bias_init([64])
h_conv2=tf.nn.relu(conv2d_func(h_pool1,W_conv2)+b_conv2)
h_pool2=max_pool_func(h_conv2)
'''
28*28的图片第1次卷积时还是28*28
第1次池化时变为14*14
第2次卷积时还是14*14
第2次池化时变为7*7
'''
W_full1=weight_init([7*7*64,1024])
b_full1=bias_init([1024])
h_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_full1=tf.nn.relu(tf.matmul(h_flat,W_full1)+b_full1)
keep_prob=tf.placeholder(tf.float32)
'''
tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None)
x: 指输入的数据
keep_prob: drop的概率,没有被drop掉的数将会是原来的1/keep_pred倍
noise_shape: 默认情况下noise_shape与x的shape相同,就是普通的drop,没有约束,即对于每个样本而言被drop的几率时等同的;而当noise_shape某一个轴值为1时,代表按照这一轴来drop,例如如果(3,4,5)是代表(句子数,每个句子的词数,每个词向量的维度),那么(3,4,1)就表示按照词向量来dropout(可以理解为随机跳过某些词)。
seed: 随机种子,数字相同时产生的一组随机数相同,即所有的随机数按照相同的算法生成
name: 指定该操作的名称
via: 关于noise_shape的讲解参考https://spaces.ac.cn/archives/4521
'''
h_drop=tf.nn.dropout(h_full1,keep_prob)
W_full2=weight_init([1024,10])
b_full2=bias_init([10])
prediction=tf.nn.softmax(tf.matmul(h_drop,W_full2)+b_full2)
loss_cross_entropy=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y,logits=prediction))
train=tf.train.AdamOptimizer(1e-4).minimize(loss_cross_entropy)
accuracy=tf.reduce_mean(tf.cast(tf.equal(tf.argmax(prediction,1),tf.argmax(y,1)),tf.float32))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch in range(21):
for batch in range(n_batch):
X_batch, y_batch=data_from_file.train.next_batch(batch_size)
sess.run(train,feed_dict={X:X_batch,y:y_batch,keep_prob:0.7})
acc=sess.run(accuracy,feed_dict={X:data_from_file.test.images,y:data_from_file.test.labels,keep_prob:1.0})
print('Iteration '+str(epoch)+', accuracy = '+str(acc))