Как структурировать граф в тензорной доске, созданной с помощью кода Keras? - PullRequest
0 голосов
/ 17 апреля 2019

Используя функциональный API, можно ли получить график тензорной диаграммы, созданный из кода keras, правильно структурированного?

Можно ли, например, назвать блокинструкций в функциональном подходе как во время создания, так и во время вызова?

Я пытаюсь получить график сети, хорошо структурированный в тензорной доске.

По-видимому, при использовании функционального API, tf.name_scope используется в графе при создании экземпляра модели / слоя, напротив, name kwargsиспользуется при вызове модели / слоя, когда он уже создан.Более того, блоки tf.name_scope не отображаются в части графика, соответствующей вызову (они появляются в части создания экземпляра).

Единственный способ, которым я обнаружил, - одно и то же имя используется как при создании, так и при вызове.правильное структурирование блока слоев на графике означает получение пользовательских слоев из базового класса Layer.Но то, что это действительно больно / излишне, делает код нечитабельным в больших моделях или может быть невозможным для некоторых моделей с несколькими входами / несколькими выходами.

Вот пример с кодом авто-кодера.

Пример с функциональным API

from keras import Model
from keras import backend as K
from keras.layers import Input, Dense, ReLU

layers=[1024,512,128,64]

graph = K.tf.Graph()
with graph.as_default():

    with K.name_scope('ns_encoder'):
        x = Input(shape=(layers[0],))
        z = x
        for hu in layers[1:]:
            with K.name_scope('ns_encblock'):
                z = Dense(hu)(z)
                z = ReLU()(z)
        encoder = Model(inputs=x,outputs=z, name='m_encoder')

    with K.name_scope('ns_decoder'):
        x = Input(shape=(layers[-1],))
        z = x
        for hu in layers[:-1][::-1]:
            with K.name_scope('ns_decblock'):
                z = Dense(hu)(z)
                z = ReLU()(z)
        decoder = Model(inputs=x,outputs=z, name='m_decoder')    

    with K.name_scope('ns_ae'):
        x = Input(shape=(layers[0],))
        z = encoder(x)
        xh = decoder(z)
        ae = Model(inputs=x,outputs=xh, name='m_ae')

writer = K.tf.summary.FileWriter(logdir='logdir', graph=graph)
writer.flush()

График, созданный функциональным API

Этот же слой re_lu_3 правильно отображается внутриблок в ns_encoder, но не в "m_encoder" из "ns_ae".Кроме того, name_scope 'ns_encoder' используется в определении модели кодера, а имя kwarg 'm_encoder' используется в функциональном использовании модели в "ns_ae"

Пример с производным классом

from keras import Model
from keras import backend as K
from keras.layers import Input, Dense, ReLU, Layer

layers=[1024,512,128,64]

class Block(Layer):
    def __init__(self, hu, **kwargs):
        super().__init__(**kwargs)
        self.hu = hu
    def build(self,input_shape):
        self.dense =  Dense(self.hu)
        self.relu = ReLU()
        super().build(input_shape)
    def compute_output_shape(self, input_shape):
        return self.relu.compute_output_shape(
                self.dense.compute_output_shape(input_shape))
    def call(self,x):
        return self.relu(self.dense(x))   

graph = K.tf.Graph()
with graph.as_default():

    with K.name_scope('ns_encoder'):
        x = Input(shape=(layers[0],))
        z = x
        for hu in layers[1:]:
            with K.name_scope('ns_encblock'):
                z = Block(hu)(z)
        encoder = Model(inputs=x,outputs=z, name='m_encoder')

    with K.name_scope('ns_decoder'):
        x = Input(shape=(layers[-1],))
        z = x
        for hu in layers[:-1][::-1]:
            with K.name_scope('ns_decblock'):
                z = Block(hu)(z)
        decoder = Model(inputs=x,outputs=z, name='m_decoder')

    with K.name_scope('ns_ae'):
        x = Input(shape=(layers[0],))
        z = encoder(x)
        xh = decoder(z)
        ae = Model(inputs=x,outputs=xh, name='m_ae')

writer = K.tf.summary.FileWriter(logdir='logdir', graph=graph)
writer.flush()

График, полученный производным класса

На этот раз график правильно структурирован: block_3 появляется как на кодере, так и на полном авто-кодере.Но код действительно переутомлен, и эта парадигма не может применяться постоянно.

...