Tensorflow-Variables-变量-LowlevelApi-翻译整理

Variables变量用于共享、持久化状态管理。

tf.Variable表示此数值在计算过程中可能会变化,它独立于sess.run上下文存在。因此我们可以在sessionA中利用ops操作改变这个变量,进而在sessionB中使用这个变量,以此达到传递共享数值的目的。


创建变量

使用tf.get_variable(name,shape,dtype,initializer)创建变量。

如果设定了初initializer初始化函数返回明确的值,那么不能同时使用shape参数,否则必须指定shape。

import tensorflow as tf
sess=tf.Session()

v1 = tf.get_variable("v1", [1, 2, 3]) #随机0~1之间
v2 = tf.get_variable("v2", [1, 2, 3],initializer=tf.zeros_initializer) #全0
v3 = tf.get_variable("v3", dtype=tf.int32,initializer=tf.constant([23, 42])) #不能同时设定shape!

init=tf.global_variables_initializer()
sess.run(init)

print(sess.run(v1))
print(sess.run(v2))
print(sess.run(v3))

打印结果

[[[-0.8628024   0.6660923   0.8403772 ]
  [-0.5985474  -0.073349    0.23826087]]]
[[[0. 0. 0.]
  [0. 0. 0.]]]
[23 42]
变量集合Variable collections

将一组变量放入集合进行管理

import tensorflow as tf
sess=tf.Session()

v1 = tf.get_variable("v1", [1, 2, 3])
tf.add_to_collection("mycollection", v1) #将v1放入名称为mycollection的集合

mycollection=tf.get_collection("mycollection")
print(mycollection) #一个列表

init=tf.global_variables_initializer()
sess.run(init)

print(sess.run(mycollection[0])) #获取v1

打印结果

[<tf.Variable 'v1:0' shape=(1, 2, 3) dtype=float32_ref>]
[[[-0.28881794  0.46018004 -0.83893764]
  [-0.93932706  0.84757173  0.78609943]]]

默认情况tf.Variable都会被放入两个默认的集:

  • tf.GraphKeys.GLOBAL_VARIABLES可用于多设备共享变量
  • tf.GraphKeys.TRAINABLE_VARIABLES会被计算梯度下降

也可以在创建变量的时候立即放入集合,语法:

my_local = tf.get_variable(name="my_local",
                                   shape=(),
                                   collections=[tf.GraphKeys.LOCAL_VARIABLES])

或者直接设定变量可被训练:

my_non_trainable = tf.get_variable("my_non_trainable",
                                   shape=(),
                                   trainable=False)
Device placement设备放置

可以把变量限定在特定设备,例如下面代码把v变量放置在GPU1下面:

with tf.device("/device:GPU:1"):
  v = tf.get_variable("v", [1])

分布式计算中变量的设备非常重要,放置不当可能导致运算缓慢甚至出错。tf.train.replica_device_setter方法可以自动化处理。

cluster_spec = {
    "ps": ["ps0:2222", "ps1:2222"],
    "worker": ["worker0:2222", "worker1:2222", "worker2:2222"]}
with tf.device(tf.train.replica_device_setter(cluster=cluster_spec)):
  v = tf.get_variable("v", shape=[20, 20])  

初始化变量

变量在使用前必须被初始化。使用low level api的时候必须手工明确初始化,hight level api中的tf.contrib.slim, tf.estimator.Estimator and Keras会自动在训练前完成初始化。

  • 一次性初始化所有变量tf.global_variables_initializer()
  • 初始化单个变量session.run(my_variable.initializer)
  • 查看哪些变量没被初始化session.run(tf.report_uninitialized_variables())

注意,tf.global_variables_initializer()初始化时候并没有固定顺序,如果某个变量依赖于其他变量的求值,那将遇到错误。当所有变量没被初始化完成的时候,用variable.initialized_value()来获取计算值,而不要直接使用变量。

v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = tf.get_variable("w", initializer=v.initialized_value() + 1)

使用变量

在计算图中,变量可以当作tf.tensor张量对象使用。例如

v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = v + 1

设定变量的值,可以直接使用变量自带的方法assign, assign_add,assign_sub等。

import tensorflow as tf
sess=tf.Session()

v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
assignment = v.assign_add(1)

init=tf.global_variables_initializer()
sess.run(init)

print(sess.run(assignment)) #或者assignment.op.run(), 或assignment.eval()

输出

1.0

由于类似梯度下降算法这样的优化器会在运算时候不断修改变量,所以变量是不稳定的。我们可以用tf.Variable.read_value方法读取变化之后的值。

import tensorflow as tf
sess=tf.Session()

v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
assignment = v.assign_add(1)


init=tf.global_variables_initializer()
sess.run(init)

print(sess.run(v.read_value()))
with tf.control_dependencies([assignment]):
    w = v.read_value()    
    print(sess.run(w))

打印结果

0.0
1.0

共享变量Sharing variables

Tensorflow有两种方法共享变量:

  • 显式的传递tf.Variable对象
  • 隐式的使用tf.variable_scope包裹tf.variable对象

比如下面的示意代码中,我们创建了一个卷积层(线性整流单元):

def conv_relu(input, kernel_shape, bias_shape):
    # 创建变量 "weights".
    weights = tf.get_variable("weights", kernel_shape,
        initializer=tf.random_normal_initializer())
    # 创建变量"biases".
    biases = tf.get_variable("biases", bias_shape,
        initializer=tf.constant_initializer(0.0))
    conv = tf.nn.conv2d(input, weights,
        strides=[1, 1, 1, 1], padding='SAME')
    return tf.nn.relu(conv + biases)

上面的代码定义了conv_relu方法,其中有两个变量weight和biases。看上去很清楚,但是,当我们使用它的时候就遇到了问题:

input1 = tf.random_normal([1,10,10,32])
input2 = tf.random_normal([1,20,20,32])
x = conv_relu(input1, kernel_shape=[5, 5, 32, 32], bias_shape=[32])
x = conv_relu(x, kernel_shape=[5, 5, 32, 32], bias_shape = [32])  # 失败!

我们试图链接两个卷积层,但计算机在计算的时候无法清楚是重新创建weight和biases还是继续使用已经存在的。
下面的代码正确的创建两个卷积层,使用新的变量:

def my_image_filter(input_images):
    with tf.variable_scope("conv1"):
        # 这里创建的变量被重新命名为 "conv1/weights", "conv1/biases".
        relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
    with tf.variable_scope("conv2"):
        # 这里创建的变量被重新命名为 "conv2/weights", "conv2/biases".
        return conv_relu(relu1, [5, 5, 32, 32], [32])

如果你需要共享变量而不是重新创建,以下两种语法都可以实现:

with tf.variable_scope("model"):
  output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True): #注意这里reuse=True
  output2 = my_image_filter(input2)
with tf.variable_scope("model") as scope:
  output1 = my_image_filter(input1)
  scope.reuse_variables() #注意这里!
  output2 = my_image_filter(input2)

其中上一种方法可以改进为

with tf.variable_scope("model") as scope: # 注意这里的as scope
  output1 = my_image_filter(input1)
with tf.variable_scope(scope, reuse=True): #注意这里传入的scope
  output2 = my_image_filter(input2)

本篇小结

  • 创建变量tf.get_variable(name,shape,dtype,initializer)
  • 变量集合tf.add_to_collection("mycollection", v1)
  • 置入不同的设备
  • 变量初始化方法tf.global_variables_initializer()session.run(my_variable.initializer)
  • 使用变量
  • 修改变量assign, assign_add,assign_sub
  • 共享变量tf.variable_scope

探索人工智能的新边界

如果您发现文章错误,请不吝留言指正;
如果您觉得有用,请点喜欢;
如果您觉得很有用,感谢转发~


END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,132评论 6 523
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,457评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,411评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,147评论 1 301
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,145评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,611评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,962评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,948评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,479评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,514评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,640评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,228评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,973评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,402评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,551评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,210评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,714评论 2 366

推荐阅读更多精彩内容