Attribute error when I am try to modify a loaded LSTM model parameter on Colab

Viewed 174

I am trying to load a LSTM model from Keras on Colab and change its units but I am getting the following error: "AttributeError: Can't set the attribute "units", likely because it conflicts with an existing read-only @property of the object. Please choose a different name". I tried to modify other layers parameters and it worked fine. What can I do to fix it?

The code I am using to load the model and modify it:

model = keras.models.load_model('model.h5')
model.summary() #the model is composed by embedding, dropout, LSTM, dropout then dense layer

model.layers[2].units = 100
new_model = model_from_json(model.to_json())

The code I am using to generate the initial model:

def lstm(vocab_size, tokenizer, X_train, X_validation, y_train, y_validation):

  model = Sequential()

  model.add(Embedding(input_dim=vocab_size,
                      output_dim=embedding_dim,
                      input_length=length_size,
                      name='embedding'))
  
  #droupout layer
  model.add(Dropout(rate = first_dropout_rate))

  #lstm layer
  model.add(LSTM(units = units))

  #dropout layer
  model.add(Dropout(rate = last_dropout_rate))

  #output layer
  model.add(Dense(units=1, activation='sigmoid'))

  model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
  #model_random.summary()

  history_random = model.fit(X_train, 
                             y_train,
                             batch_size=batch_size,
                             epochs=epochs,
                             validation_data=(X_validation, y_validation))
    
  return model
1 Answers

The error message is somewhat misleading. You cannot directly change a parameter such as the number of units in a LSTM, as this changes the size of the layer weights.
You will have to build a new model with the same structure as the first one, with a different number of units for the LSTM layer. Then you will need to copy the model weights, except for the LSTM layer and also the next layer (because the size of the LSTM output is changed).

Below is some code that does it (the values of the parameters are arbitrary):

from tensorflow.keras.layers import Embedding, Dropout, LSTM, Dense 
from tensorflow.keras import Sequential

vocab_size = 41
embedding_dim = 100
length_size = 50

first_dropout_rate=0.2
last_dropout_rate = 0.2
units=2

def create_lstm_model(vocab_size, embedding_dim, length_size, first_dropout_rate, last_dropout_rate, units):
    model = Sequential()
    model.add(Embedding(input_dim=vocab_size,
                    output_dim=embedding_dim,
                    input_length=length_size,
                    name='embedding'))
    #droupout layer
    model.add(Dropout(rate=first_dropout_rate))
    #lstm layer
    model.add(LSTM(units=units, name='mylstm'))  # give a name to the layer

    #dropout layer
    model.add(Dropout(rate=last_dropout_rate))

    #output layer
    model.add(Dense(units=1, activation='sigmoid', name='mydense'))  # give a name to the layer
    return model

# create and compile model with 2 LSTM units
model = create_lstm_model(vocab_size, embedding_dim, length_size, first_dropout_rate, last_dropout_rate, units=2)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()

# do model.fit

# create a new model with 3 LSTM units
new_model = create_lstm_model(vocab_size, embedding_dim, length_size, first_dropout_rate, last_dropout_rate, units=3)

# copy weights
for count, (layer, new_layer) in enumerate(zip(model.layers, new_model.layers)): 
    if layer.name in ['mylstm', 'mydense']:  # the weights of these two layers have different sizes in the two models 
        continue
    print(new_layer)
    new_layer.set_weights(layer.get_weights())

new_model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
new_model.summary()
Related