如何自定义Keras图层名称并使其自动递增layer.name

chhkpiq4  于 2023-10-19  发布在  其他
关注(0)|答案(4)|浏览(135)

我目前正在尝试有多个层与自定义激活的名称cust_sig。但是当我尝试编译模型时,我得到了一个ValueError,因为多个层具有相同的名称cust_sig。我知道我可以手动更改每个层的名称,但我想知道是否可以像内置层那样自动将_1, _2, ...添加到名称中。模型定义可以在下面找到。

# Creating a model
from tensorflow.python.keras import keras
from tensorflow.python.keras.models import Model
from tensorflow.python.keras.layers import Dense

# Custom activation function
from tensorflow.python.keras.layers import Activation
from tensorflow.python.keras import backend as K
from keras.utils.generic_utils import get_custom_objects

def custom_activation(x):
    return (K.sigmoid(x) * 5) - 1

get_custom_objects().update({'custom_activation': Activation(custom_activation)})

data_format = 'channels_first'

spec_input = keras.layers.Input(shape=(1, 3, 256), name='spec')
x = keras.layers.Flatten(data_format)(spec_input)

for layer in range(3):
  x = Dense(512)(x)
  x = Activation('custom_activation', name='cust_sig')(x)

out = Dense(256, activation="sigmoid", name='out')(x)
model = Model(inputs=spec_input, outputs=out)

错误消息如下所示

Traceback (most recent call last):
  File "/home/xyz/anaconda3/envs/ctf/lib/python3.7/site-packages/tensorflow/python/training/tracking/base.py", line 457, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "/home/xyz/anaconda3/envs/ctf/lib/python3.7/site-packages/tensorflow/python/keras/engine/network.py", line 315, in _init_graph_network
    self.inputs, self.outputs)
  File "/home/xyz/anaconda3/envs/ctf/lib/python3.7/site-packages/tensorflow/python/keras/engine/network.py", line 1861, in _map_graph_network
    str(all_names.count(name)) + ' times in the model. '
ValueError: The name "cust_sig" is used 3 times in the model. All layer names should be unique.
nbnkbykc

nbnkbykc1#

下面应该做:

def custom_activation(x):
    return (K.sigmoid(x) * 5) - 1

class CustSig(Layer):
    def __init__(self, my_activation, **kwargs):
        super(CustSig, self).__init__(**kwargs)
        self.supports_masking = True
        self.activation = my_activation

    def call(self, inputs):
        return self.activation(inputs)

    def get_config(self):
        config = {'activation': activations.serialize(self.activation)}
        base_config = super(Activation, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

    def compute_output_shape(self, input_shape):
        return input_shape

说明

从源代码来看,自动命名的工作原理如下:

if not name:
  self._name = backend.unique_object_name(
      generic_utils.to_snake_case(self.__class__.__name__),
      zero_based=zero_based)
else:
  self._name = name

检查Keras图中是否存在与您正在定义的对象同名的现有对象-如果存在,则继续递增1,直到没有匹配的对象。问题是,您不能指定name=,因为这消除了根据上述条件的自动命名。
唯一的解决办法可能是使用所需的名称作为类名定义自己的自定义激活层,如上所述,其表现如下:

ipt = Input(shape=(1, 3, 256), name='spec')
x   = Flatten('channels_last')(ipt)
for _ in range(3):
    x   = Dense(512)(x)
    x   = CustSig(custom_activation)(x)
out = Dense(256, activation='sigmoid', name='out')(x)

model = Model(ipt, out)

print(model.layers[3].name)
print(model.layers[5].name)
print(model.layers[7].name)
cust_sig
cust_sig_1
cust_sig_2
noj0wjuj

noj0wjuj2#

如果你检查Layer类的源代码,你可以找到决定层名称的这些行。

if not name:
    prefix = self.__class__.__name__
    name = _to_snake_case(prefix) + '_' + str(K.get_uid(prefix))
self.name = name

K.get_uid(prefix)将从图中获得唯一的id,这就是为什么你会看到activation_1activation_2
如果你想在自定义的激活函数上有同样的效果,一个更好的方法是定义你自己的类,它继承自Layer

class MyAct(Layer):
    def __init__(self):
        super().__init__()

    def call(self, inputs):
        return (K.sigmoid(inputs) * 5) - 1 

spec_input = Input(shape=(10,10))
x = Flatten()(spec_input)
for layer in range(3):
    x = Dense(512)(x)
    x = MyAct()(x)

model = Model(spec_input, x)
model.summary()

输出

# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_1 (InputLayer)         (None, 10, 10)            0         
# _________________________________________________________________
# flatten_1 (Flatten)          (None, 100)               0         
# _________________________________________________________________
# dense_1 (Dense)              (None, 512)               51712     
# _________________________________________________________________
# my_act_1 (MyAct)             (None, 512)               0         
# _________________________________________________________________
# dense_2 (Dense)              (None, 512)               262656    
# _________________________________________________________________
# my_act_2 (MyAct)             (None, 512)               0         
# _________________________________________________________________
# dense_3 (Dense)              (None, 512)               262656    
# _________________________________________________________________
# my_act_3 (MyAct)             (None, 512)               0         
# =================================================================
# Total params: 577,024
# Trainable params: 577,024
# Non-trainable params: 0
laik7k3q

laik7k3q3#

如果你想多次使用specific_name和数字后缀,使用这个:

tf.get_default_graph().unique_name("specific_name")

tf.compat.v1.get_default_graph().unique_name("specific_name")

在您的案例中:

...
for layer in range(3):
  x = Dense(512)(x)
  x = Activation('custom_activation', name=tf.get_default_graph().unique_name("cust_sig"))(x)
...
ht4b089n

ht4b089n4#

Tensorflow库不提供自定义名称的自动增量。你必须创建一个全新的层类,这是不切实际的。
以下技巧是创建激活层并为其命名的最简单方法。请随意复制粘贴,它不需要更改:

def custom_activation_layer(activation, name=None):
    class_name = tf.keras.layers.Activation.__name__

    # Set the desired name here. We default to the function name.
    if name:
        tf.keras.layers.Activation.__name__ = name
    else:
        tf.keras.layers.Activation.__name__ = f'Activation_{activation.__name__}'
    
    # The layer name is set in the constructor.
    activation_layer = tf.keras.layers.Activation(activation)

    tf.keras.layers.Activation.__name__ = class_name
    return activation_layer

只需将您的激活层替换为以下函数:

# Replace the activation layer...
    layer = tf.keras.layers.Activation(my_custom_activation)

    # ... With the function.
    layer = custom_activation_layer(my_custom_activation)

在绘制模型的图形时,名称会自动递增,以避免图形错误。它显示如下:

model = create_model()
tf.keras.utils.plot_model(model, show_shapes=True)

相关问题