tensorflow学习浅记

   这篇文章主要讲的是个人这几周来在ubuntu系统上学习tensorflow的所得所思,由于水平不足,如有缺陷与错误,望各位看官不吝赐教!谢谢!(本文中如有侵权处,望联系作者,速删)

 step 1 .安装tensorflow(不需外网):有pip,anaconda等多种方式(本人用的是anaconda),可自行百度。

  step 2. 从MNIST手写识别开始: 我是从tensorflow中文社区上的MNIST手写数字识别教程开始学习tensorflow的:

   tensorflow中文社区“MNIST入门”篇介绍了基本的代码,此处不再赘述。

   以下先附上本次要说的“卷积神经网络识别版”代码,在代码后会细致讲解:

import tensorflow as tf   

from tensorflow.examples.tutorials.mnist import input_data
mnist =  input_data.read_data_sets('MNIST_data',one_hot=True)

#此处可设置会话(tensorflow的术语,在下面解释)的类型:交互式:sess = tf.InteractiveSession()用于命令行,此处不用也可
sess = tf.InteractiveSession()

#初始化参数
def weight_variable(shape):
    initial=tf.truncated_normal(shape,stddev=0.1)  #正态分布
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape) #生成常量矩阵,shape即为矩阵的shape
    return tf.Variable(initial)

#卷积:
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')


#第一层隐藏层:
W_conv1 =weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
x_image = tf.reshape(x,[-1,28,28,1])
#h 是激活后得到的特征
h_conv1 =tf.nn.relu(conv2d(x_image,W_conv1)+b_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)

#全连接层1:
W_fc1= weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])

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处理
keep_prob=tf.placeholder('float')
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)

#全连接层2:
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))

#设置训练方法、优化器及其他
train_step =tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))
#开始训练:
sess.run(tf.global_variables_initializer())
#储存
saver =tf.train.Saver(max_to_keep=1)

for i in range(10000):
    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})
        print('第%d步:准确度为%g'%(i,train_accuracy))
    saver.save(sess,'/home/richard/my_CNN.ckpt',global_step=i)#储存模型
    train_step.run(feed_dict ={x:batch[0],y_:batch[1],keep_prob:0.5})

#打印结果:
print('综合准确度为%g'%accuracy.eval(feed_dict ={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))

1>>>

from tensorflow.examples.tutorials.mnist import input_data

这句用于导入文件input.data.py,用它自动从网上下载并解压MNIST手写数据集(含训练集与验证集)及标签集的(显然,每一个手写数字图片都对应着一个标签(label)说明它是什么数字),然后生成了名为“MNIST_data”的文件(打开里面都是后缀为 .gz 的压缩包)

mnist =  input_data.read_data_sets('MNIST_data',one_hot=True)

用read_data_sets导入数据,对one-hot=True我的理解的是这相当于打开了 [one-hot]这个模式的开关

2>>>

sess = tf.InteractiveSession()
会话:tensorflow术语。大家都知道tensorflow采用“计算图(graph)”的方式表示深度学习程序的执行过程,它是神经网络的一种直观表示方式。我理解的是:tensorflow将神经网络中出现的多种计算放到一起构成graph,在“会话”(Session)中执行。

3>>>

#占位符用于输入数据及得到目标数据
x = tf.placeholder("float",[None,784])
y_ = tf.placeholder("float",[None,10])
这两句定义占位符(placeholder),占位符是用于装输入数据、输出数据的空壳。

x:  用于输入要识别的图片,此处的图片为28*28像素。[None,784]是一个二维张量(tensor),第一位表示第几张图片,None意为任意。784=28*28,是图片的二维平面。如第42张图片的第600个像素点就是[42,600]。

x = tf.placeholder("float",[None,28,28,1])
而这样是另外一种写法。

y_ :用于接收label值,即图片识别的正确答案。[None,10]:二维张量,None意同上,第二位之所以是10,因为识别结果是0~9。

简言之,占位符就是先把位子留出来,用于装数据。

4>>>

我们需要先对W与b做预处理。

#初始化参数
def weight_variable(shape):
    initial=tf.truncated_normal(shape,stddev=0.1)  #正态分布
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape) #生成常量矩阵,shape即为矩阵的shape
    return tf.Variable(initial)

大家知道如果我们使用SGD(随机梯度下降),需要随机选取梯度下降开始点。我们这里使用的是Adam,也是一样需要随机初始化。所以对w 进行正态分布初始化。

initial=tf.truncated_normal(shape,stddev=0.1)  
truncated_normal(shape,mean=0,stddev)即正态分布,stddev为方差,此处设为0.1,控制赋值的范围在均值(默认为0)附近0.1大小范围内。
initial = tf.constant(0.1, shape=shape)
对bias:先生成一个常量矩阵即可。由于之后我们使用了Relu这个激活函数,为了防止出现负数,对b初始化为常量矩阵(值全为0.1)

5>>>定义卷积函数

def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding ='SAME')
卷积这个概念源于数学,被广泛应用于图像处理方面。它用于从图像中提取特征,涉及到矩阵运算。

>>>tf.nn.conv2d(input, filter , strides , padding ,  use_cudnn_on_gpu=None,name=None)  

是卷积神经网络核心函数之一,

input 为要做卷积的输入的图像,为一个4维tensor,有参数【batch,height,width,channels】,类型为float32或float64。batch为一次训练的图片数(样本),channels为色彩通道(如RGB三通道,此处MNIST单通道)。这里x即为input。

filter为卷积核:是4维tensor,有参数【filter_height,filter_width,in_channels, out_channels】,指【卷积核的高度,宽度,输入通道数,输出通道数】构建卷积核时需定义输入通道,并由此定下输出通道。卷积核大小又称为“感受野”。

strides为步长,有四个参数,表示卷积时在各维度上一步跨多大。strides参数分别为【batch,height,width,channels】一般strides【0】=strides【3】=1,因为第一位表示在batch(样本)维度上的步长,最后一位表示在色彩通道(channels)维度上的步长,即不跳过任何一个颜色。

padding是卷积的模式,有“SAME”(在图像边缘处自动补充0像素点以使卷积核得以卷积边缘)与“VALID”(在图像边缘处不自动补0像素点,不卷积边缘)两种。当卷积核大于1且不进行边界扩充,输出尺寸将相应缩小,当卷积核以标准方式SAME进行边界扩充,则输出图像数据的空间尺寸将与输入图像相等。

此处x即为input,W为卷积核。

关于卷积核与提取特征有必要讲的:

卷积的用途就是 提取图像的特征,比如一副手写数字8的图片,为什么人类看了一下子认出来是8?因为我们看得多了,知道8是长什么样子,也就是我们很了解8的特征。但机器不知道,所以我们要训练它学习数字8的特征:上下都有圆圈、中间窄等等。

tf.nn.conv2d(x,W,strides=[1,1,1,1],padding ='SAME')
此处W ,也就是我们的权重参数(一个张量,或者说,一个矩阵),就是我们的卷积核。卷积核又名滤波器,它就是用来提取特征的,但一开始它不是一个优秀的特征提取器。我们要通过不断的让神经网络“看”图片,让卷积核自己不断摸索着提取一些特征,再通过比较它的答案与正确答案(标签)的差异(用loss function 衡量),不断重复训练,在这个过程中更新参数(w和b)直至它成为一个优秀的特征提取器。

6>>>最大池化(别听池化名字取得高大上,本质就是采样。可以对输入的图像数据进行压缩,保留主要特征,增强鲁棒性)

def max_pool_2x2(x):
    return tf.nn.max_pool(x,ksize =[1,2,2,1],strides=[1,2,2,1],padding='SAME')

tf.nn.max_pool(input, ksize, strides, padding,name =None)重要的池化函数

ksize:滤波器的大小,即池化窗口的大小,此处池化窗口为2*2大小。

7>>>

#改变输入的图像x
x_image = tf.reshape(x,[-1,28,28,1])

此处让输入的图像数据变为(resize) 28*28*1的矩阵形式(1为通道数)

8>>>

#第一层隐藏层:
W_conv1 =weight_variable([5,5,1,32])
b_conv1=bias_variable([32])

#h 是激活后得到的特征
h_conv1 =tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
h_pool1=max_pool_2x2(h_conv1)

对第一层隐藏层的W,b进行初始化。对图像进行特征提取后加上bias再用Relu激活,之后池化。

有人可能要问:

W_conv1 =weight_variable([5,5,1,32])

为啥这里的shape是一个[5,5,1,32]的张量?

5,5,1表示第一层的卷积核(filter)是5*5*1大小的(卷积核通道数要和input一致,否则无法计算卷积)。32是输出的通道数,也就是这一层有32个5*5*1大小的卷积核。(注意这里的卷积核个数32是自定义的,非计算得出)做了第一层的卷积后我们会得到32个28*28*1的特征(feature map)(因为是SAME卷积,所以每一个filter做完卷积后输出28*28的feature map,和原图一致),这已经有了32*5*5=800个权重参数。

再将每一张都加上bias,再激活,作为输入数据输入下一隐藏层。

9>>>

#第二层隐藏层:
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)

同上。第二层有64个卷积核,这次我们得到64个feature map,有1600个权重参数。

10>>>全连接层(fully connected layers ,FC)

为什么要有全连接层?

全连接层:用于分类。如果说之前的卷积与池化是对输入的原始数据提取特征,那么全连接层就是在这些特征之上对原图进行分类。

(有的神经网络设计时将全连接层替换为全局平均池化(global average pooling,GAP),根据不同的情况两种方式有不同的准确性,而且GAP减少了参数的数量。此处不对其作展开)

#全连接层1:
W_fc1= weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])

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)
W_fc1= weight_variable([7*7*64,1024])

对【7*7*64,1024】的解释:

11>>>

#Dropout处理
keep_prob=tf.placeholder('float')
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)

keep_prob是人为设定的每个神经元被drop的概率。

12>>>

#全连接层2:
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)

对【1024,10】的解释:将h_fc1_drop映射到{0,1,2,3,4,5,6,7,8,9}上。

最后y_conv是1*10的tensor,每一位为对应数字的概率值(用softmax函数映射到【0,1】区间)

13>>>

#计算交叉熵
cross_entropy = - tf.reduce_sum(y_ * tf.log(y_conv))

#设置训练方法、优化器及其他
train_step =tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))

我们的目的是最小化交叉熵(cross entropy)

怎么计算accuracy呢?

correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))

这个式子里tf.argmax(y_conx,1)函数输出张量y_conx10个数中概率值最大者,也就是我们的预测值。再用tf.equal函数判断我们模型的预测值y与标准值y_是否一致,一致就输出True,否则False

accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))

再将bool值转换为float,再求均值,再输出这一批样本识别的正确率(accuracy of batch)

14>>>

#储存
saver =tf.train.Saver(max_to_keep=1)

使用saver类,目的是在接下来的过程中储存模型。

max_to_keep=1指只保留最后一次的。可以改为3,5等。如改为0或None,则为保留所有。

会在路径下生成后缀为 .meta, .index.data-00x(00x是可变的),以及一个checkpoint文件。

15>>>

#开始训练:
sess.run(tf.global_variables_initializer())
for i in range(10000):
    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})
        print('第%d步:准确度为%g'%(i,train_accuracy))     
    saver.save(sess,'/home/richard/my_CNN.ckpt',global_step=i)#储存模型     
    train_step.run(feed_dict ={x:batch[0],y_:batch[1],keep_prob:0.5})

#打印结果:
print('测试集准确度为%g'%accuracy.eval(feed_dict ={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))

训练10000次,每次取50个图片,用feed_dict填充数据。

accuracy.eval()

Tensor.eval(feed_dict=None, session=None):这里eval() 其实就是tf.Tensor的Session.run() 的另外一种写法。

但要注意,eval()只能用于tf.Tensor类对象,也就是有输出的Operation。对于没有输出的Operation, 可以用.run()或者Session.run()。Session.run()没有对输出限制。

最后用测试集进行测试,输出结果。

16>>>输出的东西

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz

Extracting MNIST_data/t10k-labels-idx1-ubyte.gz

#这一段是提示你安装xx可以加快速度,没有也可以运行。

W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE3 instructions, but these are available on your machine and could speed up CPU computations.
W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations.

W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.

第0步:准确度为0.08
第100步:准确度为0.82
第200步:准确度为0.92
第300步:准确度为0.82
第400步:准确度为0.96
第500步:准确度为0.92
第600步:准确度为1
第700步:准确度为0.96
第800步:准确度为0.92
第900步:准确度为1
第1000步:准确度为0.96
第1100步:准确度为0.98
第1200步:准确度为0.98
第1300步:准确度为0.98

......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值