序列比较与索引提取
常量
tf.constant(value, dtype=None, shape=None, name=’Const’, verify_shape=False)
value:是一个必须的值,可以是一个数值,也可以是一个列表;可以是一维的,也可以是多维的。
dtype:数据类型,一般是tf.float32,tf.float64等
shape:表示张量的形状,即维数以及每一维的大小
name:可以是任何内容,只要是字符串就行
verify_shape:默认为False,如果修改为True的话表示检查value的形状与shape是否相符,如果不符会报错。
1 | #未指定shape参数 |
1 | #如果指定shape参数。当第一个参数value是数字时,张量的所有元素都会用该数字填充 |
变量
在构建模型时,需要使用tf.Variable来创建一个变量。
tf.Variable(initial_value,trainable=True,collections=None,validate_shape=True,name=None)
1 | biases=tf.Variable(tf.zeros([2]),name="biases") |
但在某种情况下, 一个模型需要使用其他模型创建的变量, 两个模型一起训练。 比如, 对抗网络中的生成器模型与判别器模型 。 如果使用tf.Variable, 将会生成一个新的变量, 而我们需要的是原来的那个biases变量。 这时怎么办呢 ?
这是就要通过get_variable方法,实现共享变量来解决这个问题。这个方法可以使用多套网络模型来训练一套权重。
使用get_variable获取变量
get_variable一般会配合variable_scope一起使用,以实现共享变量。variable_scope的意思时变量作用域。在某一作用域中的变量可以被设置成共享的方式,被其它网络模型使用。
get_variable函数的定义如下:
tf.get_variable(name,shape,initializer)
在Tensorflow里,使用get_variable生成的变量是以指定的name属性为唯一标识,并不是定义的变量名称。使用时一般通过name属性定位到具体变量,并将其共享到其它模型中。
首先我们来看看variable和get_variable的用法:
variable的用法演示:
1 | import tensorflow as tf |
上面代码运行后的结果:
上面代码中定义了两次var1,可以看到在内存中生成了两个var1(因为name不一样),但是对于图来讲后面的var1是生效的,也就是var1=2.0。
var2表明了Variable定义时没有指定名字,系统会自动给加上一个名字Variable:0。
get_variable用法演示:
接着上面的代码,使用get_variable添加get_var1变量。
1 | get_var1 = tf.get_variable("firstvar",[1], initializer=tf.constant_initializer(0.3)) |
加上上面的代码后,就会在执行第四行语句时报错。这表明,使用get_variable只能定义一次指定名称的变量。同时由于变量firstvar在前面使用Variable函数生成过一次,所以系统自动变成了firstvarvar_2:0。
把上面的代码换成下面再加到variable的用法代码里:
1 | get_var1 = tf.get_variable("firstvar",[1], initializer=tf.constant_initializer(0.3)) |
从运行结果知道,这次仍然是又定义了一个get_var1,不同的是改变了它的名字firstvar1。新的get_var1会在图中生效,所以它的输出值是0.4而不是0.3。
变量作用域:
再前面的例子中,都已经知道使用get_variable创建两个同样名字的变量是行不通的。像以下代码就是行不通的:
1 | var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32) |
如果真想这么做,可以使用variable_scope将它们隔开,
1 | import tensorflow as tf |
可以看出,var1和var2都使用firstvar的名字来定义。通过输出可以看出,其实生成的两个变量var1和var2是不同的,它们作用在不同的scope下,这就是scope的作用。
另外,scope还支持嵌套,将上面的代码中的第二个scope缩进一下,
1 | import tensorflow as tf |
variable_scope还可以让模型更直观的显示。
实现共享变量
费劲使用get_variable,目的就是为了通过它实现共享变量的功能。
variable_scope里面有个reuse=True属性,表示使用已经定义过的变量。这是get_variable将不再创建新的变量,而是去图中get_variable所创建过的变量中找与name相同的变量。
1 | import tensorflow as tf |
输出如下:
var1和var3的输出名字是一样的,var2和var4的输出名字也是一样的。这表明var1和var3共用一个变量,var2和var4共用一个变量。这就实现了共享变量。在实际应用过程中,可以把var1和var2放到一个网络模型里去训练,把var3和var4放到另一个网络模型里去训练,而两个模型的训练结果都会作用于一个模型的学习参数上。
初始化共享变量的作用域
variable_scope和get_variable都有初始化的功能。 在初始化时, 如果没有对当前变量初始化,则TensorFlow会默认使用作用域的初始化方法对其初始化, 并且作用域的初始化方法也有继承功能。
1 | import tensorflow as tf |
运行代码结果如下:
var1的数组值为0.4,表明继承了test1的值。var2数组值为0.4,表明其所在的作用域test2也继承了test1的初始化。变量var3在创建时同步指定了初始化操作,所以数组值为0.3。
如果去掉test2的缩进,结果如下:
作用域和操作符的受限范围
variable_scope还可以使用with variable_scope(“name”) as xxxscope的方式定义作用域,当使用这种方式时,所定义的作用域变量xxxscope将不在受到外围的scope所限制。
1 | import tensorflow as tf |
上面这个代码定义了作用域scope1 as sp,然后将sp放在作用域scope2中,并as 成sp1。运行代码结果如下:
sp1在scope2下, 但是输出仍是scope1, 没有改变。 在它下面定义的var3的名字是scope1/v3: 0, 表明也在scope1下, 再次说明sp没有受到外层(也就是scope2)的限制。
另外再介绍一个操作符的作用域tf.name_scope。操作符不仅受到tf.name_scope作用域的限制,还受到tf.variable_scope作用域的限制。
1 | import tensorflow as tf |
从结果可以看出,虽然v和x都在scope的bar下面,但是v的命名只受到scope的限制,tf.name_scope只能限制op。不能限制变量的命名。
在tf.name_scope函数中,还可以使用空字符将作用域返回到顶层。
1 | import tensorflow as tf |
从结果可以看出,y变成顶层了,而var4多了一个空层