Как настроить имена слоев Keras, а также автоматически увеличивать layer.name - PullRequest
1 голос
/ 12 октября 2019

В настоящее время я пытаюсь создать несколько слоев с настроенной активацией с именем 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.

Ответы [ 3 ]

2 голосов
/ 12 октября 2019

Если вы проверите исходный код 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) получит уникальный идентификатор из графика, поэтому вы видите activation_1, activation_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
2 голосов
/ 12 октября 2019

Ниже следует выполнить:

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
0 голосов
/ 09 ноября 2019

Если вы хотите использовать 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)
...
...