user16059221
user16059221

Reputation: 11

TimeDistributed layer to apply several convolutional layers error

I have an issue with the tf.keras.layers.TimeDistributed layer (https://www.tensorflow.org/api_docs/python/tf/keras/layers/TimeDistributed).

I am aware that TimeDistributed can be used to apply a single layer (dense, convolutional...) to a set of inputs, obtaining a set of outputs.

Not only that, but until recently I was able to use it to apply an entire "submodel" to all the inputs. That is, a series of layers, not just one. An example of this is explained here by Patrice Ferlet (https://medium.com/smileinnovation/training-neural-network-with-image-sequence-an-example-with-video-as-input-c3407f7a0b0f).

Using that source as example I can define a sequential "submodel" like this:

import keras
from keras.layers import Conv2D, BatchNormalization, \
MaxPool2D, GlobalMaxPool2D

def build_convnet(shape=(112, 112, 3)):
  momentum = .9
  model = keras.Sequential()
  model.add(Conv2D(64, (3,3), input_shape=shape,
      padding='same', activation='relu'))
  model.add(Conv2D(64, (3,3), padding='same', activation='relu'))
  model.add(BatchNormalization(momentum=momentum))

  model.add(MaxPool2D())

  model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
  model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
  model.add(BatchNormalization(momentum=momentum))

  model.add(MaxPool2D())

  model.add(Conv2D(256, (3,3), padding='same', activation='relu'))
  model.add(Conv2D(256, (3,3), padding='same', activation='relu'))
  model.add(BatchNormalization(momentum=momentum))

  model.add(MaxPool2D())

  model.add(Conv2D(512, (3,3), padding='same', activation='relu'))
  model.add(Conv2D(512, (3,3), padding='same', activation='relu'))
  model.add(BatchNormalization(momentum=momentum))

  # flatten...
  model.add(GlobalMaxPool2D())
  return model

And then include this submodel inside a superior model which calls TimeDistributed with the whole initial submodel (convnet).

from keras.layers import TimeDistributed, GRU, Dense, Dropout

def action_model(shape=(5, 112, 112, 3), nbout=3):
  # Create our convnet with (112, 112, 3) input shape
  convnet = build_convnet(shape[1:])

  # then create our final model
  model = keras.Sequential()
  # add the convnet with (5, 112, 112, 3) shape
  model.add(TimeDistributed(convnet, input_shape=shape))
  # here, you can also use GRU or LSTM
  model.add(GRU(64))
  # and finally, we make a decision network
  model.add(Dense(1024, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(512, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(128, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(64, activation='relu'))
  model.add(Dense(nbout, activation='softmax'))
  return model

Now this works well, and I can get the model structure calling

mod=action_model()
mod.summary()

But if instead of this I define the convnet model using as backbone a predefined arquitecture from keras, like VGG16, there seems to be an error. (I also needed to change as well keras.Sequential by tf.keras.models.Sequential)

import tensorflow as tf
from keras.layers import Flatten

def build_convnet():

    prevModel = tf.keras.applications.vgg16.VGG16(
        include_top=False,
        input_shape=(112, 112, 3),
        weights='imagenet'  # ImageNet weights
    )

    model = tf.keras.models.Sequential()

    model.add(prevModel)
    model.add(Flatten())

    return model

def action_model(shape=(5, 112, 112, 3), nbout=3):
  # Create our convnet with (112, 112, 3) input shape
  convnet = build_convnet()

  # then create our final model
  model = tf.keras.models.Sequential()
  # add the convnet with (5, 112, 112, 3) shape
  model.add(TimeDistributed(convnet, input_shape=shape))
  # here, you can also use GRU or LSTM
  model.add(GRU(64))
  # and finally, we make a decision network
  model.add(Dense(1024, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(512, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(128, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(64, activation='relu'))
  model.add(Dense(nbout, activation='softmax'))
  return model

When I run this after defining my VGG16-based architecture

mod=action_model()
mod.summary()

I get the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-106-c8c6108a1d66> in <module>()
----> 1 mod=action_model()
      2 mod.summary()

1 frames
/usr/local/lib/python3.7/dist-packages/keras/layers/wrappers.py in __init__(self, layer, **kwargs)
    121           'Please initialize `TimeDistributed` layer with a '
    122           '`tf.keras.layers.Layer` instance. You passed: {input}'.format(
--> 123               input=layer))
    124     super(TimeDistributed, self).__init__(layer, **kwargs)
    125     self.supports_masking = True

ValueError: Please initialize `TimeDistributed` layer with a `tf.keras.layers.Layer` instance. You passed: <tensorflow.python.keras.engine.sequential.Sequential object at 0x7fbb36266a50>

So now it appears like python is complaining that I am using an input for TimeDistributed that is not a single layer. This doesn't make any sense, since the initial example works well and also involves using several layers with TimeDistributed. Apart from that, the VGG16 model also worked fine some weeks ago.

I am running all of this in Google CoLab.

Could someone help me figure out what is going on here? Is this caused by the new tensorflow 2.5.0 version? Everywhere I look I see people using TimeDistributed to apply a single layer, but applying a whole sequential model worked just fine until now (despite no apparent mention in the documentation).

Thank you!

Upvotes: 1

Views: 1547

Answers (1)

user11530462
user11530462

Reputation:

You get above ValueError is due to mixing tf.keras and keras imports, which is not supported in TF2.5.

Working code as shown below

import tensorflow as tf
#from keras.layers import TimeDistributed, GRU, Dense, Dropout
from tensorflow.keras.layers import Flatten, GRU, Dropout, TimeDistributed, Dense

def build_convnet():

    prevModel = tf.keras.applications.vgg16.VGG16(
        include_top=False,
        input_shape=(112, 112, 3),
        weights='imagenet'  # ImageNet weights
    )

    model = tf.keras.models.Sequential()

    model.add(prevModel)
    model.add(Flatten())

    return model

def action_model(shape=(5, 112, 112, 3), nbout=3):
  # Create our convnet with (112, 112, 3) input shape
  convnet = build_convnet()

  # then create our final model
  model = tf.keras.models.Sequential()
  # add the convnet with (5, 112, 112, 3) shape
  model.add(TimeDistributed(convnet, input_shape=shape))
  # here, you can also use GRU or LSTM
  model.add(GRU(64))
  # and finally, we make a decision network
  model.add(Dense(1024, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(512, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(128, activation='relu'))
  model.add(Dropout(.5))
  model.add(Dense(64, activation='relu'))
  model.add(Dense(nbout, activation='softmax'))
  return model

mod=action_model()
mod.summary()

Output:

Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
time_distributed_1 (TimeDist (None, 5, 4608)           14714688  
_________________________________________________________________
gru_1 (GRU)                  (None, 64)                897408    
_________________________________________________________________
dense (Dense)                (None, 1024)              66560     
_________________________________________________________________
dropout (Dropout)            (None, 1024)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 512)               524800    
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 128)               65664     
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 64)                8256      
_________________________________________________________________
dense_4 (Dense)              (None, 3)                 195       
=================================================================
Total params: 16,277,571
Trainable params: 16,277,571
Non-trainable params: 0
_________________________________________________________________

Upvotes: 1

Related Questions