tensorflow(2)

序列比较与索引提取

常量

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
2
3
4
5
6
7
8
#未指定shape参数
import tensorflow as tf
a=tf.constant(1.0)
b=tf.constant([1,2])
sess=tf.Session()
with sess.as_default():
print("a的结果是:",sess.run(a))
print("b的结果是:",b.eval())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#如果指定shape参数。当第一个参数value是数字时,张量的所有元素都会用该数字填充
import tensorflow as tf
a=tf.constant(1.0,shape=[2,3])
sess=tf.Session()
with sess.as_default():
print("a的结果是:",sess.run(a))
a的结果是: [[1. 1. 1.]
[1. 1. 1.]]
b的结果是: [1 2]
#而当第一个参数value是一个列表时,注意列表的长度必须小于等于第三个参数shape的大小(即各维大小的乘积),否则会报错,这是因为函数会生成一个shape大小的张量,然后用value这个列表中的值一一填充shape中的元素。这里列表大小为7,而shape大小为2*3=6,无法正确填充,所以发生了错误
import tensorflow as tf
a=tf.constant([1,2,3,4,5,6,7],shape=[2,3])
sess=tf.Session()
with sess.as_default():
print("a的结果是:",sess.run(a))
#报错
ValueError: Too many elements provided. Needed at most 6, but received 7
#而如果列表大小小于shape的大小,则会用列表的最后一项元素填充剩余的张量元素
import tensorflow as tf
a=tf.constant([1,2,3,4,5,6,7],shape=[2,2,3])
sess=tf.Session()
with sess.as_default():
print("a的结果是:",sess.run(a))
a的结果是: [[[1 2 3]
[4 5 6]]

[[7 7 7]
[7 7 7]]]

变量

在构建模型时,需要使用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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import tensorflow as tf

var1 = tf.Variable(1.0 , name='firstvar')
print ("var1:",var1.name)

var1 = tf.Variable(2.0 , name='firstvar')
print ("var1:",var1.name)

var2 = tf.Variable(3.0 )
print ("var2:",var2.name)

var2 = tf.Variable(4.0 )
print ("var1:",var2.name)

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("var1=",var1.eval())
print("var2=",var2.eval())

上面代码运行后的结果:

上面代码中定义了两次var1,可以看到在内存中生成了两个var1(因为name不一样),但是对于图来讲后面的var1是生效的,也就是var1=2.0。

var2表明了Variable定义时没有指定名字,系统会自动给加上一个名字Variable:0。

get_variable用法演示:

接着上面的代码,使用get_variable添加get_var1变量。

1
2
3
4
5
get_var1 = tf.get_variable("firstvar",[1], initializer=tf.constant_initializer(0.3))
print ("get_var1:",get_var1.name)

get_var1 = tf.get_variable("firstvar",[1], initializer=tf.constant_initializer(0.4))
print ("get_var1:",get_var1.name)

加上上面的代码后,就会在执行第四行语句时报错。这表明,使用get_variable只能定义一次指定名称的变量。同时由于变量firstvar在前面使用Variable函数生成过一次,所以系统自动变成了firstvarvar_2:0。

把上面的代码换成下面再加到variable的用法代码里:

1
2
3
4
5
6
7
8
get_var1 = tf.get_variable("firstvar",[1], initializer=tf.constant_initializer(0.3))
print ("get_var1:",get_var1.name)

get_var1 = tf.get_variable("firstvar1",[1], initializer=tf.constant_initializer(0.4))
print ("get_var1:",get_var1.name)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("get_var1=",get_var1.eval())

从运行结果知道,这次仍然是又定义了一个get_var1,不同的是改变了它的名字firstvar1。新的get_var1会在图中生效,所以它的输出值是0.4而不是0.3。

变量作用域:

再前面的例子中,都已经知道使用get_variable创建两个同样名字的变量是行不通的。像以下代码就是行不通的:

1
2
var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
var2=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)

如果真想这么做,可以使用variable_scope将它们隔开,

1
2
3
4
5
6
7
import tensorflow as tf
with tf.variable_scope("test1"):
var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test2"):
var2=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
print("var1",var1.name)
print("var2",var2.name)

可以看出,var1和var2都使用firstvar的名字来定义。通过输出可以看出,其实生成的两个变量var1和var2是不同的,它们作用在不同的scope下,这就是scope的作用。

另外,scope还支持嵌套,将上面的代码中的第二个scope缩进一下,

1
2
3
4
5
6
7
import tensorflow as tf
with tf.variable_scope("test1"):
var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test2"):
var2=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
print("var1",var1.name)
print("var2",var2.name)

variable_scope还可以让模型更直观的显示。

实现共享变量

费劲使用get_variable,目的就是为了通过它实现共享变量的功能。

variable_scope里面有个reuse=True属性,表示使用已经定义过的变量。这是get_variable将不再创建新的变量,而是去图中get_variable所创建过的变量中找与name相同的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tensorflow as tf
with tf.variable_scope("test1"):
var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test2"):
var2=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test1",reuse=True):
var3=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test2",reuse=True):
var4=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)

print("var1",var1.name)
print("var2",var2.name)
print("var3",var3.name)
print("var4",var4.name)

输出如下:

var1和var3的输出名字是一样的,var2和var4的输出名字也是一样的。这表明var1和var3共用一个变量,var2和var4共用一个变量。这就实现了共享变量。在实际应用过程中,可以把var1和var2放到一个网络模型里去训练,把var3和var4放到另一个网络模型里去训练,而两个模型的训练结果都会作用于一个模型的学习参数上。

初始化共享变量的作用域

variable_scope和get_variable都有初始化的功能。 在初始化时, 如果没有对当前变量初始化,则TensorFlow会默认使用作用域的初始化方法对其初始化, 并且作用域的初始化方法也有继承功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import tensorflow as tf
#将test1作用域进行初始化为0.4
with tf.variable_scope("test1",initializer=tf.constant_initializer(0.4)):
#var1没有初始化
var1=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
with tf.variable_scope("test2"):
#嵌套的test2作用域也没有初始化
var2=tf.get_variable("firstvar",shape=[2],dtype=tf.float32)
#test2下的var3进行了初始化
var3=tf.get_variable("var3",shape=[2],initializer=tf.constant_initializer(0.3))

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("var1=",var1.eval())
print("var2=",var2.eval())
print("var3=",var3.eval())

运行代码结果如下:

var1的数组值为0.4,表明继承了test1的值。var2数组值为0.4,表明其所在的作用域test2也继承了test1的初始化。变量var3在创建时同步指定了初始化操作,所以数组值为0.3。

如果去掉test2的缩进,结果如下:

作用域和操作符的受限范围

variable_scope还可以使用with variable_scope(“name”) as xxxscope的方式定义作用域,当使用这种方式时,所定义的作用域变量xxxscope将不在受到外围的scope所限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tensorflow as tf
with tf.variable_scope("scope1") as sp:
var1=tf.get_variable("v",[1])
#输出作用域名称
print("sp:",sp.name)
print("var1:",var1.name)

with tf.variable_scope("scope2"):
var2=tf.get_variable("v",[1])
with tf.variable_scope(sp) as sp1:
var3=tf.get_variable("v3",[1])

print("sp1:",sp1.name)
print("var2:",var2.name)
print("var3:",var3.name)

上面这个代码定义了作用域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
2
3
4
5
6
7
import tensorflow as tf
with tf.variable_scope("scope"):
with tf.name_scope("bar"):
v=tf.get_variable("v",[1])
x=1.0+v
print("v:",v.name)
print("x.op",x.op.name)

从结果可以看出,虽然v和x都在scope的bar下面,但是v的命名只受到scope的限制,tf.name_scope只能限制op。不能限制变量的命名。

在tf.name_scope函数中,还可以使用空字符将作用域返回到顶层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import tensorflow as tf
with tf.variable_scope("scope1") as sp:
var1=tf.get_variable("v",[1])
with tf.variable_scope("scope2"):
var2=tf.get_variable("v",[1])
with tf.variable_scope(sp) as sp1:
var3=tf.get_variable("v3",[1])
#空字符作为作用域名
with tf.variable_scope(""):
var4=tf.get_variable("v4",[1])
with tf.variable_scope("scope"):
with tf.name_scope("bar"):
v=tf.get_variable("v",[1])
x=1.0+v
with tf.name_scope(""):
y=1.0+v
print("var4:",var4.name)
print("y.op:",y.op.name)

从结果可以看出,y变成顶层了,而var4多了一个空层

添加权重参数、损失值等的变化

首先收集变量:

而后在会话中运行:

----本文结束,感谢您的阅读。如有错,请指正。----
大哥大嫂过年好!支持我一下呗
0%