如何自定义 Keras 图层名称并使其自动递增 layer.name
How to customize Keras layer names and also have it automatically increment layer.name
我目前正在尝试使用名称为 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.
下面应该做的:
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
解释:
自source code起,自动命名工作如下:
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,直到 none 匹配。问题是,您不能指定 name=
,因为这会消除上述条件的自动命名。
唯一的解决方法可能是使用所需的名称定义您自己的自定义激活层 class 名称,如上所示,其表现如下:
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
如果你查看Layer
class的源代码,你可以找到这些决定图层名称的行。
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_1
、activation_2
.
的原因
如果你想对你的自定义激活函数有同样的效果,更好的方法是定义你自己的 class 继承自 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
如果您想多次使用带数字后缀的 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)
...
我目前正在尝试使用名称为 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.
下面应该做的:
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
解释:
自source code起,自动命名工作如下:
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,直到 none 匹配。问题是,您不能指定 name=
,因为这会消除上述条件的自动命名。
唯一的解决方法可能是使用所需的名称定义您自己的自定义激活层 class 名称,如上所示,其表现如下:
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
如果你查看Layer
class的源代码,你可以找到这些决定图层名称的行。
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_1
、activation_2
.
如果你想对你的自定义激活函数有同样的效果,更好的方法是定义你自己的 class 继承自 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
如果您想多次使用带数字后缀的 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)
...