Remove n last layers from ResNet50 network - python

I have the following network that will be used for binary classification on medical image data. However, I would like to use only the 80 first layers of this model as I currently don't have a lot of data and my model is overfitting. I would like to delete all layers from block 4 or 5, and only keep blocks 1, 2 and 3. I have tried using layer.pop() but it does not work.
from keras.applications.resnet50 import ResNet50
resnet = ResNet50(include_top=False, weights='imagenet', input_shape=(im_size,im_size,3))
headModel = AveragePooling2D(pool_size=(7, 7))(resnet.output)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(256, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(1, activation="sigmoid")(headModel)

Solution 1 : You could use model.summary() to quickly check the names of the layers (80th).
layer_name = 'name_of_the_80th_layer'
intermediate_model = Model(inputs=resnet.input,
outputs=resnet.get_layer(layer_name).output)
final_model = AveragePooling2D(pool_size=(7, 7))(intermediate_model.output)
final_model = Flatten(name="flatten")(final_model)
final_model = Dense(256, activation="relu")(final_model)
final_model = Dropout(0.5)(final_model)
final_model = Dense(1, activation="sigmoid")(final_model)
Solution 2:
You could directly get it like:
intermediate_model = Model(inputs=resnet.input,
outputs=resnet.layers[80].output)
...

Related

Keras model convert into pytorch

def network():
inputs = Input(name='inputs', shape=[51, ])
layer1 = Dense(2048)(inputs)
layer1 = BatchNormalization(name='BC11')(layer1)
layer1 = Activation('relu', name='Act11')(layer1)
layer2 = Dense(1024, name='FC1')(layer1)
layer2 = BatchNormalization(name='BC1')(layer2)
layer2 = Activation('relu', name='Act1')(layer2)
layer_shortcut1 = Dense(1024, activation='relu')(inputs)
layer_shortcut1 = BatchNormalization(name='BCshortcut1')(layer_shortcut1)
layer2 = Add()([layer2, layer_shortcut1])
merge1 = concatenate([layer1, layer2])
layer3 = Dense(512, name='FC3')(merge1)
layer3 = BatchNormalization(name='BC3')(layer3)
layer3 = Activation('relu', name='Act3')(layer3)
layer4 = Dense(256, name='FC5')(layer3)
layer4 = BatchNormalization(name='BC5')(layer4)
layer4= Activation('relu', name='Act5')(layer4)
layer_shortcut2 = Dense(256, activation='relu')(layer2)
layer_shortcut2 = BatchNormalization(name='BCshortcut2')(layer_shortcut2)
layer4 = Add()([layer4, layer_shortcut2])
merge2 = concatenate([layer3, layer4])
layer5 = Dense(128, name='FC7')(merge2)
layer5 = BatchNormalization(name='BC7')(layer5)
layer5 = Activation('relu', name='Act7')(layer5)
layer6 = Dense(64, name='FC8')(layer5)
layer6 = BatchNormalization(name='BC8')(layer6)
layer6 = Activation('relu', name='Act8')(layer6)
layer_shortcut3 = Dense(64, activation='relu')(layer4)
layer_shortcut3 = BatchNormalization(name='BCshortcut')(layer_shortcut3)
layer6 = Add()([layer6, layer_shortcut3])
merge3 = concatenate([layer5, layer6])
layer7 = Dense(32, name='FC9')(merge3)
layer7 = BatchNormalization(name='BC9')(layer7)
layer7 = Activation('relu', name='Act9')(layer7)
layer8 = Dense(16, name='FC0')(layer7)
layer8 = BatchNormalization(name='BC0')(layer8)
layer8 = Activation('relu', name='Act0')(layer8)
out0 = Dense(12, activation='sigmoid', name='Out0')(merge2)
out1 = Dense(12, activation='sigmoid', name='Out1')(merge3)
out2 = Dense(12, activation='sigmoid', name='Out2')(layer8)
model = Model(inputs=inputs, outputs=[out0,out1,out2])
return model
I am new in pytorch. Could someone help me to convert this into pytorch? I have seen How can I convert this keras cnn model to pytorch version but meet the dimension issues. Many thanks!
From this stack overflow answer. Forward your upvotes to the OG.
You can save keras weight and reload them in pytorch. the steps are
Step 0: Train a Model in Keras. ...
Step 1: Recreate & Initialize Your Model Architecture in PyTorch. ...
Step 2: Import Your Keras Model and Copy the Weights. ...
Step 3: Load Those Weights onto Your PyTorch Model. ...
Step 4: Test and Save Your Pytorch Model.
You Can follow example here https://gereshes.com/2019/06/24/how-to-transfer-a-simple-keras-model-to-pytorch-the-hard-way/

Tensorflow 2.0 Model subclassing

I made this function that incorporates a resnet into a model. It works well, and I can save it.
My problem is that I can't load it because it needs a call function. I am not exactly sure of how to turn this into a class. The attempt is at the bottom. some pointers would be helpful.
def build_network():
inp = Input(shape=(256,256,3))
resnet = tf.keras.applications.ResNet152V2(
include_top=False, weights='imagenet', input_tensor=None,
input_shape=(256,256,3), pooling=None, classes=1000
)
# classifier_activation='softmax'
x = resnet(inp)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(9, activation='softmax')(x)
model = tf.keras.Model(inputs=inp,outputs = x)
opt = tf.keras.optimizers.SGD(momentum=0.9)
# optimizer = 'adam',
model.compile(loss='categorical_crossentropy',
optimizer = opt,
metrics=['accuracy'])
model.summary()
return model
class Resnet(tf.keras.Model):
def __init__(self, num_classes=9):
super(Resnet, self).__init__()
self.block_1 = tf.keras.applications.ResNet152V2(
include_top=False, weights='imagenet', input_tensor=None,
input_shape=(256,256,3), pooling=None, classes=1000)
self.global_pool = layers.GlobalAveragePooling2D()
self.dropout = Dropout(0.3)
self.classifier = Dense(num_classes, activation = 'softmax')
def call(self, inputs):
x = self.block_1(inputs)
x = self.global_pool(x)
x = self.dropout(x)
x = self.classifier(x)
return tf.keras.Model(inputs = inputs, outputs = x)
Using the subclassing API will actually make your model unserializable (see the "Limitations section in the "What are Symbolic and Imperative APIs in TensorFlow 2.0? " blogpost):
Imperative models are also more difficult to inspect, copy, or clone.
For example, model.save(), model.get_config(), and clone_model do not work for subclassed models. Likewise, model.summary() only gives you a list of layers (and doesn’t provide information on how they’re connected, since that’s not accessible).
Edit: From Tensorflow 2.4, it is possible to pass a save_traces argument to model.save to serialize models built using the subclassing API. See https://www.tensorflow.org/guide/keras/save_and_serialize#how_savedmodel_handles_custom_objects.
Here's a simple example of how you can do this:
import tensorflow as tf
from tensorflow.keras.layers import (Dense, Dropout, GlobalAveragePooling2D,
Input)
def build_network():
inp = Input(shape=(256, 256, 3))
resnet = tf.keras.applications.ResNet152V2(include_top=False,
weights="imagenet",
input_tensor=None,
input_shape=(256, 256, 3),
pooling=None,
classes=1000)
# classifier_activation="softmax"
x = resnet(inp)
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(9, activation="softmax")(x)
model = tf.keras.Model(inputs=inp, outputs=x)
# optimizer = "adam",
opt = tf.keras.optimizers.SGD(momentum=0.9)
model.compile(loss="categorical_crossentropy",
optimizer=opt,
metrics=["accuracy"])
model.summary()
return model
if __name__ == "__main__":
model = build_network()
model.summary()
# Save
model.save("my_model.h5")
# Load
loaded_model = tf.keras.models.load_model("my_model.h5")
loaded_model.summary()
To load your saved model from your build_network function use tf.keras.models.load_model.

Keras ValueError : the Dens' input dimension should be defined

I'm trying to use VGG16 with some modification on it. I followed this blog post from keras.io
Here the code I'm using to create the model:
def create_model():
vgg16_model = vgg16.VGG16(weights='imagenet', include_top=False)
print('[INFO] Model loaded.')
x = vgg16_model.output
x = Flatten()(x)
x = Dense(256, activation="relu")(x)
x = Dropout(0.5)(x)
x = Dense(1, activation='linear')(x)
model = Model(inputs=vgg16_model.inputs, outputs=x)
return model
Calling the model = create_model() gives an error:
ValueError: The last dimension of the inputs to Dense should be defined. Found None.
What could be the problem?
try to pass an input_shape when you use the vgg16.VGG16
def create_model():
vgg16_model = vgg16.VGG16(input_shape=(224,224,3), weights='imagenet', include_top=False)
print('[INFO] Model loaded.')
x = vgg16_model.output
x = Flatten()(x)
x = Dense(256, activation="relu")(x)
x = Dropout(0.5)(x)
x = Dense(1, activation='linear')(x)
model = Model(inputs=vgg16_model.inputs, outputs=x)
return model

Graph disconnected: cannot obtain value for tensor "x" Tensor at layer "x" . The following previous layers were accessed without issue: []

I am building a small network using some custom network boxes for each use case, It looks like this :
def top_block(dropout = None, training = None):
# scaled input
input_1 = tf.keras.Input(shape=(1,15), dtype='float32')
input_2 = tf.keras.Input(shape=(1,15), dtype='float32')
if dropout:
layer_one = tf.keras.layers.Dropout(rate = dropout)(input_1, training = training)
layer_two = tf.keras.layers.Dropout(rate = dropout)(input_2, training = training)
return [layer_one,layer_two]
return [input_1,input_2]
def bottom_layer(input_layers):
data = tf.reduce_mean(input_layers,0)
cls_layer = tf.keras.layers.Dense(1,
kernel_initializer = keras.initializers.glorot_uniform(seed=200),
activation = 'sigmoid')(data)
model = tf.keras.Model([input_layers[0], input_layers[1]], cls_layer , name = 'model_1')
model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics=['accuracy'])
model.summary()
return model
If I am trying to access this network without dropout, it's working fine :
top_ = top_block()
model = bottom_layer(top_ )
But if I am accessing with dropout, it's giving error:
top_ = top_block(dropout = 0.2, training = True)
model = bottom_layer(top_ )
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_72:0", shape=(None, 1, 15), dtype=float32) at layer "input_72". The following previous layers were accessed without issue: []
How to access the model with dropout layer?
How to disable training = False during evaluate? Do I need to load full model and old model weights?
Thank You!
I just realized my input is coming from intermediate layer (dropout layer), It should come directly from Input layer :
def top_block():
# scaled input
input_1 = tf.keras.Input(shape=(1,15), dtype='float32')
input_2 = tf.keras.Input(shape=(1,15), dtype='float32')
return [input_1, input_2]
def apply_dropout(layers_data, dropout_val, training):
layer_one = tf.keras.layers.Dropout(rate = dropout_val)(layers_data[0], training = training)
layer_two = tf.keras.layers.Dropout(rate = dropout_val)(layers_data[1], training = training)
return [layer_one, layer_two]
def bottom_layer(input_layers, data):
data = tf.reduce_mean(data, 0)
cls_layer = tf.keras.layers.Dense(1,
kernel_initializer = keras.initializers.glorot_uniform(seed=200),
activation = 'sigmoid')(data)
model = tf.keras.Model(input_layers, cls_layer , name = 'model_1')
model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics=['accuracy'])
model.summary()
return model
It's working now
top_ = top_block()
dropout_ = apply_dropout(top_, 0.2, True)
model = bottom_layer(top_ , dropout_)

ValueError: Error when checking target: expected avg_pool to have 4 dimensions, but got array with shape (100, 2)

I try to run this code (binary classification) but still stuck with this error : ValueError: Error when checking target: expected avg_pool to have 4 dimensions, but got array with shape (100, 2)
NUM_CLASSES = 2
CHANNELS = 3
IMAGE_RESIZE = 224
RESNET50_POOLING_AVERAGE = 'avg'
DENSE_LAYER_ACTIVATION = 'softmax'
OBJECTIVE_FUNCTION = 'binary_crossentropy'
NUM_EPOCHS = 10
EARLY_STOP_PATIENCE = 3
STEPS_PER_EPOCH_VALIDATION = 10
BATCH_SIZE_TRAINING = 100
BATCH_SIZE_VALIDATION = 100
resnet_weights_path = '../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'
train_data_dir = "C:\\Users\\Desktop\\RESNET"
model = ResNet50(include_top=True, weights='imagenet')
x = model.get_layer('avg_pool').output
predictions = Dense(1, activation='sigmoid')(x)
model = Model(input = model.input, output = predictions)
print(model.summary())
model.layers.pop()
model = Model(input=model.input,output=model.layers[-1].output)
sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=SGD(lr=0.01, momentum=0.9), metrics= ['binary_accuracy'])
data_dir = "C:\\Users\\Desktop\\RESNET"
batch_size = 32
from keras.applications.resnet50 import preprocess_input
from keras.preprocessing.image import ImageDataGenerator
image_size = IMAGE_RESIZE
data_generator = ImageDataGenerator(preprocessing_function=preprocess_input)
def append_ext(fn):
return fn+".jpg"
dir_path = os.path.dirname(os.path.realpath(__file__))
train_dir_path = dir_path + '\data'
onlyfiles = [f for f in listdir(dir_path) if isfile(join(dir_path, f))]
NUM_CLASSES = 2
data_labels = [0, 1]
t = []
maxi = 25145
LieOffset = 15799
i = 0
while i < maxi: # t = tuple
if i <= LieOffset:
t.append(label['Lie'])
else:
t.append(label['Truth'])
i = i+1
train_datagenerator = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
validation_split=0.2)
train_generator = train_datagenerator.flow_from_directory(
train_data_dir,
target_size=(image_size, image_size),
batch_size=BATCH_SIZE_TRAINING,
class_mode='categorical', shuffle=False, subset='training') # set as training data
validation_generator = train_datagenerator.flow_from_directory(
train_data_dir, # same directory as training data
target_size=(image_size, image_size),
batch_size=BATCH_SIZE_TRAINING,
class_mode='categorical', shuffle=False, subset='validation')
(BATCH_SIZE_TRAINING, len(train_generator), BATCH_SIZE_VALIDATION, len(validation_generator))
from sklearn.grid_search import ParameterGrid
param_grid = {'epochs': [5, 10, 15], 'steps_per_epoch' : [10, 20, 50]}
grid = ParameterGrid(param_grid)
# Accumulate history of all permutations (may be for viewing trend) and keep watching for lowest val_loss as final model
for params in grid:
fit_history = model.fit_generator(
train_generator,
steps_per_epoch=STEPS_PER_EPOCH_TRAINING,
epochs = NUM_EPOCHS,
validation_data=validation_generator,
validation_steps=STEPS_PER_EPOCH_VALIDATION,
callbacks=[cb_checkpointer, cb_early_stopper]
)
model.load_weights("../working/best.hdf5")
Remove these lines and it'll work,
model.layers.pop()
model = Model(input=model.input,output=model.layers[-1].output)
The former is removing the last(Dense) layer, and the letter means create a model without the last(Flatten, as Dense is already popped) layer.
It doesn't make sense as your target data is (100, 2). Why do you put them there in the first place?
Also I think this line
predictions = Dense(1, activation='sigmoid')(x)
Will error, as your target data is 2 channel, if it does error then change this to
predictions = Dense(2, activation='sigmoid')(x)
Update
The output of avg_pool is 4 dimention, (batch_size, height, width, channel). You need to do the Flatten first or use GlobalAveragePooling2D instead of AveragePooling2D.
Like
x = model.get_layer('avg_pool').output
x = keras.layers.Flatten()(x)
predictions = Dense(1, activation='sigmoid')(x)
Or
model = ResNet50(include_top=False, pooling='avg', weights='imagenet') # `pooling='avg'` makes the `ResNet50` include a `GlobalAveragePoiling` layer and `include_top=False` means that you don't include the imagenet's output layer
x = model.output # as I use `include_top=False`, you don't need to care the layer name, just use the model's output right away
predictions = Dense(1, activation='sigmoid')(x)
Also just as #bit01 said, change class_mode='categorical' to class_mode='binary'.
Change class_mode='categorical' to class_mode='binary' in both train_generator and validation_generator.
Additionally, delete the following lines as you have already created model.
model.layers.pop()
model = Model(input=model.input,output=model.layers[-1].output)
So, your model would be like:
model = ResNet50(include_top=True, weights='imagenet')
x = model.get_layer('avg_pool').output
x = Flatten()(x)
predictions = Dense(1, activation='sigmoid')(x)
model = Model(input = model.input, output = predictions)

Categories

Resources