model.summary() can't print output shape while using subclass model

前端 未结 4 892
情话喂你
情话喂你 2021-01-01 20:48

This is the two methods for creating a keras model, but the output shapes of the summary results of the two methods are different. Obviously, the former prints

相关标签:
4条回答
  • 2021-01-01 21:31

    I have used this method to solve this problem, I don't know if there is an easier way.

    class subclass(Model):
        def __init__(self):
            ...
        def call(self, x):
            ...
    
        def model(self):
            x = Input(shape=(24, 24, 3))
            return Model(inputs=[x], outputs=self.call(x))
    
    
    
    if __name__ == '__main__':
        sub = subclass()
        sub.model().summary()
    
    0 讨论(0)
  • 2021-01-01 21:34

    I guess that key point is the _init_graph_network method in the class Network, which is the parent class of Model. _init_graph_network will be called if you specify the inputs and outputs arguments when calling __init__ method.

    So there will be two possible methods:

    1. Manually calling the _init_graph_network method to build the graph of the model.
    2. Reinitialize with the input layer and output.

    and both methods need the input layer and output (required from self.call).

    Now calling summary will give the exact output shape. However it would show the Input layer, which isn't a part of subclassing Model.

    from tensorflow import keras
    from tensorflow.keras import layers as klayers
    
    class MLP(keras.Model):
        def __init__(self, input_shape=(32), **kwargs):
            super(MLP, self).__init__(**kwargs)
            # Add input layer
            self.input_layer = klayers.Input(input_shape)
    
            self.dense_1 = klayers.Dense(64, activation='relu')
            self.dense_2 = klayers.Dense(10)
    
            # Get output layer with `call` method
            self.out = self.call(self.input_layer)
    
            # Reinitial
            super(MLP, self).__init__(
                inputs=self.input_layer,
                outputs=self.out,
                **kwargs)
    
        def build(self):
            # Initialize the graph
            self._is_graph_network = True
            self._init_graph_network(
                inputs=self.input_layer,
                outputs=self.out
            )
    
        def call(self, inputs):
            x = self.dense_1(inputs)
            return self.dense_2(x)
    
    if __name__ == '__main__':
        mlp = MLP(16)
        mlp.summary()
    

    The output will be:

    Model: "mlp_1"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    input_1 (InputLayer)         [(None, 16)]              0         
    _________________________________________________________________
    dense (Dense)                (None, 64)                1088      
    _________________________________________________________________
    dense_1 (Dense)              (None, 10)                650       
    =================================================================
    Total params: 1,738
    Trainable params: 1,738
    Non-trainable params: 0
    _________________________________________________________________
    
    0 讨论(0)
  • 2021-01-01 21:34

    The way I solve the problem is very similar to what Elazar mensioned. Override the function summary() in the class subclass. Then you can directly call summary() while using model subclassing:

    class subclass(Model):
        def __init__(self):
            ...
        def call(self, x):
            ...
    
        def summary(self):
            x = Input(shape=(24, 24, 3))
            model = Model(inputs=[x], outputs=self.call(x))
            return model.summary()
    
    if __name__ == '__main__':
        sub = subclass()
        sub.summary()
    
    0 讨论(0)
  • 2021-01-01 21:34

    had the same problem - fix it by 3 steps:

    1. add input_shape in the _ init _
    2. add a input_layer
    3. add out layer
    class MyModel(tf.keras.Model):
        
        def __init__(self,input_shape=(32,32,1), **kwargs):
            super(MyModel, self).__init__(**kwargs) 
            self.input_layer = tf.keras.layers.Input(input_shape)
            self.dense10 = tf.keras.layers.Dense(10, activation=tf.keras.activations.softmax)    
            self.dense20 = tf.keras.layers.Dense(20, activation=tf.keras.activations.softmax)
            self.out = self.call(self.input_layer)    
        
        def call(self, inputs):
            x =  self.dense10(inputs)
            y_pred =  self.dense20(x)
         
            return y_pred
    
    model = MyModel()
    model(x_test[:99])
    print('x_test[:99].shape:',x_test[:10].shape)
    model.summary()
    

    output:

    x_test[:99].shape: (99, 32, 32, 1)
    Model: "my_model_32"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense_79 (Dense)             (None, 32, 32, 10)        20        
    _________________________________________________________________
    dense_80 (Dense)             (None, 32, 32, 20)        220       
    =================================================================
    Total params: 240
    Trainable params: 240
    Non-trainable params: 0
    
    
    0 讨论(0)
提交回复
热议问题