Breast Histopathology Image Segmentation Part 3
- Part 1: Data Inspection and Pre-processing
- Part 2: Weights, Data Augmentations and Generators
- Part 3: Model creation based on a pre-trained and a custom model
- Part 4: Train our model to fit the dataset
- Part 5: Evaluate the performance of your trained model
- Part 6: Running Predictions
Based on Breast Histopathology Images by Paul Mooney.
Invasive Ductal Carcinoma (IDC) is the most common subtype of all breast cancers. To assign an aggressiveness grade to a whole mount sample, pathologists typically focus on the regions which contain the IDC. As a result, one of the common pre-processing steps for automatic aggressiveness grading is to delineate the exact regions of IDC inside of a whole mount slide.
Can recurring breast cancer be spotted with AI tech? - BBC News
- Citation: Deep learning for digital pathology image analysis: A comprehensive tutorial with selected use cases
- Dataset: 198,738 IDC(negative) image patches; 78,786 IDC(positive) image patches
Model Creation - ResNet50
Start by loading the pre-trained model:
./train_ResNet50_32_20k.py
# Loading the ResNet50, ensuring the head Full Connected layers are left off / removed
baseModel = ResNet50(weights="imagenet", include_top=False, input_tensor=Input(shape=(48, 48, 3)))
Construct the head of the model that will be placed on top of the the base model:
## Flattening is converting the data into a 1-dimensional array for inputting it to the next layer.
## We flatten the output of the convolutional layers to create a single long feature vector.
### Average pooling computes the average of the elements present in the region of feature map covered by the filter.
#### ReLU stands for Rectified Linear Unit.
#### The main advantage of using the ReLU function over other activation functions is that it does not activate all the neurons at the same time.
## Dropout is a technique where randomly selected neurons are ignored during training.
headModel = baseModel.output
headModel = AveragePooling2D(pool_size=(7, 7), padding="same")(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(256, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(len(config.CLASSES), activation="softmax")(headModel)
# Placing the head model on top of the base model
model = Model(inputs=baseModel.input, outputs=headModel)
# Loop over all the layers of the base model and freeze them so that they are
# not updated during the training process
for layer in baseModel.layers:
layer.trainable = False
Model Creation - Custom CNN Model
Construction
Instead of downloading a pre-trained model we can build our own. The layers of the Custom Model are constructed according to:
utils/conv_bc_model.py
class BC_Model:
@staticmethod
def build(width, height, depth, classes):
# Lets first initialize the model with input shape to be "channels last" and channel's dimension
model = Sequential()
inputShape = (height, width, depth)
chanDim = -1
# If we are using "channels first", then let's update the input shape and channel's dimension
if K.image_data_format() == "channels_first":
inputShape = (depth, height, width)
chanDim = 1
# (CONV2D => RELU => BatchNormalization ) * 1 => POOL => DROPOUT
model.add(Conv2D(32, (3, 3), padding="same", input_shape=inputShape))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# (CONV2D => RELU => BatchNormalization ) * 2 => POOL => DROPOUT
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# (CONV2D => RELU => BatchNormalization ) * 3 => POOL => DROPOUT
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# (CONV2D => RELU => BatchNormalization ) * 4 => POOL => DROPOUT
model.add(Conv2D(256, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(256, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(256, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(256, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# FC => RELU layers => BatchNormalization => DROPOUT
model.add(Flatten())
model.add(Dense(512))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.5))
# Dense layer and softmax classifier
model.add(Dense(classes))
model.add(Activation("softmax"))
# Returning the created network architecture
return model
We can use this function to build the model:
./train_CustomModel_32_conv_20k.py
# Building the model
print("Building the model")
model = BC_Model.build(width=48, height=48, depth=3, classes=2)