Deep learning 我可以在keras层之间共享权重,但其他参数不同吗?

Deep learning 我可以在keras层之间共享权重,但其他参数不同吗?,deep-learning,keras,Deep Learning,Keras,在keras中,是否可以在两层之间共享权重,但其他参数不同?考虑下面的(诚然有点做作)例子: 请注意,除了填充之外,其他层都是相同的。我能让keras使用相同的重量吗?(即,也相应地对网络进行培训?) 我看过keras文档,它似乎暗示共享只有在层完全相同的情况下才有效。据我所知,keras使用的通用“API级别”无法做到这一点。 然而,如果你再深入一点,有一些(丑陋的)方法来分享权重 首先,通过调用add\u weight(),在build()函数中创建Conv2D层的权重: self.kern

在keras中,是否可以在两层之间共享权重,但其他参数不同?考虑下面的(诚然有点做作)例子:

请注意,除了
填充
之外,其他层都是相同的。我能让keras使用相同的重量吗?(即,也相应地对网络进行培训?)


我看过keras文档,它似乎暗示共享只有在层完全相同的情况下才有效。

据我所知,keras使用的通用“API级别”无法做到这一点。 然而,如果你再深入一点,有一些(丑陋的)方法来分享权重

首先,通过调用
add\u weight()
,在
build()
函数中创建
Conv2D
层的权重:

self.kernel=self.add\u weight(shape=kernel\u shape,
初始值设定项=self.kernel\u初始值设定项,
name='kernel',
正则化器=self.kernel\u正则化器,
constraint=self.kernel\u约束)
对于您提供的用法(即,默认的
trainable
/
constraint
/
正则化器
/
初始值设定项
),
添加权重()
除了将权重变量附加到
\trainable\u权重
之外,没有什么特殊的作用:

weight=K.variable(初始值设定项(形状),dtype=dtype,name=name)
...
自身重量。可训练重量。附加(重量)
最后,由于
build()
仅在
\uuuuu call\uuuuuu()
内部调用(如果尚未构建层),因此可以通过以下方式创建层之间的共享权重:

  • 调用
    conv1.build()
    初始化要共享的
    conv1.kernel
    conv1.bias
    变量
  • 调用
    conv2.build()
    初始化层
  • conv2.kernel
    conv2.bias
    替换为
    conv1.kernel
    conv1.bias
  • conv2.\u可训练权重
    中删除
    conv2.kernel
    conv2.bias
  • conv1.kernel
    conv1.bias
    附加到
    conv2.\u可训练的\u权重
  • 完成模型定义。这里
    conv2.\uuuu call\uuuu()
    将被调用;但是,由于已经构建了
    conv2
    ,因此不会重新初始化权重
  • 以下代码段可能会有所帮助:

    def创建共享权重(conv1、conv2、输入形状):
    使用K.name\u范围(conv1.name):
    conv1.构建(输入_形状)
    使用K.name\u范围(conv2.name):
    conv2.构建(输入_形状)
    conv2.kernel=conv1.kernel
    conv2.bias=conv1.bias
    conv2.\u可训练的\u重量=[]
    conv2.\u可训练的\u权重.append(conv2.kernel)
    conv2.\u可训练的\u权重。附加(conv2.偏差)
    #检查权重是否已成功共享
    输入=输入(形状=(299299,3))
    conv1=Conv2D(64,3,padding='same')
    conv2=Conv2D(64,3,padding='valid')
    创建共享权重(conv1、conv2、input\u img.\u keras\u shape)
    打印(conv2.weights==conv1.weights)#真
    #安装模型后,检查重量是否相等
    左=conv1(输入信号)
    右=conv2(输入信号)
    左=全局平均池2D()(左)
    右=全局平均池2D()(右)
    合并=连接([左,右])
    输出=密集(1)(合并)
    模型=模型(输入、输出)
    compile(loss='binary\u crossentropy',optimizer='adam')
    X=np.random.rand(5299299,3)
    Y=np.random.randint(2,大小=5)
    模型拟合(X,Y)
    打印([np.all(w1==w2)用于w1,w2在zip中(conv1.get_-weights(),conv2.get_-weights())])#[True,True]
    

    这种不切实际的权重共享的一个缺点是,在模型保存/加载后,权重不会保持共享。这不会影响预测,但如果要加载经过训练的模型进行进一步微调,则可能会出现问题。

    您尝试过吗?理论上,具有相同内核大小和相同输入输出通道乘积的卷积层将具有相同维度的权重张量。@E_net4确实维度匹配,我的问题是如何让keras共享权重(即,我想试试,我只是不知道如何:))有趣!我不知道可以这样做。虽然无法保存共享是一个问题,但我希望能够微调模型。我没有尝试过,但我认为您可以使用
    model.save_weights()
    仅保存权重数组,而不是整个模型对象。要进行微调,只需使用相同的代码重新创建模型,然后调用
    model.load\u weights()
    。您确定这样做有效吗?我得到了OOM,我可以从
    tensorflow/core/common_runtime/bfc_allocator.cc
    看出tf实际上试图分配权重的多个副本。我的问题是由于自定义层。如果这些是共享的权重,则最好在层初始化期间传递它们。这解决了我的OOM问题。如果您正在编写自定义层,那么当然不应该使用此解决方案。重新编写层要干净得多。正如我所说的,这只是一个快速的破解。
    conv1 = Conv2D(64, 3, input_shape=input_shape, padding='same')
    conv2 = Conv2D(64, 3, input_shape=input_shape, padding='valid')