TensorFlow的常量、变量、常用函数(一)

TensorFlow常用函数(一)

(1)tf.variable_scope('namespace')和tf.name_scope('namespace'):返回一个用于定义创建variable(层)的op的上下文管理器,相当于给下面的变量定义了一个命名空间,在这个with下面的所有节点会自动命名为:namespace/xxxx这样的格式

(2)tf.nn.conv2d(input,filter,strides,padding,use_cudnn_on_gpu=None,data_format=None, name=None):卷积操作

(3)tf.layers.conv2d(inputs,filters,kernel_size,strides=(1, 1), activation=None, padding='valid',    use_bias=True, kernel_initializer=None,bias_initializer=tf.zeros_initializer())):卷积操作

(4)激活函数比较:tf.nn.relu()、tf.nn.sigmoid()、tf.nn.tanh()、tf.nn.bias_add()、tf.nn.dropout():

(5)池化函数:tf.nn.avg_pool()、tf.nn.max_pool()

(6)tf.nn.conv2d_transpose():反卷积函数

(7)tf.nn.atrous_conv2d(value, filters, rate, padding, name=None):空洞卷积

(8)tf.Session.run(fetches,feed_dict=None,options=None,run_metadata=None):

(9)tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)和tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None):求两个分布的交叉熵


下一篇:TensorFlow常用函数(二)


1、创建tensor常量

(1)tf.constant(或tf.constant_initializer)创建常量:

      函数原型:tf.constant(value,dtype=None,shape=None,name='Const',verify_shape=False)
      tensor = tf.constant([1, 2, 3, 4, 5, 6, 7])   --->[1, 2, 3, 4, 5, 6, 7]
      tensor = tf.constant(-1.0, shape=[2, 3])   --->[[-1. -1. -1.] [-1. -1. -1.]]
      tensor=tf.constant(np.arange(10),dtype = tf.float32,shape = [2,5],name = "constant")
      -->[[0. 1. 2. 3. 4.] [5. 6. 7. 8. 9.]]

(2)tf.zeros(或tf.zeros_initializer)、tf.ones(或tf.ones_initializer)创建常量

       tensor=tf.zeros((2,3),dtype = tf.float32,name = None)
      -->[[0. 0. 0.] [0. 0. 0.]]
      tensor=tf.ones((2,3),dtype = tf.float32,name = None)
      -->[[1. 1. 1.] [1. 1. 1.]]

(3)递增序列创建常量

      tf.linspace(start,stop,num,name = None )
      tf.range(start,limit,delta = 1,name = "range")
      tensor=tf.linspace(0.0,10.0,11)--->[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
      tensor=tf.range(0.0,5.0,delta = 1,name = "range")--->[0. 1. 2. 3. 4.]

(4)创建特殊分布的常量(tf.random_normal_initializer()、tf.truncated_normal_initializer()、tf.random_uniform_initializer()、tf.random_shuffle_initializer())

      tf.random_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)
      tf.truncated_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)

      这两函数都是生成正态随机数,区别是truncated在生成随机数后,如果随机数在两倍标准差之外,就重新生成一个,直到生成最终结果。参数中shape为一个列表,表示形状,mean和stddev分别标书均值和标准差,seed为随机数种子。和其他python随机语法一样,固定seed以后,生成的随机数将不变。
      tf.random_uniform(shape,minval = 0.0,maxval = 1.0,dtype = tf.float32,seed = None):这个函数生成从0到1中平均分布的数值。   
      tf.random_shuffle(value,seed = None,name = None):传入一个tensor,然后将这个rensor进行随机洗牌。

(5)使用numpy的数组来创建

     x = np.array([[[11, 21, 31],[41, 51, 61]]])
     tensor= tf.convert_to_tensor(x, dtype = tf.float32)

     -->[[[11. 21. 31.]  [41. 51. 61.]]]

2、tensor变量的创建、保存、读取

     tensorflow中变量一般用来用来描述学习的参数,tensorflow变量需要先进行初始化,然后才可以使用,变量也可以进行分享与保存,变量部分主要有新建、初始化、保存与读取、分享、更新几个部分。

(1)tensorflow中有两个关于variable的op,tf.Variable()与tf.get_variable():

       1)tf.Variable(initial_value=None, trainable=True, collections=None,validate_shape=True, caching_device=None, name=None, variable_def=None, dtype=None, expected_shape=None, import_scope=None)

     2) tf.get_variable(name, shape=None, dtype=None, initializer=None, regularizer=None, trainable=True, collections=None, caching_device=None, partitioner=None, validate_shape=True, custom_getter=None)

     init_value为其初始化值,可以传入数值,列表,numpy数组,tf的tensor等,init_value必须含有shape,如果没有,validate_shape必须设置为False,但是对一个变量来说,最好使用固定结构的变量。trainable默认为True。这两个函数的区别如下:  使用tf.Variable时,如果检测到命名冲突,系统会自己处理。使用tf.get_variable()时,系统不会处理冲突,而会报错

w_1 = tf.Variable(3,name="w_1")
w_2 = tf.Variable(1,name="w_1")
print w_1.name
print w_2.name
输出
w_1:0
w_1_1:0

 w_1 = tf.get_variable(name="w_1",initializer=1)
w_2 = tf.get_variable(name="w_1",initializer=2)
错误信息

ValueError: Variable w_1 already exists, disallowed. Did you mean to set reuse=True in VarScope?

with tf.variable_scope("scope1"):
    w1 = tf.get_variable("w1", shape=[])
    w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
    w1_p = tf.get_variable("w1", shape=[])
    w2_p = tf.Variable(1.0, name="w2")
print(w1 is w1_p, w2 is w2_p)
输出
True  False

    看到这,就可以明白官网上说的参数复用的真面目了。由于tf.Variable() 每次都在创建新对象,所有reuse=True 和它并没有什么关系。对于get_variable(),来说,如果已经创建变量对象,就把那个对象返回,如果没有创建变量对象的话,就创建一个新的。基于这两个函数的特性,当我们需要共享变量的时候,需要使用tf.get_variable()。在其他情况下,这两个的用法是一样的。

(2)初始化:

      tensorflow中所有的变量在构架的时候都是一个框架,并没有具体的值,只有在初始化之后才有具体的值,最新版的tf采用initializer的方式,更符合面向对象的思想。主要有两个初始化器:
    1)tf.variables_initilizer(var_list,name = "nint")  :对指定的一个变量列表进行初始化
    2)tf.global_variables_initializer()  :对所有的变量进行初始化。
    3)tf.gloable_variables() :显示图中所有的变量,包括可训练的和不可训练的变量。 
    4)tf.trainable_variables() :显示图中可训练的变量,除非创建变量时指定trainable=False,否则均为可训练的。返回的结果是一个变量的列表,变量名是在定义变量的时候命名的名字:name=xxx。如果定义变量时没有显示命名,那么列表中的变量名为:Variable:0  Variable_1:0  Variable_2:0 …………
    5)tf.assert_variables_initialized(var_list) 判断传入的变量列表是否已经初始化,如果还有没初始化的,就报错。

注意:这里的初始化只是在计算图中定义了这样的一个节点,这个节点的运算是将变量进行初始化,所以在实际计算中,还是要调用seee.run(initializer),才能真正的完成初始化过程。

(3)变量的保存与读取:

      tensorflow使用Saver类进行变量的保存和读取,系统的变量将被保存到checkpoints中,point其本质是tensorflow使用二进制保存的变量名到变量值的map映射文件。新建Saver类,其init方法为:

__init__(
    var_list=None,#一系列的Variable,SaveableObject, 或者dict名称,如果没有则表示所有可保存的变量
    reshape=False,    #如果为True,表示允许恢复数据室variables有着不同的shape。
    sharded=False,    #如果为Ture,表示在不同的设备上通向检查点
    max_to_keep=5,  #保持最新的几个检查点,默认是5个
    keep_checkpoint_every_n_hours=10000.0,   #间隔多久保存一次检查点。
    name=None,            #string,可选的变量,具体没看明白
    restore_sequentially=False,    #一个Bool值,可以在恢复大量模型的时候减少内存的使用
    saver_def=None,     #用于替换当前的保存builder,这个builder是之前的只保存Graph的那种Saver。将其保存成proto的形式。有点没有理解。
    builder=None,      #当没有提供saver_def的时候可选的,默认为BaseSaverBuilder()
    defer_build=False,
    allow_empty=False,
    write_version=tf.train.SaverDef.V2,   #是用那个版本进行保存
    pad_step_number=False,
    save_relative_paths=False,
    filename=None
)

  1)简单的话,可以使用(如果不传入参数,默认是将所有的变量都保存):

      tf.train.Saver({"v1":v1,"v2":v2})          //传入dict
      tf.train.Saver([v1,v2])                         //传入list
      tf.train.Saver{v.op.name for v in [v1,v2]} //传入list

      从这个角度来看,Saver可以传入变量名set,变量名list,变量名:变量值的dict等类型。。参数中重要的是:
          max_to_keep: 最大备份数量,即保存最新的几份模型;
          keep_checkpoint_every_n_hours :每隔多少小时备份一次。

  2)Saver类需要调用save才能真正的完成保存。调用方法为:

saver = tf.train.Saver(max_to_keep=10)  # 最多保存10个模型文件
tf.train.Saver.save(sess,save_path,global_step=None,latest_filename =None)

   其中:sess 和path 是必须传入的,global_step为迭代轮数,保存时的文件名为在save_path后加上global_step。一般global_step=i,i为for循环中的迭代次数,当i满足一定条件时(如i%100==0)保存一次模型参数,文件名就为:*ckpi-100。保存之后会生成4个文件,分别是:checkpoint、model.ckpt-iter.data、model.ckpt-iter.meta、model.ckpt-iter.index。

  3)读取模型进行预测:

saver = tf.train.import_meta_graph("**ckpi.meta")  #加载了TensorFlow计算图上定义的全部变量,不用重新定义计算图
tf.train.Saver.restore(sess, save_path)   #简单的使用sess 和path就可以读取,需要指定文件名,下一种方式不用指定名字。

ckpt=tf.train.get_checkpoint_state('./CNN/')  # 获取最新的模型文件名,只需要指定保存模型的目录即可

saver.restore(sess, ckpt.model_checkpoint_path) # 读取最新的模型

x = graph.get_tensor_by_name("x:0")  # 读取计算图中的变量名,原来的变量名要设置好
feed_dict = {x:data}  # 定义好feed数据
y = graph.get_tensor_by_name("y:0") # 读取输出值
result=sess.run(y,feed_dict)   # 读取模型进行预测

3、tensor的一些属性

    a= np.array([[[11, 21, 31],[41, 51, 61]]])
    a = tf.convert_to_tensor(x, dtype = tf.float32)
    sess = tf.Session() 
    print(sess.run(a)[0,1,2])  //输出为:61.0
    print (a.shape)   //输出为:(1,2,3)的元组
    print (a.dtype)   //输出为:float32
    sess.close()
    with tf.Session() as sess: 
          print (a.eval()[0,1,2])   //输出61.0,a.eval()表示tensor所保存的值。
注:看tensor的维度的时候要从外向里面看。比如tensor: [  [ [11. 21. 31.]  [41. 51. 61.] ]  ],最外层中括号进去是第0维,也就是整个第二层中括号是一个元素 [ [11. 21. 31.]  [41. 51. 61.] ] 。第二层中括号进去是第1维,这时有两个中括号[11. 21. 31.]  [41. 51. 61.],表示有两个元素。第三层中括号进去是第2维,有三个元素11. 21. 31.。

4、常用函数

(1)tf.variable_scope('namespace')和tf.name_scope('namespace'):返回一个用于定义创建variable(层)的op的上下文管理器,相当于给下面的变量定义了一个命名空间,在这个with下面的所有节点会自动命名为:namespace/xxxx这样的格式

    函数原型:tf.variable_scope(name_or_scope,  default_name=None,  values=None,
                                                    initializer=None,  regularizer=None,  caching_device=None,
                                                    partitioner=None, custom_getter=None, reuse=None,
                                                   dtype=None,  use_resourc=None, constraint=None,
                                                   auxiliary_name_scope=True)

    参数:
      name_or_scope:string或者VariableScope表示打开的范围。
      default_name:如果name_or_scope参数为None,则使用默认的名称,该名称将是唯一的;如果提供了name_or_scope,它将不会被使用,因此它不是必需的,并且可以是None。
      values:传递给操作函数的Tensor参数列表。
      initializer:此范围内变量的默认初始值设定项。
      regularizer:此范围内变量的默认正规化器。
      caching_device:此范围内变量的默认缓存设备。
      partitioner:此范围内变量的默认分区程序。
      custom_getter:此范围内的变量的默认自定义吸气。
     reuse:可以是True、None或tf.AUTO_REUSE;如果是True,则我们进入此范围的重用模式以及所有子范围;如果是tf.AUTO_REUSE,则我们创建变量(如果它们不存在),否则返回它们;如果是None,则我们继承父范围的重用标志。当启用紧急执行时,该参数总是被强制为tf.AUTO_REUSE。
      dtype:在此范围中创建的变量类型(默​​认为传入范围中的类型,或从父范围继承)。
    use_resource:如果为false,则所有变量都将是常规变量;如果为true,则将使用具有明确定义的语义的实验性 ResourceVariables。默认为false(稍后将更改为true)。当启用紧急执行时,该参数总是被强制为true。
      constraint:一个可选的投影函数,在被Optimizer(例如用于实现层权重的范数约束或值约束)更新之后应用于该变量。该函数必须将代表变量值的未投影张量作为输入,并返回投影值的张量(它必须具有相同的形状)。进行异步分布式培训时,约束条件的使用是不安全的。
      auxiliary_name_scope:如果为True,则我们用范围创建一个辅助名称范围;如果为False,则我们不接触名称范围。

   两者区别:tf.variable_scope可以让变量有相同的命名,包括tf.get_variable()和tf.Variable()的变量。如果tf.variable_scope()下是用tf.get_variable()定义的变量,则想重用已定义的变量时需要加上参数:reuse=True,如果是tf.Variable()定义的变量,则:reuse=True不起作用,因为tf.Variable()无论如何都会创建新的变量。tf.name_scope()可以让变量有相同的命名,但只是限于tf.Variable()的变量。

with tf.variable_scope("a"):  
    v1 = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.0))    # v1在TensorFlow中的变量名为:a/v

with tf.variable_scope("a"):  
    v2 = tf.get_variable("v", [1])   # 报错 ValueError: Variable a/v already exists,  没有加reuse=True,会冲突  

with tf.variable_scope("a", reuse=True):  
    v3 = tf.get_variable("v", [1])  
    print(v3 == v1)  # True,因为scope:a内有"v"这个变量,并且reuse=True,所以返回原来的变量

with tf.variable_scope("b", reuse=True):  
  v4 = tf.get_variable("v",[1])  # 报错 ValueError: Variable b/v does not exist, or was not created with tf.get_variable().在scope:b内没有"v"这个变量,重用的时候出错。
with tf.name_scope('V1'):  
    a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))  
    a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')  
with tf.Session() as sess:  
    sess.run(tf.global_variables_initializer())  
    print (a1.name)  
    print (a2.name)  
结果为:
a1:0
V1/a2:0

(2)tf.nn.conv2d(input,filter,strides,padding,use_cudnn_on_gpu=None,data_format=None, name=None):卷积操作

    input:输入的张量,尺寸为:[batch, in_height, in_width, in_channels]
    filter:卷积核张量,尺寸为: [filter_height, filter_width, in_channels, out_channels] 
    padding:填充方式,'SAME'表示输出和输入尺寸相同(如果步长为1),输出是输入的1/4(如果步长为2).‘VALID’表示不填充,输出为:(输入尺寸-卷积核尺寸)/步长 + 1 
    strides:卷积步长,是一个四元组:[1,step_h,step_w,1], step_h和step_w分别为纵向和横向步长

例如:输入[64,28,28,1],卷积核[5,5,1,64],步长[1,2,2,1],如果为‘SAME’则输出为:(64, 14, 14, 64)。如果为'VALID',则输出为:(64, 12, 12, 64)。

(3)tf.layers.conv2d(inputs,filters,kernel_size,strides=(1, 1), activation=None, padding='valid',    use_bias=True, kernel_initializer=None,bias_initializer=tf.zeros_initializer())):卷积操作

    input : 输入的张量,[batch, in_height, in_width, in_channels]
    filters:输出的通道数,也就是卷积核个数
    kernel_size:卷积核的尺寸,可以是一个整数值或者一个二元组,卷积核通道和输入图像相同
    strides;卷积步长:(step_h,step_w)
    activation:激活函数
    padding :填充,为'valid'或者'same'
    use_bias:使用偏置,默认使用
    kernel_initializer:卷积核初始化器,如 tf.random_normal_initializer(0, 0.02)
    bias_initializer:偏置的初始化器

注:tf.layers.conv2d()卷积时,它的kernel和biase变量是自动创建并初始化的(而且应该是调用tf.get_variable()函数创建的),而且在这两个变量前加上命名空间conv2d,因此变量名为:conv2d/kernel:0和conv2d/biase:0,使用这个函数作为卷积时,获取卷积过程中需要优化的参数需要调用tf.trainable_variables()来获取,然后传入优化器。而使用tf.nn.conv2d()作为卷积函数时,卷积的参数(w、b)是手动创建并初始化的,因此可以手动添加参数到优化器。当然如果做好命名管理tf.name_scope(),也可以用tf.trainable_variables()来获取需要优化的参数。

(4)激活函数比较:tf.nn.relu()、tf.nn.sigmoid()、tf.nn.tanh()、tf.nn.bias_add()、tf.nn.dropout():

 

(5)池化函数:tf.nn.avg_pool()、tf.nn.max_pool()

    1)tf.nn.avg_pool(value,ksize,strides,padding,data_format='NHWC',name=None) :平均池化,计算窗口平均值。
      value:是一个四维的张量,数据维度是[batch, height, width, channels]
      ksize:是一个长度不小于4的整型数组,每一位上的值对应于输入数据张量中每一维的窗口对应值,[1,2,2,1]表示窗口为2*2。
      strides:一个长度不小于4的整型数组,该参数指定滑动窗口在输入数据张量每一维上的步长,[1,2,1,1]表示2*2的池化。
      padding:一个字符串, 取值为SAME或者VALID
      data_format:'NHWC'代表输入张量维度的顺序,N为个数,H为高度,W为宽度,C为通道数
      name:为这个操作取一个名字;

    2)tf.nn.max_pool(value,ksize, strides, padding, data_format='NHWC', name=None):最大池化,计算窗口最大值。

(6)tf.nn.conv2d_transpose():反卷积函数

    函数原型:tf.nn.conv2d_transpose(value, filter, output_shape, strides, padding="SAME", data_format="NHWC", name=None)
      value:指需要做反卷积的输入图像,它要求是一个Tensor
      filter:卷积核,它要求是一个Tensor,具有[filter_height, filter_width, out_channels, in_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,卷积核个数,图像通道数]
      output_shape:反卷积操作输出的shape,细心的同学会发现卷积操作是没有这个参数的.
      strides:反卷积时在图像每一维的步长,这是一个一维的向量,长度4,[stride_batch, stride_height, stride_width, stride_channel]
      padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式
      data_format:string类型的量,'NHWC'和'NCHW'其中之一,这是tensorflow新版本中新加的参数,它说明了value参数的数据格式。'NHWC'指tensorflow标准的数据格式[batch, height, width, in_channels],'NCHW'指Theano的数据格式,[batch, in_channels,height, width],当然默认值是'NHWC'。    

inputs=tf.constant(1.0, shape=[1,2,2,1])
kernel=tf.constant(1.0, shape=[3,3,1,1])
y1 = tf.nn.conv2d_transpose(inputs,kernel,output_shape=[1,4,4,1],strides=[1,1,1,1],padding="VALID")
y2 = tf.nn.conv2d_transpose(inputs,kernel,output_shape=[1,5,5,1],strides=[1,2,2,1],padding="VALID")
with tf.Session() as sess:
	print (sess.run(y1))
	print (sess.run(y2))

[[[[1.] [2.] [2.] [1.]]
  [[2.] [4.] [4.] [2.]]
  [[2.] [4.] [4.] [2.]]
  [[1.] [2.] [2.] [1.]]]]

[[[[1.] [1.] [2.] [1.] [1.]] 
  [[1.] [1.] [2.] [1.] [1.]]
  [[2.] [2.] [4.] [2.] [2.]]
  [[1.] [1.] [2.] [1.] [1.]]
  [[1.] [1.] [2.] [1.] [1.]]]]

总结: 

    1)、反卷积本质上还是卷积,只是卷积前会对输入内部、边界进行填充,使得输入分辨率增加,普通卷积只会对边界进行填充,所以输出的分辨率小于或等于输入分辨率。
    2)、一旦输入形状确定,stride参数确定,那么输出的形状也就确定了,所以给定的输出形状要匹配。根据输出形状、stride和padding方式进行卷积计算,计算出的结果要与输入形状相同,否则会报错。
    3)、内部填充方式与stride有关:

        当stride=1时,只进行外围填充,设填充后的形状为x*x,则 (x - kernel_size)/1+1=output_size,对于:

tf.nn.conv2d_transpose(inputs,kernel,output_shape=[1,4,4,1],strides=[1,1,1,1],padding="VALID")

      (x - 3)/1+1=4 ====>x = 6 ,所以先填充到6*6,在进行正常的卷积。

    

         当stride>1时,进行间隙填充,行与行之间,列与列之间都填充0,填充的行、列数为stride-1,设填充后的形状为x*x,则 (x - kernel_size)/1+1=output_size,对于:

tf.nn.conv2d_transpose(inputs,kernel,output_shape=[1,5,5,1],strides=[1,2,2,1],padding="VALID")

       (x - 3)/1+1=5 ====> x = 7 ,所以先填充到7*7,在进行正常的卷积。

    

(7)tf.nn.atrous_conv2d(value, filters, rate, padding, name=None):空洞卷积

      参数:

        value:指需要做卷积的输入图像,要求是一个4维Tensor,具有[batch, height, width, channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数]
       filters:相当于CNN中的卷积核,要求是一个4维Tensor,具有[filter_height, filter_width, channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],同理这里第三维channels,就是参数value的第四维
        rate:要求是一个int型的正数,正常的卷积操作应该会有stride(即卷积核的滑动步长),但是空洞卷积是没有stride参数的,这一点尤其要注意。取而代之,它使用了新的rate参数,那么rate参数有什么用呢?它定义为我们在输入图像上卷积时的采样间隔,你可以理解为卷积核当中穿插了(rate-1)数量的“0”,把原来的卷积核插出了很多“洞洞”,这样做卷积时就相当于对原图像的采样间隔变大了。具体怎么插得,可以看后面更加详细的描述。此时我们很容易得出rate=1时,就没有0插入,此时这个函数就变成了普通卷积。
        padding:string类型的量,只能是”SAME”,”VALID”其中之一,这个值决定了不同边缘填充方式。    

    完了,到这就没有参数了,或许有的小伙伴会问那“stride”参数呢。其实这个函数已经默认了stride=1,也就是滑动步长无法改变,固定为1。结果返回一个Tensor,填充方式为“VALID”时,返回[batch,height-2*(filter_width-1),width-2*(filter_height-1),out_channels]的Tensor,填充方式为“SAME”时,返回[batch, height, width, out_channels]的Tensor,其实用一句话概括就是,在不用pooling的情况下扩大感受野(pooling层会导致信息损失).下面我们来对比普通卷积核膨胀卷积区别:

img = tf.constant(value=[[[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]]]],dtype=tf.float32)
img = tf.concat(values=[img,img],axis=3)
filter = tf.constant(value=1, shape=[3,3,2,5], dtype=tf.float32)
out_img = tf.nn.atrous_conv2d(value=img, filters=filter, rate=1)
out_img = tf.nn.conv2d(input=img, filter=filter, strides=[1,1,1,1], padding='SAME')

输出5个channel,我们设置rate=1,此时空洞卷积可以看做普通的卷积,分别在SAME模式下输出如下: 

    调整rate=2,继续运行程序:

out_img = tf.nn.atrous_conv2d(value=img, filters=filter, rate=2, padding='SAME') 

    这里我们看到rate=2时,通过穿插“0”,卷积核由3*3膨胀到了5*5。 

 

  总结: 普通卷积核膨胀卷积的区别在于卷积核,膨胀卷积只需要按照膨胀率在卷积核中间插0,扩大卷积核尺寸,然后再和原图进行普通卷积,就得到膨胀卷积的结果。膨胀卷积的stride默认为1,在“SAME”和“VALID”方式下输入的图像尺寸和普通卷积有相同的结果。自己实现的实例如下: 

x1 = tf.constant(np.arange(25),dtype = tf.float32,shape = [1,5,5,1])
kernel = tf.constant(np.arange(9),dtype = tf.float32,shape = [3,3,1,1])
y5=tf.nn.atrous_conv2d(x1,kernel,2,'SAME')
with tf.Session() as sess:
	print (x1.eval())
	print (kernel.eval())
	print (sess.run(y5))
输出:
[[[[ 0.] [ 1.] [ 2.] [ 3.] [ 4.]]
  [[ 5.] [ 6.] [ 7.] [ 8.] [ 9.]]
  [[10.] [11.] [12.] [13.] [14.]]
  [[15.] [16.] [17.] [18.] [19.]]
  [[20.] [21.] [22.] [23.] [24.]]]]

[[[[0.]] [[1.]] [[2.]]]
 [[[3.]] [[4.]] [[5.]]]
 [[[6.]] [[7.]] [[8.]]]]

[[[[176.] [200.] [284.] [172.] [192.]]
  [[296.] [320.] [449.] [272.] [292.]]
  [[420.] [447.] [624.] [375.] [396.]]
  [[164.] [176.] [233.] [128.] [136.]]
  [[224.] [236.] [308.] [168.] [176.]]]]

(8)tf.Session.run(fetches,feed_dict=None,options=None,run_metadata=None):

    tf.Session.run() 执行 fetches 中的操作,计算 fetches 中的张量值。这个函数执行一步 TensorFlow 运算,通过运行必要的图块来执行每一个操作,并且计算每一个 fetches 中的张量的值,用相关的输入变量替换 feed_dict 中的值。fetches 参数可能是一个单一图元素,或者任意嵌套列表,元组,namedtuple,字典,或者有序字典在叶子中包含图元素。
    tf.Session.run()函数返回值为fetches的执行结果。如果fetches是一个元素就返回一个值;若fetches是一个list,则返回list的值,若fetches是一个字典类型,则返回和fetches同keys的字典。

(9)tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)和tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None):求两个分布的交叉熵

(1)第一个函数:tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)

  第一个参数logits:就是神经网络最后一层的输出,如果有batch的话,它的大小就是:(batchsize,num_classes),单样本的话,大小就是num_classes的一维向量。
  第二个参数labels:实际的标签,大小同上。

具体的执行流程大概分为两步:
  第一步是先对网络最后一层的输出做一个softmax,这一步通常是求取输出属于某一类的概率,对于单样本而言,输出就是一个num_classes大小的向量([Y1,Y2,Y3...]其中Y1,Y2,Y3...分别代表了是属于该类的概率)
  softmax的公式是:

                 

  用代码表示为:softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)

 第二步是softmax的输出向量[Y1,Y2,Y3...]和样本的实际标签做一个交叉熵,公式如下:

                
其中指代实际的标签中第i个的值(用mnist数据举例,如果是3,那么标签是[0,0,0,1,0,0,0,0,0,0],除了第4个值为1,其他全为0)。就是softmax的输出向量[Y1,Y2,Y3...]中,第i个元素的值。显而易见,预测越准确,结果的值越小(别忘了前面还有负号),最后求一个平均,得到我们想要的loss。
注意,tf.nn.softmax_cross_entropy_with_logits()这个函数的返回值并不是一个数,而是一个向量,如果要求交叉熵,我们要再做一步tf.reduce_sum操作,就是对向量里面所有元素求和,最后才得到,如果求loss,则要做一步tf.reduce_mean操作,对向量求均值。

(2)第二个函数:tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)

    这个函数和tf.nn.softmax_cross_entropy_with_logits函数比较明显的区别在于它的参数labels的不同,这里的参数label是非稀疏表示的,比如表示一个3分类的一个样本的标签,稀疏表示的形式为[0,0,1]这个表示这个样本为第3个分类,而非稀疏表示就表示为2(因为从0开始算,0,1,2,就能表示三类),同理[0,1,0]就表示样本属于第二个分类,而其非稀疏表示为1。tf.nn.sparse_softmax_cross_entropy_with_logits()比tf.nn.softmax_cross_entropy_with_logits多了一步将labels稀疏化的操作。因为深度学习中,图片一般是用非稀疏的标签的,所以用tf.nn.sparse_softmax_cross_entropy_with_logits()的频率比tf.nn.softmax_cross_entropy_with_logits高。

5、TensorFlow中的广播Broadcast机制:

    TensorFlow支持广播机制(Broadcast),可以广播元素间操作(elementwise operations)。正常情况下,当你想要进行一些操作如加法,乘法时,你需要确保操作数的形状是相匹配的,如:你不能将一个具有形状[3, 2]的张量和一个具有[3,4]形状的张量相加。但是,这里有一个特殊情况,那就是当你的其中一个操作数是一个具有单独维度(singular dimension)的张量的时候,TF会隐式地在它的单独维度方向填满(tile),以确保和另一个操作数的形状相匹配。所以,对一个[3,2]的张量和一个[3,1]的张量相加在TF中是合法的。(这个机制继承自numpy的广播功能。其中所谓的单独维度就是一个维度为1,或者那个维度缺失) 

    a = tf.constant([[1., 2.], [3., 4.]])
    b = tf.constant([[1.], [2.]])
    # c = a + tf.tile(b, [1, 2])
    c = a + b

    a = tf.constant([[1.], [2.]])
    b = tf.constant([1., 2.])
    c = tf.reduce_sum(a + b)

    答案应该是12.这是因为当两个张量的阶数不匹配的时候,在进行元素间操作之前,TF将会自动地在更低阶数的张量的第一个维度开始扩展,所以这个加法的结果将会变为[[2, 3], [3, 4]],所以这个reduce的结果是12. (答案详解如下,第一个张量的shape为[2, 1],第二个张量的shape为[2,]。因为从较低阶数张量的第一个维度开始扩展,所以应该将第二个张量扩展为shape=[2,2],也就是值为[[1,2], [1,2]]。第一个张量将会变成shape=[2,2],其值为[[1, 1], [2, 2]]。) 

Broadcasting 规则:
  当两个数组进行算术运算时,TensorFlow从后向前,逐元素比较两个数组的形状。当逐个比较的元素值满足以下条件时,认为满足 Broadcasting 的条件:
  1)相等
  2)其中一个是1
    当不满足时,会抛出 ValueError: frames are not aligne 异常。算术运算的结果的形状的每一元素,是两个数组形状逐元素比较时的最大值。而且,两个数组可以有不同的维度。比如一个 256x256x3 的数组储存 RGB 值,如果对每个颜色通道进行不同的放缩,我们可以乘以一个一维、形状为 (3, ) 的数组。因为是从后向前比较,因此 3 == 3,符合 Broadcasting 规则 。
  Image  (3d array): 256 x 256 x 3
  Scale  (1d array):             3
  Result (3d array): 256 x 256 x 3
当其中一个是 1 时,就会被“拉伸”成和另一个相同大小,即“复制”(没有真正复制)元素值来 Match 另一个,如:
  A      (4d array):  8 x 1 x 6 x 1
  B      (3d array):      7 x 1 x 5
  Result (4d array):  8 x 7 x 6 x 5
更多的例子:  

  A      (2d array):  5 x 4
  B      (1d array):      1
  Result (2d array):  5 x 4
  A      (2d array):  5 x 4
  B      (1d array):      4
  Result (2d array):  5 x 4
  A      (3d array):  15 x 3 x 5
  B      (3d array):  15 x 1 x 5
  Result (3d array):  15 x 3 x 5
  A      (3d array):  15 x 3 x 5
  B      (2d array):       3 x 5
  Result (3d array):  15 x 3 x 5
  A      (3d array):  15 x 3 x 5
  B      (2d array):       3 x 1
  Result (3d array):  15 x 3 x 5

一些反例(不满足 Broadcasting 规则 ):

  A      (1d array):  3
  B      (1d array):  4 # trailing dimensions do not match
  A      (2d array):      2 x 1
  B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched

    TensorFlow的其它常用函数。

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值