前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深度学习500问——Chapter12:网络搭建及训练(1)

深度学习500问——Chapter12:网络搭建及训练(1)

作者头像
JOYCE_Leo16
发布2024-06-17 09:06:09
1090
发布2024-06-17 09:06:09
举报
文章被收录于专栏:计算机视觉计算机视觉

12.1 TensorFlow

12.1.1 TensorFlow 是什么

TensorFlow支持各种异构平台,支持多CPU/GPU、服务器、移动设备,具有良好的跨平台的特性;TensorFlow架构灵活,能够支持各种网络模型,具有良好的通用性;此外,TensorFlow架构i具有良好的可扩展性,对OP的扩展支持,Kernel特化方面表现出众。

TensorFlow最初由Google大脑的研究员和工程师开发出来,用于机器学习和神经网络方面的研究,于2015.10宣布开源,在众多深度学习框架中脱颖而出,在Github上获得了最多的Star量。

12.1.2 TensorFlow的设计理念是什么

TensorFlow的设计理念主要体现在两个方面:

(1)将图定义和图运算完全分开。TensorFlow 被认为是一个“符号主义”的库。我们知道,编程模式通常分为命令式编程(imperative style programming)和符号式编程(symbolic style 皮肉gramming)。命令式编程就是编写我们理解的通常意义上的程序,很容易理解和调试,按照原有逻辑执行。符号式编程涉及很多的嵌入和优化,不容易理解和调试,但运行速度相对有所提升。现有的深度学习框架中,Torch是典型的命令式的,Caffe、MXNet采用了两种编程模式混合的方法,而TensorFlow完全采用符号式编程。

符号式计算一般是先定义各种变量,然后建立一个数据流图,在数据流图中规定各个变量间的计算关系,最后需要对数据流图进行编译,但此时的数据流图还是一个空壳,里面没有任何实际数据,只有把需要运算的输入放进去后,才能在整个模型中形成数据流,从而形成输出值。

例如:

代码语言:javascript
复制
t = 8 + 9
print(t)

  在传统的程序操作中,定义了 t 的运算,在运行时就执行了,并输出 17。而在 TensorFlow中,数据流图中的节点,实际上对应的是 TensorFlow API 中的一个操作,并没有真正去运行:

代码语言:javascript
复制
import tensorflow as tf
t = tf.add(8,9)
print(t)

#输出  Tensor{"Add_1:0",shape={},dtype=int32}

(2)TensorFlow 中涉及的运算都要放在图中,而图的运行只发生在会话(session)中。开启会话后,就可以用数据去填充节点,进行运算;关闭会话后,就不能进行计算了。因此,会话提供了操作运行和 Tensor 求值的环境。

  例如:

代码语言:javascript
复制
import tensorflow as tf
#创建图
a = tf.constant([4.0,5.0])
b = tf.constant([6.0,7.0])
c = a * b
#创建会话
sess  = tf.Session()
#计算c
print(sess.run(c))   #进行矩阵乘法,输出[24.,35.]
sess.close()
12.1.3 TensorFlow特点有哪些

1. 高度的灵活性

TensorFlow并不仅仅是一个深度学习库,只要可以把你的计算过程表示成一个数据流图的过程,我们就可以使用TensorFlow来进行计算。TensorFlow允许我们用计算图的方式建立计算网络,同时又可以很方便的对网络进行操作。用户可以基于TensorFlow的基础上用Python编写自己的上层结构和库,如果TensorFlow没有提供我们需要的API的,我们也可以自己编写底层的C++代码,通过自定义操作将新编写的功能添加到TensorFlow中。

2. 真正的移植性

TensorFlow 可以在 CPU 和 GPU 上运行,可以在台式机、服务器、移动设备上运行。你想在你的笔记本上跑一下深度学习的训练,或者又不想修改代码,想把你的模型在多个CPU上运行, 亦或想将训练好的模型放到移动设备上跑一下,这些TensorFlow都可以帮你做到。

3. 多语言支持

TensorFlow采用非常易用的python来构建和执行我们的计算图,同时也支持 C++ 的语言。我们可以直接写python和C++的程序来执行TensorFlow,也可以采用交互式的ipython来方便的尝试我们的想法。当然,这只是一个开始,后续会支持更多流行的语言,比如Lua,JavaScript 或者R语言。

4. 丰富的算法库

TensorFlow提供了所有开源的深度学习框架里,最全的算法库,并且在不断的添加新的算法库。这些算法库基本上已经满足了大部分的需求,对于普通的应用,基本上不用自己再去自定义实现基本的算法库了。

5. 完善的文档

TensorFlow的官方网站,提供了非常详细的文档介绍,内容包括各种API的使用介绍和各种基础应用的使用例子,也包括一部分深度学习的基础理论。

  自从宣布开源以来,大量人员对TensorFlow做出贡献,其中包括Google员工,外部研究人员和独立程序员,全球各地的工程师对TensorFlow的完善,已经让TensorFlow社区变成了Github上最活跃的深度学习框架。

12.1.4 TensorFlow的系统架构是怎样的

整个系统从底层到上层可分为七层:

设备层:硬件计算资源,支持CPU、GPU

网络层:支持两种通信协议

数值计算层:提供最基础的计算,有线性计算、卷积计算

高维计算层:数据的计算都是以数组的形式参与计算

计算图层:用来设计神经网络的结构

工作流层:提供轻量级的框架调用

构造层:最后构造的深度学习网络可以通过TensorBoard服务端可视化

12.1.5 TensorFlow编程模型是怎样的

TensorFlow 的编程模型:让向量数据在计算图里流动。那么在编程时至少有这几个过程:1、构建图;2、启动图;3、给图输入数据并获取结果。

1. 构建图

TensorFlow 的图的类型是 tf.FGraph,它包含着计算节点和tensor的集合。

这里引用了两个新概念:tensor和计算节点。我们先介绍tensor,一开始我们就介绍了,我们需要把数据输入给启动的图才能获取计算结果。那么问题来了,在构建图时用什么表示中间计算结果?这个时候tensor的概念就需要引入了。类型是 tf.Tensor,代表某个计算节点的输出,一定要看清楚是“代表”。它主要有两个作用:

(1)构建不同计算节点直接的数据流

(2)在启动图时,可以设置某些tensor的值,然后获取指定tensor的值。这样就完成了计算的输入输出功能。

如下代码所示:

代码语言:javascript
复制
inImage = tf.placeholder(tf.float32,[32,32,3],"inputImage")
processedImage = tf.image.per_image_standardization(inImage,"processedImage")

 这里inImage和processedImage都是tensor类型。它们代表着计算节点输出的数据,数据的值具体是多少在启动图的时候才知道。上面两个方法调用都传递了一个字符串,它是计算节点的名字,最好给节点命名,这样我们可以在图上调用get_tensor_by_name(name)获取对应的tensor对象,十分方便。(tensor名字为“<计算节点名字>:<tensor索引>”)

  创建tensor时,需要指定类型和shape。对不同tensor进行计算时要求类型相同,可以使用 tf.cast 进行类型转换。同时也要求 shape (向量维度)满足运算的条件,我们可以使用 tf.reshape 改变shape。

  现在了解计算节点的概念,其功能是对tensor进行计算、创建tensor或进行其他操作,类型是tf.Operation。获取节点对象的方法为get_operation_by_name(name)。

构建图,如下代码:

代码语言:javascript
复制
g=tf.Graph()

with g.as_default():
    input_data=tf.placeholder(tf.float32,[None,2],"input_data")
    input_label=tf.placeholder(tf.float32,[None,2],"input_label")

    W1=tf.Variable(tf.truncated_normal([2,2]),name="W1")
    B1=tf.Variable(tf.zeros([2]),name="B1")

    output=tf.add(tf.matmul(input_data,W1),B1,name="output")
    cross_entropy=tf.nn.softmax_cross_entropy_with_logits(logits=output,labels=input_label)

    train_step=tf.train.AdamOptimizer().minimize(cross_entropy,name="train_step")

    initer=tf.global_variables_initializer()

上面的代码中我们创建了一个图,并在上面添加了很多节点。我们可以通过调用get_default_graph()获取默认的图。

  Input_data,input_label,W1,B1,output,cross_entropy都是tensor类型,train_step,initer,是节点类型。

有几类tensor或节点比较重要,下面介绍一下:

(1)placeholder

Tensorflow,顾名思义, tensor代表张量数据,flow代表流,其最初的设计理念就是构建一张静态的数据流图。图是有各个计算节点连接而成,计算节点之间流动的便是中间的张量数据。要想让张量数据在我们构建的静态计算图中流动起来,就必须有最初的输入数据流。而placeholder,翻译过来叫做占位符,顾名思义,是给我们的输入数据提供一个接口,也就是说我们的一切输入数据,例如训练样本数据,超参数数据等都可以通过占位符接口输送到数据流图之中。使用实例如下代码:

代码语言:javascript
复制
import tensorflow as tf
x = tf.placeholder(dtype=tf.float32,shape=[],name='x')
y = tf.placeholder(dtpe=tf.float32,shape=[],nmae='y')
z = x*y
with tf.Session() as sess:
	prod = sess.run(z,feed_dict={x:1.,y:5.2})
	print(prod)
[out]:5.2

(2)variable

无论是传统的机器学习算法,例如线性支持向量机(Support Vector Machine, SVM),其数学模型为y = <w,x> + b,还是更先进的深度学习算法,例如卷积神经网络(Convolutional Neural Network, CNN)单个神经元输出的模型y = w*x + b。可以看到,w和b就是我们要求的模型,模型的求解是通过优化算法(对于SVM,使用 SMO[1]算法,对于CNN,一般基于梯度下降法)来一步一步更新w和b的值直到满足停止条件。因此,大多数机器学习的模型中的w和b实际上是以变量的形式出现在代码中的,这就要求我们在代码中定义模型变量。

代码语言:javascript
复制
import tensorflow as tf
a = tf.Variable(2.)
b = tf.Variable(3.)
with tf.Session() as sess:
	sess.run(tf.global_variables_initializer()) #变量初始化
    print(sess.run(a*b))
[out]:6.

[1] Platt, John. "Sequential minimal optimization: A fast algorithm for training support vector machines." (1998).

(3)initializer

由于tensorflow构建的是静态的计算流图,在开启会话之前,所有的操作都不会被执行。因此为了执行在计算图中所构建的赋值初始化计算节点,需要在开启会话之后,在会话环境下运行初始化。如果计算图中定义了变量,而会话环境下为执行初始化命令,则程序报错,代码如下:

代码语言:javascript
复制
import tensorflow as tf
a = tf.Variable(2.)
b = tf.Variable(3.)
with tf.Session() as sess:
	#sess.run(tf.global_variables_initializer()) #注释掉初始化命令
    print(sess.run(a*b))
[Error]: Attempting to use uninitialized value Variable

2. 启动图

先了解session的概念,然后才能更好的理解图的启动。   图的每个运行实例都必须在一个session里,session为图的运行提供环境。Session的类型是tf.Session,在实例化session对象时我们需要给它传递一个图对象,如果不显示给出将使用默认的图。Session有一个graph属性,我们可以通过它获取session对应的图。

代码如下:

代码语言:javascript
复制
numOfBatch=5
datas=np.zeros([numOfBatch,2],np.float32)
labels=np.zeros([numOfBatch,2],np.float32)

sess=tf.Session(graph=g)
graph=sess.graph
sess.run([graph.get_operation_by_name("initer")])

dataHolder=graph.get_tensor_by_name("input_data:0")
labelHolder=graph.get_tensor_by_name("input_label:0")
train=graph.get_operation_by_name("train_step")
out=graph.get_tensor_by_name("output:0")

for i inrange(200):
   result=sess.run([out,train],feed_dict={dataHolder:datas,labelHolder:labels})
   if i%100==0:
       saver.save(sess,"./moules")

sess.close()

代码都比较简单,就不介绍了。不过要注意2点:1.别忘记运行初始化节点,2.别忘记close掉session对象以释放资源。

3. 给图输入数据并获取结果

代码:

代码语言:javascript
复制
for i inrange(200):
    result=sess.run([out,train],feed_dict={dataHolder:datas,labelHolder:labels})

 这里主要用到了session对象的run方法,它用来运行某个节点或tensor并获取对应的值。我们一般会一次传递一小部分数据进行mini-batch梯度下降来优化模型。

  我们需要把我们需要运行的节点或tensor放入一个列表,然后作为第一个参数(不考虑self)传递给run方法,run方法会返回一个计算结果的列表,与我们传递的参数一一对应。

  如果我们运行的节点依赖某个placeholder,那我们必须给这个placeholder指定值,怎么指定代码里面很清楚,给关键字参数feed_dict传递一个字典即可,字典里的元素的key是placeholder对象,value是我们指定的值。值的数据的类型必须和placeholder一致,包括shape。值本身的类型是numpy数组。

这里再解释一个细节,在定义placeholder时代码如下:

代码语言:javascript
复制
input_data=tf.placeholder(tf.float32,[None,2],"input_data")
input_label=tf.placeholder(tf.float32,[None,2],"input_label")

  shape为[None,2],说明数据第一个维度是不确定的,然后TensorFlow会根据我们传递的数据动态推断第一个维度,这样我们就可以在运行时改变batch的大小。比如一个数据是2维,一次传递10个数据对应的tensor的shape就是[10,2]。可不可以把多个维度指定为None?理论上不可以!

12.1.6 如何基于TensorFlow搭建VGG16

介绍完关于tensorflow的基础知识,是时候来一波网络搭建实战了。虽然网上有很多相关教程,但我想从最标准的tensorflow代码和语法出发(而不是调用更高级的API,失去了原来的味道),向大家展示如何搭建其标准的VGG16网络架构。话不多说,上代码:

代码语言:javascript
复制
import numpy as np
import tensorflow as tf

def get_weight_variable(shape):
    return tf.get_variable('weight', shape=shape, initializer=tf.truncated_normal_initializer(stddev=0.1))

def get_bias_variable(shape):
    return tf.get_variable('bias', shape=shape, initializer=tf.constant_initializer(0))

def conv2d(x, w, padding = 'SAME', s=1):
    x = tf.nn.conv2d(x, w, strides=[1, s, s, 1], padding = padding)
    return x

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

def conv2d_layer(x,in_chs, out_chs, ksize, layer_name):
    with tf.variable_scope(layer_name):
        w = get_weight_variable([ksize, ksize, in_chs, out_chs])
        b = get_bias_variable([out_chs])
        y = tf.nn.relu(tf.bias_add(conv2d(x,w,padding = 'SAME', s=1), b))
    return y

def fc_layer(x,in_kernels, out_kernels, layer_name):
    with tf.variable_scope(layer_name):
        w = get_weight_variable([in_kernels,out_kernels])
        b = get_bias_variable([out_kernels])
        y = tf.nn.relu(tf.bias_add(tf.matmul(x,w),b))
    return y
        
def VGG16(x):
    conv1_1 = conv2d_layer(x,tf.get_shape(x).as_list()[-1], 64, 3, 'conv1_1')
    conv1_2 = conv2d_layer(conv1_1,64, 64, 3, 'conv1_2')
    pool_1 = maxPoolLayer(conv1_2)
    
    conv2_1 = conv2d_layer(pool1,64, 128, 3, 'conv2_1')
    conv2_2 = conv2d_layer(conv2_1,128, 128, 3, 'conv2_2')
    pool2 = maxPoolLayer(conv2_2)
    
	conv3_1 = conv2d_layer(pool2,128, 256, 3, 'conv3_1')
    conv3_2 = conv2d_layer(conv3_1,256, 256, 3, 'conv3_2')
	conv3_3 = conv2d_layer(conv3_2,256, 256, 3, 'conv3_3')
    pool3 = maxPoolLayer(conv3_3)
    
	conv4_1 = conv2d_layer(pool3,256, 512, 3, 'conv4_1')
    conv4_2 = conv2d_layer(conv4_1,512, 512, 3, 'conv4_2')
	conv4_3 = conv2d_layer(conv4_2,512, 512, 3, 'conv4_3')
    pool4 = maxPoolLayer(conv4_3)
    
	conv5_1 = conv2d_layer(pool4,512, 512, 3, 'conv5_1')
    conv5_2 = conv2d_layer(conv5_1,512, 512, 3, 'conv5_2')
	conv5_3 = conv2d_layer(conv5_1,512, 512, 3, 'conv5_3')
    pool5 = maxPoolLayer(conv5_3)
    
	pool5_flatten_dims = int(np.prod(pool5.get_shape().as_list()[1:]))
    pool5_flatten = tf.reshape(pool5,[-1,pool5_flatten_dims])
    
    fc_6 = fc_layer(pool5_flatten, pool5_flatten_dims, 4096, 'fc6')
	fc_7 = fc_layer(fc_6, 4096, 4096, 'fc7')
	fc_8 = fc_layer(fc_7, 4096, 10, 'fc8')
    
    return fc_8
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 12.1 TensorFlow
    • 12.1.1 TensorFlow 是什么
      • 12.1.2 TensorFlow的设计理念是什么
        • 12.1.3 TensorFlow特点有哪些
          • 12.1.4 TensorFlow的系统架构是怎样的
            • 12.1.5 TensorFlow编程模型是怎样的
              • 12.1.6 如何基于TensorFlow搭建VGG16
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档