Related
I try to reuse a pre-trained model and add some new convolution layers. The pre-trained classifier is also be replaced.
1. The pre-trained model looks like this:
input_shape = X_train.shape[1:] #(224, 224, 3)
num_classes = 500
model = Sequential()
model.add(Conv2D(32, kernel_size = (3, 3), input_shape=input_shape, activation='relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(Conv2D(32, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(64, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(Conv2D(64, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(128, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(Conv2D(128, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(256, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(Conv2D(256, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(Conv2D(256, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
2. Try to perform transfer learning as following:
# mark loaded layers as not trainable
for layer in base_model.layers:
layer.trainable = False
x = base_model.layers[-3].output
# A`enter code here`dd new layers :
[line 47] x = tf.keras.layers.Conv2D(256, kernel_size = (3, 3), activation = 'relu', padding = 'same',kernel_initializer='glorot_normal')(x)
x = tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2))(x)s
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.xPool2D(pool_size=(2, 2), strides=(2, 2))(x)
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same')(x)
x = tf.keras.layers.xPool2D(pool_size=(2, 2), strides=(2, 2))(x)
x = Flatten()(x)
x = Dense(1024, activation='relu')(x)
output = Dense(class_number, activation='softmax')(x)
# define new model
new_model = Model(inputs=base_model.inputs, outputs=output)
new_model.summary()
Encounter this error:
ValueError: Input 0 of layer "conv2d_11" is incompatible with the layer: expected min_ndim=4, found ndim=2. Full shape received: (None, 256) [at line 47]
Is it possible/how to add new convolution layers to a pre-trained model for transfer learning?
update:
inspired from(Remove top layer from pre-trained model, transfer learning, tensorflow (load_model))
Following codes work for my purpose.
inputshape = (224, 224, 3)
# num_classes = y_train.shape[1]
num_classes = 2000
# Load Model
path = r'D:\00_twm_cnn_model\02_prt\02_outputs'
os.chdir(path)
ModelName = r'Model_CNN_VGG-16_chi_prt_100_2022-06-15_1.h5'
base_model = load_model(ModelName)
base_model.summary()
model = tf.keras.Sequential()
for layer in base_model.layers[0:-6]:
model.add(layer)
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_10'))
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_11'))
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_12'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2),name='max_pooling2d_4'))
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_13'))
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_14'))
model.add(Conv2D(512, kernel_size = (3, 3), activation = 'relu', padding = 'same',input_shape=input_shape,name='conv2d_15'))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2),name='max_pooling2d_5'))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.1))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.1))
#model.add(BatchNormalization())
model.add(Dense(num_classes, activation='softmax'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
I am working on a hand character recognition model. I created a CNN+BiLSTM+CTC Loss model. But getting error when I run model.fit(). Please help me fix this error.
My Model
# input with shape of height=32 and width=128
inputs = Input(shape=(32,128,1))
# convolution layer with kernel size (3,3)
conv_1 = Conv2D(64, (3,3), activation = 'relu', padding='same')(inputs)
# poolig layer with kernel size (2,2)
pool_1 = MaxPooling2D(pool_size=(2, 2), strides=2)(conv_1)
conv_2 = Conv2D(128, (3,3), activation = 'relu', padding='same')(pool_1)
pool_2 = MaxPooling2D(pool_size=(2, 2), strides=2)(conv_2)
conv_3 = Conv2D(256, (3,3), activation = 'relu', padding='same')(pool_2)
conv_4 = Conv2D(256, (3,3), activation = 'relu', padding='same')(conv_3)
# poolig layer with kernel size (2,1)
pool_4 = MaxPooling2D(pool_size=(2, 1))(conv_4)
conv_5 = Conv2D(512, (3,3), activation = 'relu', padding='same')(pool_4)
# Batch normalization layer
batch_norm_5 = BatchNormalization()(conv_5)
conv_6 = Conv2D(512, (3,3), activation = 'relu', padding='same')(batch_norm_5)
batch_norm_6 = BatchNormalization()(conv_6)
pool_6 = MaxPooling2D(pool_size=(2, 1))(batch_norm_6)
conv_7 = Conv2D(512, (2,2), activation = 'relu')(pool_6)
squeezed = Lambda(lambda x: K.squeeze(x, 1))(conv_7)
# bidirectional LSTM layers with units=128
blstm_1 = Bidirectional(LSTM(128, return_sequences=True, dropout = 0.2))(squeezed)
blstm_2 = Bidirectional(LSTM(128, return_sequences=True, dropout = 0.2))(blstm_1)
outputs = Dense(len(char_dict)+1, activation = 'softmax')(blstm_2)
act_model = Model(inputs, outputs)
Define a CTC loss model that takes the outputs of previous model as inputs
labels = Input(name='the_labels', shape=[max_length], dtype='float32')
input_length = Input(name='input_length', shape=[1], dtype='int64')
label_length = Input(name='label_length', shape=[1], dtype='int64')
def ctc_lambda_func(args):
y_pred, labels, input_length, label_length = args
return K.ctc_batch_cost(labels, y_pred, input_length, label_length)
loss_out = Lambda(ctc_lambda_func, output_shape=(1,), name='ctc')([outputs, labels, input_length,
label_length])
model = Model(inputs=[inputs, labels, input_length, label_length], outputs=loss_out)
model.compile(loss={'ctc': lambda y_true, y_pred: y_pred}, optimizer = 'adam')
model.fit(x=[input_array,
output_array,
train_input_length,
train_label_length],
y=np.zeros(input_array.shape[0]),
batch_size=256,
epochs = 100,
validation_data = ([test_input_array, test_output_array, valid_input_length,
valid_label_length], [np.zeros(test_input_array.shape[0])]),
verbose = 1,
callbacks = callbacks_list)
The error I am getting is
ValueError: Shape (None, 17) must have rank 1
I want to visualize the layers in capsule networks. For that I need shape of intermediate layers. The code is as follows:
from keras.models import Model
model = Sequential()
conv1 = model.add(Conv2D(256, (9, 9), padding='valid', strides = 1, input_shape = (28, 28, 1), activation = 'relu', name = 'conv1'))
model.add(Conv2D(256, (9,9), padding='valid', strides = 2, name = 'primarycaps_conv2d'))
model.add(keras.layers.core.Reshape([-1,8]))
model.add(keras.layers.core.Lambda(squash, name = 'hello'))
layer_name = 'conv1'
intermediate_layer_model = Model(inputs=model.input,
outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(data)
Throws the following error:
NameError: name 'data' is not defined
How to overcome this?
Referring this, I got the solution as follows:
model = Sequential()
conv1 = model.add(Conv2D(256, (9, 9), padding='valid', strides = 1, input_shape = (28, 28, 1), activation = 'relu', name = 'conv1'))
model.add(Conv2D(256, (9,9), padding='valid', strides = 2, name = 'primarycaps_conv2d'))
model.add(keras.layers.core.Reshape([-1,8]))
model.add(keras.layers.core.Lambda(squash, name = 'hello'))
idx = 3 # index of desired layer
input_shape = model.layers[idx].get_output_shape_at(0)
print(input_shape)
get the output shape as follows:
(None, 1152, 8).
The problem of getting specific layer's output is solved.
I am trying to create a UNET using VGG16 as first layers.
def BuildUNet2():
keras.backend.set_learning_phase(1)
inputs = keras.layers.Input(shape=(PATCH_SIZE, PATCH_SIZE, 3), name="inputs")
vggModel=keras.applications.VGG16(include_top=False, input_tensor=inputs)
layers = dict([(layer.name, layer) for layer in vggModel.layers])
print("Layers", len(layers), layers)
block1_conv2 = layers["block1_conv2"].output
block2_conv2 = layers["block2_conv2"].output
block3_conv3 = layers["block3_conv3"].output
block4_conv3 = layers["block4_conv3"].output
vggTop = layers["block5_conv3"].output
up6=keras.layers.concatenate([keras.layers.Conv2DTranspose(256, (2,2), strides=(2,2), padding="same")(vggTop), block4_conv3], axis=3)
conv61=keras.layers.Conv2D(256, 3, activation="relu", padding="same", kernel_initializer="he_normal")(up6)
conv62=keras.layers.Conv2D(256, 3, activation="relu", padding="same", kernel_initializer="he_normal")(conv61)
up7 = keras.layers.concatenate([keras.layers.Conv2DTranspose(128, (2, 2), strides=(2, 2), padding="same")(conv62), block3_conv3], axis=3)
conv71=keras.layers.Conv2D(128, 3, activation="relu", padding="same", kernel_initializer="he_normal")(up7)
conv72=keras.layers.Conv2D(128, 3, activation="relu", padding="same", kernel_initializer="he_normal")(conv71)
up8 = keras.layers.concatenate([keras.layers.Conv2DTranspose(64, (2, 2), strides=(2, 2), padding="same")(conv72), block2_conv2], axis=3)
conv81=keras.layers.Conv2D(64, 3, activation="relu", padding="same", kernel_initializer="he_normal")(up8)
conv82=keras.layers.Conv2D(64, 3, activation="relu", padding="same", kernel_initializer="he_normal")(conv81)
up9 = keras.layers.concatenate([keras.layers.Conv2DTranspose(32, (2, 2), strides=(2, 2), padding="same")(conv82), block1_conv2], axis=3)
conv91=keras.layers.Conv2D(32, 3, activation="relu", padding="same", kernel_initializer="he_normal")(up9)
conv92=keras.layers.Conv2D(32, 3, activation="relu", padding="same", kernel_initializer="he_normal")(conv91)
conv93=keras.layers.Conv2D(1, (1, 1), activation="sigmoid")(conv92)
model = keras.models.Model(input=[inputs], output=[conv93])
for layer in model.layers[:19]:
layer.trainable = False
model.compile(optimizer=keras.optimizers.Adam(lr=1e-5), loss=metric.dice_coef_loss,
metrics=[metric.dice_coef, "accuracy"])
model.summary()
return model
I am training with:
with h5py.File(parms.training, "r") as trainingsFile:
wrk=trainingsFile["work"].value
np.random.seed(42)
np.random.shuffle(wrk)
limit=int(wrk.shape[0]*0.8)
trainData=wrk[:limit]
valData=wrk[limit:]
trainGen=DataGenerator(trainData, parms.batchSize)
valGen=DataGenerator(valData, parms.batchSize)
bestCheckpoint = keras.callbacks.ModelCheckpoint("best.h5",
monitor="val_loss",
save_best_only=True,
save_weights_only=False)
regCheckpoint = keras.callbacks.ModelCheckpoint("checkpoint-{epoch:04d}.h5", period=10)
csvLog = keras.callbacks.CSVLogger("log.csv", append=True)
runName = datetime.datetime.now().isoformat("#")[:19].replace(":", "-")
tensorBoard = keras.callbacks.TensorBoard(log_dir="./logs/%s/" % runName)
lrPlateau = keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.2, patience=10, cooldown=5)
model.fit_generator(trainGen,
epochs=parms.epochs,
steps_per_epoch=trainGen.__len__(),
validation_data=valGen,
validation_steps=valGen.__len__(),
callbacks=[bestCheckpoint, regCheckpoint, csvLog, tensorBoard, lrPlateau],
use_multiprocessing=False,
)
The DataGenerator is defined as:
class DataGenerator(keras.utils.Sequence):
def __init__(self, data, batchSize):
self.data=data
self.batchSize=batchSize
def __len__(self):
return int((self.data.shape[0]+self.batchSize-1)/(self.batchSize))
def __getitem__(self, item):
X=np.zeros((self.batchSize, self.data.shape[1], self.data.shape[2], 3), dtype=np.float32)
Y=np.zeros((self.batchSize, self.data.shape[1], self.data.shape[2]), dtype=np.float32)
j=0
wrk=np.zeros((self.data.shape[1], self.data.shape[2], self.data.shape[3]), dtype=np.float32)
for i in range(item*self.batchSize, min((item+1)*self.batchSize,self.data.shape[0])):
wrk=self.data[i, :, :, :]
if random.random() < 0.5:
wrk=wrk[:, ::-1, :]
if random.random() < 0.5:
wrk = wrk[::-1, :, :]
direction = int(random.random() * 4) * 90
if direction:
wrk = imutils.rotate(wrk, direction)
X[j, :, :, :]=wrk[:, :, 0: 3]
Y[j, :, :]=wrk[:, :, 3]
j+=1
X=X.resize((j, X.shape[1], X.shape[2], X.shape[3]))
Y=Y.resize((j, Y.shape[1], Y.shape[2]))
return X, Y
Trying to train the model results in
tensorflow.python.framework.errors_impl.InvalidArgumentError: You must feed a value for placeholder tensor 'conv2d_9_sample_weights' with dtype float and shape [?]
Even explicitly returning a sample_weight (an addtional np.ones((j), dtype=np.float32) from the DataGenerator does not solve the problem.
What's wrong?
How do I correct it?
The problem was with DataGenerator.getitem():
resize does not return a new numpy array. It changes the original array and returns nothing. Therefore the getitem method returned None, None.
The keras error messages is misleading.
I am a newbie in machine learning.
Actually, I used my unet code for image segmentation using one input image slice (192x912) and one output mask image (192x192)
My Unet code is contained several CNN layer and I usually used one input image (192x912) and one its corresponding mask binary image for training.
Code related with above explanation is as below.
def get_unet():
inputs = Input((img_rows, img_cols, 1))
conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
drop1 = Dropout(0.2)(pool1)
conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(drop1)
conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
drop2 = Dropout(0.2)(pool2)
'''''''
return model
model.fit(imgs_train, imgs_mask_train, batch_size=32, epochs=100, verbose=2, shuffle=True, validation_split=0.1, callbacks=[model_checkpoint])
it works well. But, now, I would like to use multi input image when I train my network. So, I add another train data and edit my code like below.
def get_unet():
inputs = Input((img_rows, img_cols, 1))
conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
drop1 = Dropout(0.2)(pool1)
conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(drop1)
conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
drop2 = Dropout(0.2)(pool2)
'''''''
return model
model.fit([imgs_train, imgs_other_train], imgs_mask_train, batch_size=32, epochs=100, verbose=2, shuffle=True, validation_split=0.1, callbacks=[model_checkpoint])
but when I run the train code, I got error message as below.
"ValueError: Error when checking model input: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 1 array(s), but instead got the following list of 2 arrays: "
I think my U net needs to be changed for multi input, but I don't know where I have to change.
Please help and give me any comments.
Thanks.
This is actually rather easy. All you need to do would adjust your input size I believe.
inputs = Input((img_rows, img_cols, size)) would have worked. Or you could have used concat like:
inputs = []
for _ in range(num_inputs):
inputs.append(Input((self.input_height, self.input_width, self.input_features)))
x = concatenate(inputs)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
You can check something similar I implemented here