深入理解TensorFlow变量

本文主要讲解以下语法的区别:

  • tf.Variable
  • tf.get_variable
  • tf.variable_scope(<scope_name>)
  • tf.name_scope(<scope_name>)

创建变量

变量通过tf.Variable类来操纵,可以通过实例化tf.Variable来创建变量,比如a = tf.Variable([1.0], name='a')。不过官方推荐的最佳创建方式是通过调用tf.get_variable来隐式的创建,这个函数要求你指定变量的名称,这个名称将作为副本用于访问相同的变量,以及在检查点和导出模型时命名次变量的值。tf.get_variable还允许你重复使用先前创建的同名变量,从而轻松定义复用层的模型。而直接通过tf.Variable来创建变量的话无论什么时候都会创建新的变量。

下面通过官方文档中的几个例子来说明。

创建一个形状是[1,2,3]名称为my_variable的变量,默认数据类型是tf.float32,并且默认数值将通过tf.glorot_uniform_initializer被随机初始化。

my_variable = tf.get_variable("my_variable", [1, 2, 3])

我们可以自己指定数据的类型和初始化器。TensorFlow提供了很多的初始化器(这个自己看api文档),还可以直接指定初始值,像这个样子:

my_int_variable = tf.get_variable("my_int_variable", [1, 2, 3], dtype=tf.int32, 
  initializer=tf.zeros_initializer)
other_variable = tf.get_variable("other_variable", dtype=tf.int32, 
  initializer=tf.constant([23, 42]))

变量集合

默认情况下,每个tf.Variable被放置在以下两个集合中:

tf.GraphKeys.GLOBAL_VARIABLES -- 能在多设备上共享

tf.GraphKeys.TRAINABLE_VARIABLES -- 会计算梯度的变量

如果你希望某个变量不要被训练,那可以放在这个集合里:tf.GraphKeys.LOCAL_VARIABLES

比如这样:

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

或者这样,添加trainableFalse

my_non_trainable = tf.get_variable("my_non_trainable", shape=(), trainable=False)

当然也可以创建自己的集合,像这样:

添加my_loacl变量到my_collection_name集合

tf.add_to_collection("my_collection_name", my_local)

取出集合中的变量list:

tf.get_collection("my_collection_name")

共享变量

我们在构造一些网络的时候,可能会遇到一个层多次利用或多个输入使用同一个层的情况,这种时候就需要重复利用同一套权重变量,不然就无法达到预期的效果,这个时候就可以通过变量作用域tf.variable_scope()tf.get_variable配合来实现,下面继续拿官方文档上的例子来做说明。

例如,我们通过便编写一个函数来创建卷积层:

def conv_relu(input, kernel_shape, bias_shape):
    # Create variable named "weights".
    weights = tf.get_variable("weights", kernel_shape,
        initializer=tf.random_normal_initializer())
    # Create variable named "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)

在我们的真实模型中,有两个输入需要使用同一个卷积,于是你可能会想这么做:

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])  # This fails.

但是你很快就会发现,这是行不通的,第一次调用函数的时候就已经创建了weightsbiases变量,第二次调用的时候变量名称已经存在,所以就无法再使用这两个名称了,而如果要复用与第一次想通的变量,就需要使用变量作用域,并且声明重复使用变量,像下面这样操作:(设置reuse=True

with tf.variable_scope("model"):
  output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True):
  output2 = my_image_filter(input2)

或者:(设置scope.reuse_variables())

with tf.variable_scope("model") as scope:
  output1 = my_image_filter(input1)
  scope.reuse_variables()
  output2 = my_image_filter(input2)

当然,我们可能遇到的更多情况是模型中有多次卷积操作,并且使用不同的变量,于是我们可以定义不同的变量作用域来实现:

def my_image_filter(input_images):
    with tf.variable_scope("conv1"):
        # Variables created here will be named "conv1/weights", "conv1/biases".
        relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
    with tf.variable_scope("conv2"):
        # Variables created here will be named "conv2/weights", "conv2/biases".
        return conv_relu(relu1, [5, 5, 32, 32], [32])

或者使用tf.Variable,这样每次调用conv_relu都会创建出不同的变量。

而名称作用域tf.name_scope并不会对tf.get_variable产生影响,只会对tf.Variable之类的其他的命名操作增加一个名称范围前缀。下面做个演示:

with tf.variable_scope("conv1"):
    a = tf.Variable([1.0], name='a')
with tf.variable_scope("conv2"):
    b = tf.Variable([1.0], name='a')
print(a)
print(b)
# 输出:
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv2/a:0' shape=(1,) dtype=float32_ref>

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv2"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 输出
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv2/a:0' shape=(1,) dtype=float32_ref>

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv1"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 报错
# ValueError: Variable conv1/a already exists, disallowed. Did you mean to set reuse=True in 
# VarScope? Originally defined at:

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv1", reuse=True):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 输出
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>

with tf.name_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.name_scope("conv2"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 报错
# ValueError: Variable a already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally defined at:

with tf.name_scope("conv1"):
    a = tf.get_variable('a', [1])
print(a)
# 输出 (可以看出名称域对它没有影响)
# <tf.Variable 'a:0' shape=(1,) dtype=float32_ref>

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

推荐阅读更多精彩内容