get_variable与variable_scope实现权值共享

 

 

 

这篇博文的主线是  探究如何使用tensorflow 的  tf.get_variable  和 tf.variable_scope 这两个函数 来实现  权值共享  , 这点别忘。

 

所谓的权值共享其实就是卷积核参数的共享,  首先在这里你要搞清楚是哪些卷积核的哪些参数参与了共享。

 

我们输入的  feature map 的长和宽(heoght , width)都是远大于卷积核( filter )的 size 的, 因此在一个二维平面上(暂时不考虑channel 的depth层面, 在这个层面上是二者的维度是相同的)  输入的   feature map 与 filter 是局部连接的(一个大一个小,想不局部连接都不行啊), 这也是CNN的特性之一。  然后这个 filter 是要遍历完整个平面的,遍历的步长由参数 stride 来控制。

如果你在脑海里能想象出这个画面, 那么我估计你也就能理解到底是哪些参数会共享了;

(总共就一个卷积核上上下下的来回遍历, 这在不叫共享 就有鬼了。)

再说的明白一些,其实就是相同的 filter 在每次遍历一张 feature map 时,filter 里面的参数是共享的,也就是对于这张feature map 所做的每次卷积操作都是用的一组数,每次有改变的是feature map的值。

如果你的 filter_size 为 3x3, 并且出入的 feature map 的depth (或者说叫 number of channel)是256, 

这就能决定你每一个 filter 的真实大小了,共计   3x3x256 个参数  。

我们取出256个 filter 中的第一个来举个例子, 我们给他编号为 F1  ,  也就是说只要是用 F1 来遍历你的输入, 那么这2304个参数就是固定死了的,  你上上下下怎么晃悠,用的都是这2304个参数。 

 

 

 

 

 

  • 首先我们从广义的层面来看,TensorFlow是如何管理所创建的参数的:

众所周知,一个神经网络的包含众多的参数, 那么就需要一个好的参数管理机制来管理它们。

在 tensorflow 中的管理机制是 基于变量的名称 来管理, 这样一来在不同的函数当中就可以直接通过变量的名字来

获取并使用这个变量, 不需要将变量以参数的形式四处传递, 增强了代码的可读性。

 

但是用名称来定义就会有可能出现同名的问题, 况且tensorflow 的运算机制有点特别,它是先定义图,再计算。

这样一来你所定义的每一个节点都会被加入到计算图当中去, 不存在 ‘ 局部变量 ’ 的这样一个说法,

所以,在为参数起名字的时候要小心一些,不能重, 可是这样会不会太麻烦了,定义sum之后是 sum1, 如果加法计算比较多,那岂不是要定义到sum100,

 

 

这时我们就可以借助  tf.name_scope 这个函数来解决这个问题了。

这个函数的作用看一眼下面的代码就能理解了:  

with tf.name_scope('abc'):
    v1 = tf.Variable(initial_value=1.0, name='v1_name')
    with tf.name_scope('def'):
        v2 = tf.Variable(initial_value=2.0, name='v2_name')

print(v1.name)
print(v2.name)


#  输出

abc/v1_name:0
abc/def/v2_name:0

 

其实tensorflow 一般情况下是不允许 同名变量的出现的,因为这样会带来很多问题,

但是如果你就是不小心( 或者说就是故意的)定义了两个同名的变量, 在编译的时候也不会出现问题,大概率会在

你之后调用的时候出错(这样说是应为我没实验过。。。)。

 

 

看吧,编译的时候确实可以通过, 但是它俏销的给你改了名字。

 

 

  • 明白了变量的管理机制,我们来看参数共享的实现

 

首先一点, 共享不是复制, 共享是每次使用同一组参数,  不是把一组参数复制了四处取用。(不知道我说明白了没有。。)

 

明白了这一点,我们来看 tf.get_variable  和 tf.variable_scope 这两个函数 , TensorFlow正是通过他们的组合来实现共享的。

 

 

首先是 tf.get_variable ,它的形式和 TensorFlow 中最基本的定义变量的方式 tf.variable 有些相似,

它的作用有两个,一个是创建变量,另一个则是获取变量。

当仅仅是用来创建变量时, 二者的功能基本上是等价的,差别就是在于指定变量名称的参数。

 

对于  tf.variable 来说,变量的名称是一个可选的参数, 可以在定义的时候通过  name = ' a '  的形式来给出,

当然了,你也可以不给他这个 name  ,这样做在编译的时候也是可以通过的。

import tensorflow as tf

a = tf.Variable(initial_value=3.0)
print(a)


#  结果是
<tf.Variable 'Variable:0' shape=() dtype=float32_ref>

(关于上面print 输出的结果, 这里顺便说一下;   tensorflow 和 numpy 不同,同样的做一个 a+b 的运算(a,b均是数组),前者返回的是一个张量的结构,后者返回的是一个ndarray类型的数组  。 所以,将前者的结果直接输出,得到的会是 name , type, shape 等这类用于描述一个张量的信息;  而后者的输出是一个ndarray类型的数组。

并且在 tensorflow 中把赋值操作也看做是一种特殊的运算, 所以这就能解释为什么不经过session ,直接 print 的输出得到的都是一些描述张量的信息了,  因为这个运算本来就没有得到你以为的结果,只得到了这种结构信息;  ps:个人理解,如有错误欢迎指出)

 

但对于 tf.get_variable 这个函数来说,它参数列表当中的 name 是一个必填的参数。

a = tf.get_variable(initializer=1.0)
print(a)


TypeError: get_variable() missing 1 required positional argument: 'name'

在编译的时候, tf.get_variable 会根据这个给出的  name 参数的值来创建或者是获取一个变量。

如果这个变量不存在,那么一切都正常,他会创建一个;

但是如果这个变量是已经存在了的,这时候程序就会报错;

import tensorflow as tf

a = tf.get_variable(name='weight', initializer=1.0)
print(' a 已创建', a)
b = tf.get_variable(name='weight', initializer=2.0)

#  输出 
a 已创建 < tf.Variable 'weight:0' shape = () dtype = float32_ref >

ValueError: Variable weight already exists, disallowed.
Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? 

 

出错了, 出错了, 程序报错了, 为什么呢? 

 因为有重复的变量了,  并且程序不会自动给你改名了,所以就错了呗。

 

重复就出错很好啊, 这不就正使我们的目的么 (共享),

每个filter 的卷积操作对应 一个 tf. variable_scope(), 

这样一来     在这个区域内  (scope)    就只允许出现 一个 weight 和 一个 bias,  多了就编译不过了。

 

那其他的参数怎么办?

你说嘞。。。。。。

自然是共享这个了,

 

怎么共享  ?

 说实话这里我也有些含糊,, 应该是用resue 的, 

但具体的实现我还得在研究研究。。。。今天就先到这吧,

 

 

顺便说一句

name_scope是对  tf. get_variable 不起作用的。

 

with tf.name_scope('abc'):
    v1 = tf.Variable(initial_value=1.0, name='v1')
    with tf.name_scope('def'):
        v2 = tf.Variable(initial_value=2.0, name='v2')
        v3 = tf.get_variable(name='v3', initializer=3.0)

print(v1.name)
print(v2.name)
print(v3.name)

#   output  
abc/v1:0
abc/def/v2:0
v3:0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值