tensorflow gpu中几点名字后面的:1什么意思如‘import/Conv2d_1a_3x3/BatchNorm/cond_1/Identity/Switch:

Tensorflow中实现leakyRelu操作(高效)
从github上转来,实在是厉害的想法,什么时候自己也能写出这种精妙的代码就好了
代码如下: 我做了些改进,因为实在tensorflow中使用,就将原来的abs()函数替换成了tf.abs()
import tensorflow as tf
def LeakyRelu(x, leak=0.2, name="LeakyRelu"):
with tf.variable_scope(name):
f1 = 0.5 * (1 + leak)
f2 = 0.5 * (1 - leak)
return f1 * x + f2 * tf.abs(x)
没有更多推荐了,在Tensorflow上运行cifar10时出现了ArrgumentError
[问题点数:40分]
本版专家分:0
结帖率 85.71%
CSDN今日推荐
本版专家分:4994
2016年12月 其他开发语言大版内专家分月排行榜第一
本版专家分:0
结帖率 85.71%
本版专家分:0
本版专家分:4994
2016年12月 其他开发语言大版内专家分月排行榜第一
匿名用户不能发表回复!|
CSDN今日推荐独家|一文读懂TensorFlow基础独家|一文读懂TensorFlow基础晨语百家号本文长度为7196字,建议阅读10分钟本文为你讲解如何使用Tensorflow进行机器学习和深度学习。1. 前言深度学习算法的成功使人工智能的研究和应用取得了突破性进展,并极大地改变了我们的生活。越来越多的开发人员都在学习深度学习方面的开发技术。Google推出的TensorFlow是目前最为流行的开源深度学习框架,在图形分类、音频处理、推荐系统和自然语言处理等场景下都有丰富的应用。尽管功能强大,该框架学习门槛并不高,只要掌握Python安装和使用,并对机器学习和神经网络方面的知识有所了解就可以上手。本文就带你来一趟TensorFlow的启蒙之旅。2. 初识TensorFlow2.1. TensorFlow安装说明我们先来安装TensorFlow。TensorFlow对环境不算挑剔,在Python 2.7和Python3下面均可运行,操作系统Linux、MAC、Windows均可(注意新版本刚出来时可能只支持部分操作系统),只要是64位。安装TensorFlow主要不同之处是TensorFlow安装包分支持GPU和不支持GPU两种版本,名称分别为tensorflow-gpu和tensorflow。实际生产环境最好安装支持GPU的版本,以利于GPU强大的计算能力,不过这需要先安装相应的CUDA ToolKit和CuDNN。相比之下,安装不支持GPU的TensorFlow包容易些,顺利的话执行一句pip install tensorflow就OK。如果读者在安装中遇到问题,可根据错误提示在网上搜索解决办法。安装后,可在命令行下启动Python或打开Jupyter Notebook,执行下面的语句验证TensorFlow是否安装成功。>>>import tensorflow as tf用tf引用TensorFlow包已成为一种约定。在本文的所有示例代码中,均假定已事先执行该语句。2.2. TensorFlow计算模型我们先来看在TensorFlow中如何计算c = a + b。这里a = 3,b = 2。>>>a = tf.constant (3)>>>b = tf.constant (2)>>>c = a + b>>>sess = tf.Session ()>>>print (sess.run(c))5从上面的代码可以看出,比起Python中的一句print (3+2),TensorFlow中实现同样的功能需要更多的步骤。首先得把参数打包,再交给Session对象执行才能输出结果。现在我们对代码稍作修改,让程序输出更多的调试信息。>>>print (a, b)Tensor("Const:0", shape=(), dtype=int32) Tensor("Const_1:0", shape=(), dtype=int32)>>>print(c)Tensor("add:0", shape=(), dtype=int32)>>>sess.run ((a,b))(3,2)>>>print(sess.run(c))从上面可以看出,a、b、c都是张量(Tensor)而不是数字。张量的数学含义是多维数组。我们把1维数组称为向量,2维数组称为矩阵。而不管1维、2维、3维、4维,都可以称作张量,甚至标量(数字)也可以看作是0维的张量。在深度学习中,几乎所有数据都可以看作张量,如神经网络的权重、偏置等。一张黑白图片可以用2维张量表示,其中的每个元素表示图片上一个像素的灰度值。一张彩色图片则需要用3维张量表示,其中两个维度为宽和高,另一个维度为颜色通道。TensorFlow的名字中就含有张量(Tensor)这个词。另一个词Flow的意思是“流”,表示通过张量的流动来表达计算。TensorFlow是一个通过图(Graph)的形式来表述计算的编程系统,图中每个节点为一种操作(Operation),包括计算、初始化、赋值等。张量则为操作的输入和输出。如上面的c = a + b为张量的加法操作,等效于c = tf.add (a, b),a和b是加法操作的输入,c是加法操作的输出。把张量提交给会话对象(Session)执行,就可以得到具体的数值。即在TensorFlow中包含两个阶段,先以计算图的方式定义计算过程,再提交给会话对象,执行计算并返回计算结果。这是由于,TensorFlow的核心不是用Python语言实现的,每一步调用都需要函数库与Python之间的切换,存在很大开销。而且TensorFlow通常在GPU上执行,如果每一步都自动执行的话,则GPU把大量资源浪费在多次接收和返回数据上,远不如一次性接收返回数据高效。我们可以把TensorFlow的计算过程设想为叫外卖。如果我们到馆子里用餐,可以边吃边上菜。如果叫外卖的话,就得先一次性点好菜谱,再让对方把饭菜做好后打包送来,让送餐的多次跑路不太合适。与sess.run (c)的等效的语句是c.eval (session = sess)。作为对象和参数,张量和会话刚好调了个位置。如果上下文中只用到一个会话,则可用tf.InteractiveSession()创建默认的会话对象,后面执行计算时无需再指定。即:>>>sess = tf.InteractiveSession ()>>>print (c.eval())另外,在先前的代码中,参数3和2被固化在代码中。如果要多次执行加法运算,我们可以用tf.placeholder代替tf.constant,而在执行时再给参数赋值。如下面的代码所示:>>>a = tf.placeholder(tf.int32)>>>b = tf.placeholder(tf.int32)>>> sess = tf.InteractiveSession()#下面的语句也可写成print (sess.run (c, {a:3, b:2}))>>>print (c.eval ({a:3, b:2}))>>>print (c.eval ({a:[1,2,3], b:[4,5,6]}))[5 7 9]另一种存储参数的方式是使用变量对象(tf.Variable)。与tf.constant函数创建的张量不同,变量对象支持参数的更新,不过这也意味着依赖更多的资源,与会话绑定得更紧。变量对象必须在会话对象中明确地被初始化,通常调用tf.global_variables_initializer函数一次性初始化所有变量。>>>a = tf.Variable (3)>>>b = tf.Variable (2)>>>init = tf.global_variables_initializer()>>>sess = tf.InteractiveSession()>>>init.run()>>>print(c.eval())>>>a.load (7)>>>b.load (8)15在深度学习中,变量对象通常用于表示待优化的模型参数如权重、偏置等,其数值在训练过程中自动调整。这在本文后面的例子中可以看到。3. TensorFlow机器学习入门3.1. 导入数据MNIST是一个非常有名的手写体数字识别数据集,常常被用作机器学习的入门样例。TensorFlow的封装让使用MNIST更加方便。现在我们就以MINIST数字识别问题为例探讨如何使用TensorFlow进行机器学习。MNIST是一个图片集,包含70000张手写数字图片:它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。在下面的代码中,input_data.read_data_sets()函数下载数据并解压。from tensorflow.examples.tutorials.mnist import input_data# MNIST_data为随意指定的存储数据的临时目录mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)下载下来的数据集被分成3部分:55000张训练数据(minist.train);5000张验证数据(mnist.validation);10000张测试数据(mnist.test)。切分的目的是确保模型设计时有一个单独的测试数据集不用于训练而是用来评估这个模型的性能,从而更加容易把设计的模型推广到其他数据集上。每一张图片包含个像素点。我们可以用一个数字数组来表示一张图片:数组展开为长度是的向量,则训练数据集mnist.train.images 是一个形状为 [6] 的张量。在此张量里的每一个元素,都表示某张图片里的某个像素的灰度,其值介于0和1之间。MNIST数据集的标签是长度为10的one-hot向量(因为前面加载数据时指定了one_hot为True)。 一个one-hot向量除了某一位的数字是1以外其余各维度数字都是0。比如,标签3将表示成([0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0])。因此, mnist.train.labels 是一个 [55000, 10] 的数字矩阵。3.2. 设计模型现在我们通过训练一个叫做Softmax的机器学习模型来预测图片里的数字。回顾一下,分类和回归(数值预测)是最基本的机器学习问题。线性回归是针对回归问题最基本的机器学习模型,其基本思想是为各个影响因素分配合适的权重,预测的结果是各影响因素的加权和。逻辑(Logistic)回归则常用来处理分类问题,它在线性回归的基础上,通过Logistic函数(也称Sigmoid函数)把低于和高于参照值的结果分别转换为接近0和1的数值。不过逻辑回归只能处理二分问题。Softmax回归则是逻辑回归在多分类问题上的推广。整个模型如下图所示:或者用线性代数公式表示为:其中,x为输入数据的特征向量,向量的长度为图片的像素(),向量中的每个元素为图片上各点的灰度值,W为的权重矩阵,其中784对应于图片的像素,10对应于0 - 9这10个数字,b为长度为10的向量,向量中的每个元素为0 - 9各个数字的偏置,得到各个数字的权重,最后softmax函数把权重转换为概率分布。通常我们最后只保留概率最高的那个数字,不过有时也关注概率较高的其他数字。下面是TensorFlow中实现该公式的代码,核心代码为最后一句,其中tf.matmul函数表示Tensor中的矩阵乘法。注意与公式中略有不同的是,这里把x声明为2维的张量,其中第1维为任意长度,这样我们就可以批量输入图片进行处理。另外,为了简单起见,我们用0填充W和b。x = tf.placeholder (tf.float32, [None, 784])W = tf.Variable (tf.zeros([784, 10]))b = tf.Variable (tf.zeros([10]))y = tf.nn.softmax (tf.matmul (x, W) + b)除了模型外,我们还需要定义一个指标来指示如何优化模型中的参数。我们通常定义指标来表示一个模型不尽人意的程度,然后尽量最小化这个指标。这个指标称为成本函数。成本函数与模型是密切相关的。回归问题一般用均方误差作成本函数,而对于分类问题,常用的成本函数是交叉熵(cross-entropy),定义为其中y是我们预测的概率分布,y’是实际的分布。对交叉熵的理解涉及信息论方面的知识,这里我们可以把它看作反映预测不匹配的指标,或者说该指标反映实际情况出乎预料的程度。注意交叉熵是非对称的。在TensorFlow中,交叉熵表示为下面的代码:cross_entropy = -tf.reduce_sum (y_ * tf.log (y))因为交叉熵一般会与Softmax回归一起使用,所以TensorFlow对这两个功能进行了统一封装,并提供了tf.nn.softmax_cross_entropy_with_logits函数。可以直接通过下面的代码来实现使用了Softmax回归之后的交叉熵函数。注意与公式中的y不同,代码中的y是Softmax函数调用前的值。最后调用tf.reduce_mean函数取平均值,因为图片是批量传入的,针对每张图片会计算出一个交叉熵。y = tf.matmul (x, W) + bcross_entropy = tf.reduce_mean (tf.nn.softmax_cross_entropy_with_logits (labels = y_, logits = y))3.3. 设计优化算法现在我们需要考虑如何调整参数使成本函数最小,这在机器学习中称为优化算法的设计问题。笔者这里对TensorFlow实现优化的过程作一个简要的介绍,要知道优化算法从某种意义上讲比模型更重要。TensorFlow是一个基于神经网络的深度学习框架。对于Softmax这样的模型,被当作是不含隐藏层的全连接神经网络。通过调整神经网络中的参数对训练数据进行拟合,可以使得模型对未知的样本提供预测的能力,表现为前向传播和反向传播(Backpropagation)的迭代过程。在每次迭代的开始,首先需要选取全部或部分训练数据,通过前向传播算法得到神经网络模型的预测结果。因为训练数据都是有正确答案标注的,所以可以计算出当前神经网络模型的预测答案与正确答案之间的差距。最后,基于预测值和真实值之间的差距,反向传播算法会相应更新神经网络参数的取值,使得在这批数据上神经网络模型的预测结果和真实答案更加接近。如下图所示:TensorFlow支持多种不同的优化器,读者可以根据具体的应用选择不同的优化算法。比较常用的优化方法有三种:tf.train.GradientDescentOptimizer、tf.train.AdamOptimizer和tf.train.MomentumOptimizer。train_step = tf.train.GradientDescentOptimizer (0.01).minimize (cross_entropy)在这里,我们要求TensorFlow用梯度下降算法(Gradient Descent)以0.01的学习速率最小化交叉熵。梯度下降算法是一个简单的学习过程,TensorFlow只需将每个变量一点点地往使成本不断降低的方向移动。语句返回的train_step表示执行优化的操作(Operation),可以提交给会话对象运行。3.4. 训练模型现在我们开始训练模型,迭代1000次。注意会话对象执行的不是W、b也不是y,而是train_step。for i in range(1000):batch_xs, batch_ys = mnist.train.next_batch(100)sess.run (train_step, feed_dict = {x: batch_xs, y_: batch_ys})该循环的每个步骤中,我们都会随机抓取训练数据中的100个批处理数据点,然后我们用这些数据点作为参数替换之前的占位符来运行train_step操作。使用一小部分的随机数据来进行训练被称为随机训练(stochastic training)- 在这里更确切的说是随机梯度下降训练。在理想情况下,我们希望用我们所有的数据来进行每一步的训练,因为这能给我们更好的训练结果,但显然这需要很大的计算开销。所以,每一次训练我们可以使用不同的数据子集,这样做既可以减少计算开销,又可以最大化地学习到数据集的总体特性。3.5. 评估模型到验证我们的模型是否有效的时候了。我们可以基于训练好的W和b,用测试图片计算出y,并取预测的数字与测试图片的实际标签进行对比。在Numpy中有个非常有用的函数argmax,它能给出数组中最大元素所在的索引值。由于标签向量是由0, 1组成,因此最大值1所在的索引位置就是类别标签。对y而言,最大权重的索引位置就是预测的数字,因为softmax函数是单调递增的。下面代码比较各个测试图片的预测与实际是否匹配,并通过均值函数计算正确率。import numpy as npoutput = sess.run (y, feed_dict = {x: mnist.test.images})print (np.mean (np.argmax(output,1) == np.argmax(mnist.test.labels,1)))我们也可以让TensorFlow来执行比较,这在很多时候更为方便和高效。TensorFlow中也有类似的argmax函数。correct_prediction = tf.equal (tf.argmax(y,1), tf.argmax(y_,1))accuracy = tf.reduce_mean (tf.cast(correct_prediction, "float"))print (sess.run (accuracy, feed_dict = {x: mnist.test.images, y_: mnist.test.labels}))这个最终结果值应该大约是91%。完整的代码请参考https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/mnist/mnist_softmax.py,有少量修改。4. TensorFlow深度学习入门4.1. 卷积神经网络介绍前面我们使用了单层神经网络。如果增加神经网络的层数,可以进一步提高正确率。不过,增加层数会使需要训练的参数增多,这除了导致计算速度减慢,还很容易引发过拟合问题。所以需要一个更合理的神经网络结构来有效地减少神经网络中参数个数。对于图像识别这类问题,卷积神经网络(CNN)是目前最为有效的结构。卷积神经网络是一个层级递增的结构,其基本思想是从对像素、边缘的认识开始,再到局部形状,最后才是整体感知。在传统方法中,我们需要在分类前对图像进行预处理,如平滑、去噪、光照归一化等,从中提取角点、梯度等特征,而卷积神经网络把这一过程自动化。当然,神经网络是一个黑盒子,没有前面所提到的这些概念,它所提取的都是抽象意义上的特征,与人类理解的语意特征无法对应。况且经过多层变换,图片早已面目全非。另外卷积神经网络也可以用于图像识别以外的领域。不过为了浅显易懂,下文中仍然使用像素、颜色之类的日常用语。卷积神经网络中特征识别的基本手段是卷积(Convolution)。我们可以理解为把图片进行特效处理,新图片的每个位置的像素值是原图片对应位置及相邻位置像素值的某种方式的叠加或取反,类似于Photoshop中的滤镜如模糊、锐化、马赛克什么的,TensorFlow中称为过滤器(Filter)。卷积的计算方式是相邻区域内像素的加权求和,用公式表示的话,仍是,不过计算限定在很小的矩形区域内。由于卷积只针对图片的相邻位置,可保证训练后能够对于局部的输入特征有最强的响应。另外,不论在图像的什么位置,都使用同一组权重,相当于把过滤器当作手电筒在图片上来回扫描,这使图像内容在图片中的位置不影响判断结果。卷积网络的这些特点使它显著减少参数数量的同时,又能够更好的利用图像的结构信息,提取出图像从低级到复杂的特征,甚至可以超过人类的表现。神经网络需要使用激活函数去除线性化,否则即便增加网络的深度也依旧还是线性映射,起不到多层的效果。与Softmax模型所使用的Sigmoid函数不同,卷积神经网络钟爱激活函数的是ReLU,它有利于反向传播阶段的计算,也能缓解过拟合。ReLU函数很简单,就是忽略小于0的输出,可以理解为像折纸那样对数据进行区分。注意在使用ReLU函数时,比较好的做法是用一个较小的正数来初始化偏置项,以避免神经元节点输出恒为0的问题。下图是Sigmoid和ReLU函数的对比。除了卷积外,卷积神经网络通常还会用到降采样(downsampling或subsampling)。我们可以理解为把图片适当缩小,由此在一定程度上控制过拟合并减少图像旋转、扭曲对特征提取的影响,因为降采样过程中模糊了方向信息。卷积神经网络正是通过卷积和降采样,成功将数据量庞大的图像识别问题不断降维,最终使其能够被训练。降采样在卷积神经网络中通常被称为池化(Pooling),包括最大池化、平均池化等。其中最常见的是最大池化,它将输入数据分成不重叠的矩形框区域,对于每个矩形框的数值取最大值作为输出。如下图所示。4.2. 构建LeNet-5网络对卷积神经网络有了基本了解后,我们现在开始使用这种网络来处理MNIST数字识别问题。这里参照最经典的LeNet-5模型,介绍如何使用TensorFlow进行深度学习。LeNet-5的结构如下图所示。可以看出,LeNet-5中包含两次的卷积和降采样,再经过两次全连接并使用Softmax分类作为输出。模型第一层是卷积层。输入是原始图片,尺寸为,颜色用灰度表示,因此数据类型为,考虑到批量输入,数据应有4个维度。过滤器尺寸为,计算32个特征,因此权重W为的张量,偏置b为长度32的向量。另外,为确保输出的图片仍为大小,在对图片边缘的像素进行卷积时,我们用0补齐周边。TensorFlow中,tf.nn.conv2d函数实现卷积层前向传播的算法。这个函数的前两个参数分别表示输入数据x和权重W,均为4个维度的张量,如前所述。权重在初始化时应该加入少量的噪声来打破对称性以及避免0梯度,这里我们用tf.truncated_normal函数生成的随机量填充。函数的随后两个参数定义卷积的方式,包括过滤器在图像上滑动时移动的步长及填充方式。步长用长度为4的数组表示,对应输入数据的4个维度,实际上只需要调整中间两个数字,这里我们设置为[1, 1, 1, 1],表示一个像素一个像素地移动。填充方式有“SAME”或“VALID”两种选择,其中“SAME”表示添加全0填充,“VALID”表示不添加。下面的代码实现模型第一层:# 这里使用tf.reshape函数校正张量的维度,-1表示自适应x_image = tf.reshape (x, [-1, 28, 28, 1])W_conv1 = tf.Variable (tf.truncated_normal ([5, 5, 1, 32], stddev = 0.1))b_conv1 = tf.Variable (tf.constant (0.1, shape = [32]))#执行卷积后使用ReLU函数去线性化h_conv1 = tf.nn.relu (tf.nn.conv2d(x_image, W_conv1, strides = [1, 1, 1, 1], padding = 'SAME') + b_conv1)模型第二层为降采样层。采样窗口尺寸为,不重叠,因此步长也是,采用最大池化,采样后图像的尺寸缩小为原来的一半。实现图片最大池化的函数是tf.nn.max_pool。它的参数与tf.nn.conv2d类似,只不过第二个参数设置的不是权重而是采样窗口的大小,用长度为4的数组表示,对应输入数据的4个维度。h_pool1 = tf.nn.max_pool (h_conv1, ksize = [1, 2, 2, 1],strides = [1, 2, 2, 1], padding = 'SAME')模型第三层为卷积层。输入数据尺寸为,有32个特征,过滤器尺寸仍为,需计算64个特征,因此权重W的类型为,偏置b为长度64的向量。W_conv2 = tf.Variable (tf.truncated_normal ([5, 5, 32, 64], stddev = 0.1))b_conv2 = tf.Variable (tf.constant(0.1, shape = [64]))h_conv2 = tf.nn.relu (tf.nn.conv2d(h_pool1, W_conv2, strides = [1, 1, 1, 1], padding = 'SAME') + b_conv2)模型第四层为降采样层,与第二层类似。图像尺寸再次缩小一半。h_pool2 = tf.nn.max_pool (h_conv2, ksize = [1, 2, 2, 1],模型第五层为全连接层。输入数据尺寸为,有64个特征,输出1024个神经元。由于是全连接,输入数据x和权重W都应为2维的张量。全连接参数较多,这里引入Dropout避免过拟合。Dropout在每次训练时随机禁用部分权重,相当于多个训练实例上取平均结果,同时也减少了各个权重之间的耦合。TensorFlow中实现Dropout的函数为tf.nn.dropout。该函数第二个参数表示每个权重不被禁用的概率。W_fc1 = tf.Variable (tf.truncated_normal ([7 * 7 * 64, 1024], stddev = 0.1))b_fc1 = tf.Variable (tf.constant (0.1, shape = [1024]))#把4维张量转换为2维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)keep_prob = tf.placeholder (tf.float32)h_fc1_drop = tf.nn.dropout (h_fc1, keep_prob)模型最后一层为全连接加上Softmax输出,类似之前介绍的单层模型。W_fc2 = tf.Variable (tf.truncated_normal ([1024, 10], stddev = 0.1))b_fc2 = tf.Variable (tf.constant(0.1, shape = [10]))y_conv = tf.matmul (h_fc1_drop, W_fc2) + b_fc2cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits (labels = y_, logits = y_conv))4.3. 训练和评估模型为了进行训练和评估,我们使用与之前简单的单层Softmax模型几乎相同的一套代码,只是我们会用更加复杂的ADAM优化器来缩短收敛时间,另外在feed_dict中加入额外的参数keep_prob来控制Dropout比例。然后每100次迭代输出一次日志。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, tf.float32))sess = tf.InteractiveSession()sess.run (tf.global_variables_initializer())for i in range(20000):batch_xs, batch_ys = mnist.train.next_batch(50)if i % 100 == 0:train_accuracy = accuracy.eval (feed_dict = {x: batch_xs, y_: batch_ys, keep_prob: 1.0})print('step %d, training accuracy %g' % (i, train_accuracy))train_step.run (feed_dict = {x: batch_xs, y_: batch_ys, keep_prob: 0.5})print ('test accuracy %g' % accuracy.eval (feed_dict = {x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))以上代码,在最终测试集上的准确率大概是99.2%。完整的代码请参考https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/mnist/mnist_deep.py,局部有修改。5. 总结在本文中,我们介绍了TensorFlow的基本用法,并以MNIST数据为例,基于Softmax模型和卷积神经网络分别讲解如何使用TensorFlow进行机器学习和深度学习。TensorFlow对深度学习提供了强大的支持,包含丰富的训练模型,还提供了TensorBoard、TensorFlow游乐场、TensorFlow Debugger等可视化和调试等手段方便。限于篇幅,这里不一一介绍,详见TensorFlow的官方文档。深度学习是一名较新的技术,理论和实践中都有不少坑。不过只要多学多上手,相信能让TensorFlow成为您手中的利器。参考资料:1. 《TensorFlow:实战Google深度学习框架》 才云科技、郑泽宇、顾思宇著2. 《面向机器智能的TensorFlow实践》 Sam Abrahams等著,段菲、陈澎译3. 《你好,TensorFlow》 http://mp.weixin.qq.com/s/0qJmicqIxwS7ChTvIcuJ-g4. 《TensorFlow白皮书》(译文) http://www.jianshu.com/p/65dc64e4c81f5. 《卷积神经网络》 http://blog.csdn.net/celerychen2009/article/details/89732186. 《卷积神经网络入门学习》 http://blog.csdn.net/hjimce/article/details/编辑:文婧作者简介王小鉴 重庆大学计算机硕士,IT老兵,现于重庆一家公司从事技术研发及团队管理。对海量数据存储、分布式计算、数据分析、机器学习有浓厚兴趣,重点关注性能优化、自然语言处理等技术。更多精彩内容请关注清华-青岛数据科学研究院官方微信公众平台“THU数据派”本文由百家号作者上传并发布,百家号仅提供信息发布平台。文章仅代表作者个人观点,不代表百度立场。未经作者许可,不得转载。晨语百家号最近更新:简介:不管结局如何,我们都要心存善念感恩世界!作者最新文章相关文章Sina Visitor Systemtensorflow学习笔记(五):TensorFlow变量共享和数据读取
  这一节我们提及了三个内容:、和,这些都是TensorFlow官方指导中的内容。会在程序中经常遇到所以放在一起进行叙述。前面都是再利用已有的数据进行tensorflow的学习,这一节我们要学习怎么从文件中读取我们需要的各类数据。
1、变量共享
  前面已经说过如何进行变量的生成和初始化内容,也用到了命名空间的概念,这里说一下什么是变量共享。当我们有一个非常庞大的模型的时候免不了需要进行大量的变量共享,而且有时候还希望能够在一个地方初始化所有的变量,这就需要tf.variable_scope() 和 tf.get_variable()。
  当只有两层的卷积的时候,前面的程序都是定义了两个卷积变量W1和W2(忽略b),而且简单的命名了。如下面:
def my_image_filter(input_images):
conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
name="conv1_weights")
conv1_biases = tf.Variable(tf.zeros([32]), name="conv1_biases")
conv1 = tf.nn.conv2d(input_images, conv1_weights,
strides=[1, 1, 1, 1], padding='SAME')
relu1 = tf.nn.relu(conv1 + conv1_biases)
conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
name="conv2_weights")
conv2_biases = tf.Variable(tf.zeros([32]), name="conv2_biases")
conv2 = tf.nn.conv2d(relu1, conv2_weights,
strides=[1, 1, 1, 1], padding='SAME')
return tf.nn.relu(conv2 + conv2_biases)
  但是假设你在reuse这个模型的时候如果有两个图像都调用my_image_filter就会有4*2个变量产生。用全局变量进行参数表示当然可以,但是却破坏了代码封装性,于是用tensorflow的变量作用域(Variable Scope)概念可以解决这个问题。这不得不用到两个函数:
tf.get_variable(name, shape, initializer): Creates or returns a variable with a given name.建立并返回一个给定名称的变量
tf.variable_scope( scope_name): Manages namespaces for names passed to tf.get_variable(). 管理变量命名空间忽略get_variable定义的变量,而name_scope是所有的都会放到其命名空间中见
  如何用这两个方式实现变量共享呢?方法如下假设被调用的函数为:
  def my_image_filter(input_images):
with tf.variable_scope("conv1"):
relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
with tf.variable_scope("conv2"):
return conv_relu(relu1, [5, 5, 32, 32], [32])
只要用到reuse_variables()进行注释即可,方法如下:
with tf.variable_scope("image_filters") as scope:
result1 = my_image_filter(image1)
scope.reuse_variables()
result2 = my_image_filter(image2)
至于为什么会这样,建议参考,因为后面还会用到所以这里只是大概了解一下。
2、线程(Threading)和队列(queues)
  这个是一个基本概念,也是后续数据读取的基础。这里会对相关概念进行一下详细的分析,包括队列、协调器(Coordinator)、QueueRunner。
(1)线程和队列使用的总览
  在TensorFlow中使这么描写队列的:Queues are a powerful mechanism for asynchronous(异步) computation using TensorFlow。队列其实也是一个节点,是个有点类似于variable的状态节点,通过入队(enqueue)和出队(dequeue)来维持一种状态。其中异步是一个很重要的内容,以数据读取为例:在输入的pipeline上,多线程可以有效地增加数据读取的效率,当我们用队列来准备用于训练的数据时可以:
  * 多线程的准备训练数据,然后把它们push到队列中
  * 训练线程生成一个一个训练operation来从数据队列中去除mini-batch数量的数据。
  其实Session就是多线程的,所以TensorFlow可以并行运行,但是多线程有三个条件需要满足:
  - 所有线程都需要能够同时停止
  - 必须能够捕捉和报告异常
  - 队列必须能在停止的时候适当关闭
  TensorFlow给了我们两个类用于帮助我们协调线程:tf.Coordinator和tf.train.QueueRunner。这两个类实际上是一起使用的,其中tf.Coordinator用于多线程停止和异常捕捉,tf.train.QueueRunner用于操作Tensor入队。
(2)主要的队列类
上面对线程和队列的作用进行了一些简单的介绍,我们常用的队列在TensorFlow中已经定义好了:tf.FIFOQueue和tf.RandomShuffleQueue,从名字就可以了解到两个队列的工作方式一个按顺序一个随机。这两个队列支持enqueue、enqueue_many和dequeue操作,这些操作内容也能直接理解出来。最长见的操作就是一次性读入数据,然后一个一个的出队,这里注意是没有dequeue_many操作的,如果想一次性得到多个输出需要使用tf.train.batch或是tf.train.shuffle_batch。
  这里还有一个在sequence-to-sequence上比较常用的tf.PaddingFIFOQueue也就是带变量填充的队列,而且它支持dequeue_many。
  我们可以自己定义一个队列,其常用的参数有min_after_dequeue(在dequeue后队列中剩余的最小数目的元素)、bounded capacity(队列中的最大元素数)、shape of the elements in the queue(如果shape为None则元素可以是任何shape)。但是在实际中我们通常不会直接使用队列本身,而是使用string_input_producer(后面读取数据时会用到)。
(2)Coordinator
  前面说过协调器帮助多线程共同停止。其关键的方法有:
tf.train.Coordinator.should_stop:如果线程可以停止返回返回True
tf.train.Coordinator.request_stop : 请求多线程停止
tf.train.Coordinator.join:直到指定线程停止前进行等待
我们可以初始化一个Coordinator对象,然后制造一些线程进行测试。教程给的代码如下,一个线程申请申请停止,其他线程的should_stop就会变为True:
def MyLoop(coord):
while not coord.should_stop():
...do something...
if ...some condition...:
coord.request_stop()
coord = tf.train.Coordinator()
threads = [threading.Thread(target=MyLoop, args=(coord,)) for i in xrange(10)]
for t in threads:
coord.join(threads)
  显然coordinator可以管理许多线程做不同的事情,而不用像上面的例子那样都做同一件事。而且关于异常的捕获和抛出可以看tf.train.Coordinator的文档。
(4)QueueRunner
  QueueRunne类会生成一些线程反复的执行enqueue操作。然后这些线程可以利用Coordinator来停止这些线程。而且如果有异常报道至Coordinator时一个QueueRunner会自动运行一个closer thread来关闭线程。
  下面可以自己使用queue runner来执行上面的结构:
  1. 首先建立一个使用TensorFlow队列(如tf.RandomShuffleQueue)的图,接着增加一个Op用于处理数据并将其入队。
  2. 建立一个queuerunner并行的运行4个线程进行入队,然后建立一个Coordinator让QueueRunner在这个Coordinator上开始线程,并在运行期间不断使用Coordinator监控停止情况。
  这里没有用官方文档,因为里面有些东西有一些错误。用的是的程序。
N_SAMPLES = 1000#样本数
NUM_THREADS = 4#线程数
# Generating some simple data生成数据和标签
# create 1000 random samples, each is a 1D array from the normal distribution (10, 1)
data = 10 * np.random.randn(N_SAMPLES, 4)+1
# create 1000 random labels of 0 and 1
target = np.random.randint(0, 2, size=N_SAMPLES)
#建立一个队列
queue = tf.FIFOQueue(capacity = 50, dtypes=[tf.float32, tf.int32 ], shapes =[[4], []])
#增加Op用于数据入队出队
enqueue_op = queue.enqueue_many([data, target])
dequeue_op = queue.dequeue()
# create NUM_THREADS to do enqueue创建一个QueueRunner用于管理4个线程
qr = tf.train.QueueRunner(queue, [enqueue_op]*NUM_THREADS)
with tf.Session() as sess:
# Create a coordinator, launch the queue runner threads.生成一个Coordinator启动线程
coord = tf.train.Coordinator()
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
for step in xrange (100): #do to 100 iterations,执行100次循环进行出队操作,得到需要的数据
if coord.should_stop():
data_batch,label_batch=sess.run(dequeue_op)#这里是一条一条的数据
coord.request_stop()
coord.join (enqueue_threads)
3、数据读取
  我们前面读取数据都是封装好的内容了,下面就打开封装看看tensorflow是如何读取数据的。上面的队列和线程这一部分内容是数据读取的基础内容,可以两部分对照着看。数据读取有三个来源:Python代码提供的(feeding)、从文件中读出来的、预加载数据。我们的内容主要集中在文件读取上。
(1)feeding
  这个我们遇到了几次,前面一直用的这种方法,先用python读数据再给tensorflow,需要配合Placeholder。python读数据可以用pickle结合os读取数据(这个看看Python就可以了)。但是这种方式读取数据却会出现一个问题就是数据是先读到我们的client手中然后再传入需要数据的地方(workers),当client和worker不在同一个机器上时就会非常慢,这种需要两次传导肯定会比较慢,可能单机的时候没那么明显而已。
(1)从文件读入
  从文件读入可以避免上面的问题,可以直接从数据存储的地方读到worker中。
  这里有三个(这个对数据读取的概念讲的很好)、、讲的比较详细,我根据官方文档进行了一些补充。
细,我根据官方文档进行了一些补充。
首先建立一个待读入的文件名列表。
有下面几种定义形式:[‘file0’, ‘file1’]、[(“file%d” % i) for i in range(2)],或者直接用python的os生成。
创建文件名队列
用tf.train.string_input_producer创建一个文件名队列,其有两个参数shffle(是否打乱文件名)和num_epoch(epoch需要的数量)。
定义一个reader
需要定义一个reader以便在文件名队列中读取数据。这时候由于有不同的数据格式存在,可以选择不同的reader,其中TextLineReader用的相对较多。而可以把Reader想象成一个每次返回不同值的Op(有点类似于Python的生成器),当我们使用Reader.read()的时候返回键值对,键用于鉴定文件名,值为对应的数据值。
csv或txt格式:使用tf.TextLineReader,配合tf.decode_csv进行读取。每次读取一行,其中tf.decode_csv为一个op,把读出来的数据放入一个tensor列表中(其record_defaults参数用于填充缺失值)
bin格式:对于二进制格式可以用tf.FixedLengthRecordReader读取,在所有的文件都是固定长度的时候读取整个文件,可以配合tf.decode_raw操作(将一个string转为uint8的tensor),比如图片数据就可以这么读取,见这里
标准tensorflow格式:不论什么数据都转为tensorflow的支持格式,推荐的格式是TFRecords file,然后再用tf.TFRecordReader进行读取,用 tf.parse_single_example进行解码,后面会提到。
一次读取全部数据:tf.WholeFileReader,其read(queue, name=None)方法返回的(key, value)。key为文件名,value为文件对应的内容。有一个例子可以参加这里和这里。
这里还有一个tf . ReaderBase帮助我们自定义reader。
这里以一个csv读取为例,我们命名为例1,完整程序见这里(源程序有一些函数已经过时如pack已经变为stack):
filename_queue=tf.train.string_input_producer(["heart.csv"])
reader=tf.TextLineReader(skip_header_lines=1)
# it means you choose to skip the first line for every file in the queue
# 跳过第一行,比如第一行是一些特征名。
key,value=reader.read(filename_queue)
读出来的数据形式可能为:
key = data/heart.csv:2
value = 144, 0.01, 4.41, 28.61, Absent, 55, 28.87, 2.06, 63,1
  train.string_input_producer所创建的队列是一个封装好的FIFOQueue用于读取文件名,这部分的流程最好参考一下上面提到的blog1。然后产生一个Reader这相当于数据队列,所以为了运行这个队列需要tf.Coordinator 和 tf.QueueRunner。程序如下:
filename_queue =tf.train.string_input_producer(filenames)
reader = tf.TextLineReader(skip_header_lines=1) # skip the first line in the file
key, value = reader.read(filename_queue)
with tf.Session() as sess:
coord = tf.train.Coordinator ()
threads = tf.train.start_queue_runners(coord=coord,sess=sess)#这个相当于前面的定义线程并开启
print sess.run(key) # data/heart.csv:2
print sess.run(value) # 144, 0.01, 4.41, 28.61, Absent, 55, 28.87, 2.06, 63,1
coord.request_stop ()
coord.join(threads)
  上面程序得到的value其实是一个string类型的,为了能得到可用的数据,比如上面的value包含9个特征和1个lable,我们需要使用decoder,decoder通常有两个参数,第一个是数据,第二个是默认数据。其中默认数据有两个作用,一个是指定value中的数据类型,还有一个就是在value中某一列为空时进行填充:
content=tf.decode_csv(value,record_defaults=record_defaults)
现在继续上面的例子:
record_defaults = [[1.0] for _ in range(N_FEATURES)] # define all features to be floats
record_defaults[4] = [''] # make the fifth feature string,第四个特征为string类型
record_defaults.append([1])# 让标签变为整数
content=tf.decode_csv(value,record_defaults=record_defaults)
(3)预处理
  可以对上面产生的数据进行一下预处理。比如数据增强,列表切分等等。这里继续对上面的例子进行预处理,比如对某些数据进行处理并切割数据。
# convert the 5th column (present/absent) to the binary value 0 and 1
# 转换第5列中的string为一个0.0或1.0的常数值
condition=tf.equal(content[4],tf.constant('Present')) #判断是否出席返回false或true
content[4] = tf.select(condition,tf.constant(1.0),tf.constant(0.0))#这个的意思是对应位置为true就变为1.0
# pack all 9 features into a tensor
features=tf.stack(content[:N_FEATURES]) #这个函数用于打包tf.stack([x, y, z]) = np.asarray([x, y, z])
# assign the last column to label
label=content[-1]
(4)Batching
在结束pipeline之前需要另一个队列来把数据整合起来,可以利用tf.train.batch或tf.train.shuffle_batch。程序如下:
# minimum number elements in the queue after a dequeue, used to ensure
# that the samples are sufficiently mixed
# I think 10 times the BATCH_SIZE is sufficient
# 10倍的batch_size作为出队后,队中最少的数据量,越大shuffle约充分但是速度慢占用空间大
min_after_dequeue=10*BATCH_SIZE
# the maximum number of elements in the queue队列中的最大的数据量,建议
# 值为min_after_dequeue + (num_threads + a small safety margin) * batch_size
capacity=20*BATCH_SIZE
# shuffle the data to generate BATCH_SIZE sample pairs
data_batch,label_batch=tf.train.shuffle_batch([features,label],batch_size=BATCH_SIZE,
capacity=capacity,min_after_dequeue=min_after_dequeue)
这样就能使用data_batch和label_batch进行训练了。
  其实还有一种读取方式速度更快一点,就是使用read_up_to的方式,这个在后面的补充部分会提到。
3、数据读取
例1、前面已经提到
  这里首先再增加一个读取二进制文件的例子。而这里说的二进制文件是TensorFlow自己的二进制文件格式TFRecords。TFRecords是一个序列化的tf.train.Example Protobuf对象,可以用几行代码就将一个图像转为一个二进制文档。大致流程是首先读取数据并把数据填充到一个Example protocol buffer中,然后序列化protocol buffer为一个string,并用tf.python_io.TFRecordWriter将这个string写入TFRecords 中。
  这里用一个例子2来介绍:
def get_image_binary (filename):
image=Image.open(filename)
image=np.asarray(image,np.uint8)
shape=np.array(image.shape,np.int32)
return shape.tobytes(),image.tobytes()
为了把上面生成的byte strings写入TFRecords需要使用tf.python_io.TFRecordWriter和tf.train.Features。
def write_to_tfrecord(label,shape,binary_image, tfrecord_file):
""" This example is to write a sample to TFRecord file. If you want to write more samples , just use a loop.
这个例子只是写入一个采样,想写入多组数据只需要用个循环
writer=tf.python_io.TFRecordWriter(tfrecord_file)
example=tf.train.Example(features=tf.train.Features(feature ={
'label':tf.train.Feature(bytes_list=tf.train.BytesList(value=[label])),
'shape':tf.train.Feature(bytes_list=tf.train.BytesList(value=[shape])),
'image':tf.train.Feature(bytes_list=tf.train.BytesList(value=[binary_image]))
writer.write(example.SerializeToString())
writer.close()
  这样就已经将数据写入了TFRecord中了,当要读取数据的时候,需要TFRecordReader 和tf.parse_single_example,但是注意这里读取的数据是一个tensor,想得到值还需要eval。
def read_from_tfrecord(filenames):
tfrecord_file_queue=tf.train.string_input_producer(filenames, name='queue')
reader=tf.TFRecordReader()
_ , tfrecord_serialized=reader.read(tfrecord_file_queue )
tfrecord_features=tf.parse_single_example(tfrecord_serialized,
features ={
'label' : tf.FixedLenFeature([],tf.string ),
'shape' : tf.FixedLenFeature([],tf.string ),
'image' : tf.FixedLenFeature([],tf.string ),
}, name='features')
image = tf.decode_raw(tfrecord_features['image'], tf.uint8 )
shape = tf.decode_raw(tfrecord_features['shape'], tf.int32 )
image=tf.reshape(image,shape)
label=tf.cast(tfrecord_features['label'],tf.string)
return label, shape, image
程序和讲解在我的上。
4.进阶补充
这里对上面用到的一些函数进行更详细的解释:
  我们在线程和队列部分知道了需要一个QueueRunner生成一些线程反复的执行enqueue操作,并且显示的定义了一个queue和QueueRunner进行了一些操作,但是后面我们就直接用到了Reader和start_queue_runners这些内容有什么关系呢  
1. tf.train.start_queue_runners
  用于启动图中所有的queue runners,我们的图中包含两个queue runners一个是文件名队列,一个是内存中的数据的队列。其构造函数为:
start_queue_runners(
sess=None,这个是执行队列操作Op的对话,默认是default session
coord=None,可选:协调器用于协调起始线程
daemon=True,是否线程标记为守护线程
start=True,如果是FALSE就只创造线程而不启动他们
collection=tf.GraphKeys.QUEUE_RUNNERS
2.tf.ReaderBase
  这个是所有Reader的基类,只要这个懂了就差不多都明白了。这个类简单的说是提供了将string(通常为filename)内容提取出来的功能,每次只能提取一条内容,但是一个文件有很多条内容而且我们又有很多的文件存在,所以为了更方便需要用一个队列来进行,队列中保存文件名然后在需要读取的时候用Reader出队。
3. batch用到的函数:
  在batch的时候遇到了tf.train.batch等函数,这里对这些函数的原理进行分析。这些函数在图中加入了一个queue用于聚合a batch of examples,它们还加了一个QueueRunner用于填充队列。
其中tf.train.batch和tf.train.shuffle_batch是单线程的产生数据,或是在有一个单一子图用于生成数据的时候用N个线程来运行(N是能够保证队列满的数量)
tf.train.batch_join和tf.train.shuffle_batch_join用于多子图多线程的生成数据。
这些看上去不好分辨,看一下构造函数就明白了。
 首先是tf.train.batch的构造函数:
tensors,可以是列表或字典,这个函数的返回值和这个tensor中的值是一样
batch_size,
num_threads=1,入队所需的线程数
capacity=32,队列中最大的element数量
enqueue_many=False,这个表示上面输入的tensor是不是只是一个example
shapes=None,
dynamic_pad=False,是否对于不同shape的例子进行补充
allow_smaller_final_batch=False,
shared_name=None,
接着是tf.train.batch_join:
batch_join(
tensors_list,这个是tensor的元组或字典列表,列表中的一个元素和上面batch中的tensors是一样的,而启动的线程数量等于len(tensors_list)
batch_size,
capacity=32,
enqueue_many=False,
shapes=None,
dynamic_pad=False,
allow_smaller_final_batch=False,
shared_name=None,
4.一种更高效的数据读取方法read_up_to
  我们前面的模式都是Reader.read+train_batch的形式,但是这样还是和理想速度差很多。其实我们可以用read_up_to的方式提高读取效率。这是Reader中的一个方法,其构造函数为:
read_up_to(
queue,文件队列
num_records,读取数据的数量
返回值是一个Tensor(keys,values)元组
其大概使用流程:
构造文件队列-&构造reader对象-&读取n条数据-&返回数据
而read+train_batch流程为:
构造文件队列-&构造reader对象-&读取1条数据-&将改数据加入队列-&若数据队列长度大于n,从队列中返回结果
没有更多推荐了,

我要回帖

更多关于 tensorflow 安装 的文章

 

随机推荐