Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Frozen weight transfer learning

Frozen weight transfer learning vs. non-frozen weights in medical imaging classification using pre-trained models like VGG16, Xception, InceptionV3, DenseNet121.

Frozen-weight transfer learning is a training choice: you take a net pre-trained on ImageNet, you either lock those weights and train only a new head, or you let the whole net move on your medical set. This page is one 2023 PYCAD Team run of that choice on Kvasir endoscopy stills. It is not a definition of machine learning for imaging. It is not an iNeuron course. It is not a PYCAD product.

If you meant what imaging ML actually returns (mark / mask / score)machine learning for medical imaging. If you meant CNN vs ViT on X-ray PNGsCNNs or ViT for medical imaging. If you meant what a CNN isconvolutional neural networks explained. If you meant the radiology product jobAI in radiology.

The code is public: amine0110/medical-imaging-classification. The slug still says iNeuron because that is the URL; the dead course marketing is not the job.

The question

ImageNet weights already know edges and textures. Medical images are not ImageNet. Two common recipes:

  • Freeze the backbone. layer.trainable = False on the imported net. Train only GlobalAveragePooling + a softmax head. Cheap. The features stay ImageNet features.
  • Do not freeze. Same starting weights, every layer can move. You are fine-tuning, not just fitting a linear probe. More GPU, more chance to overfit a small set.

The default blog advice is “freeze, then maybe unfreeze later.” This run asked whether freezing was actually better on this set. It was not.

The set and the loaders

Kvasir is a public GI-endoscopy set (Kaggle mirrors exist). Classes are anatomical landmarks and findings, not a chest X-ray. Still RGB JPEGs, not DICOM. That matters for how far you should generalise the table below.

Eight Kvasir endoscopy stills used as the classification set: landmarks and findings, RGB, not DICOM.

image_dataset_from_directory does the 80/20 split. Input size follows the backbone (224 for VGG16 / DenseNet121, 299 if you switch to Xception). Batch 16 train, 8 val.

def return_ds(input_dir):
    train_ds = tf.keras.preprocessing.image_dataset_from_directory(
        input_dir,
        validation_split=0.2,
        subset="training",
        seed=42,
        image_size=(cfg.input_dim, cfg.input_dim),
        batch_size=16,
        label_mode="categorical",
    )
    val_ds = tf.keras.preprocessing.image_dataset_from_directory(
        input_dir,
        validation_split=0.2,
        subset="validation",
        seed=42,
        image_size=(cfg.input_dim, cfg.input_dim),
        batch_size=8,
        label_mode="categorical",
    )
    return train_ds, val_ds

The model

Four Keras applications, ImageNet weights, top off, a GAP + softmax head. freeze=True locks the backbone. Config picks the name and the learning rate (this run used SGD at 0.01).

def return_model(input_dim, nb_classes, freeze=False, head=None):
    heads = {
        "xception": Xception,
        "vgg16": VGG16,
        "inceptionv3": InceptionV3,
        "densenet121": DenseNet121,
    }
    if head is None or head.lower() not in heads:
        raise ValueError("choose head: xception, vgg16, inceptionv3, densenet121")
    ctor = heads[head.lower()]
    base_model = ctor(
        include_top=False,
        weights="imagenet",
        input_shape=(input_dim, input_dim, 3),
    )
    if freeze:
        for layer in base_model.layers:
            layer.trainable = False
    x = GlobalAveragePooling2D()(base_model.output)
    predictions = Dense(nb_classes, activation="softmax")(x)
    return Model(inputs=base_model.inputs, outputs=predictions)

The live 2023 snippet used if head == 'inceptionv3' or 'Inceptionv3', which is always true in Python. That is a real bug; the dict above is the same four models without it. The repo is the source of truth if the two diverge.

model.compile(
    loss="categorical_crossentropy",
    optimizer=tf.keras.optimizers.SGD(learning_rate=cfg.lr),
    metrics=["accuracy"],
)
save_weights = ModelCheckpoint(
    filepath="models/my_model.h5",
    monitor="val_accuracy",
    save_best_only=True,
    mode="max",
)

That run

Same recipe, frozen vs not, VGG16 and Xception. Numbers from the 2023 table (one run, this set, this LR):

Frozen backbone Not frozen
Model VGG16 Xception VGG16 Xception
Loss 222.78 190.12 0.43 0.43
Accuracy 0.55 0.56 0.87 0.88
2023 table: frozen VGG16 and Xception stay near 0.55 accuracy with huge loss; unfrozen both reach about 0.87–0.88.

A loss of ~200 on a softmax classifier is a model that did not fit. Frozen ImageNet features plus SGD at 0.01 on this endoscopy set were not enough. Letting the backbone move dropped the loss three orders of magnitude and gained ~30 accuracy points. That is this run. It is not “never freeze.”

Why it is not a law: RGB endoscopy, not DICOM; ImageNet pretrain; one LR; no site hold-out; no class-balanced report. A chest X-ray net, a 3D U-Net, or a two-stage freeze-then-unfreeze schedule can look different. The 2023 note already said so. If the frozen head is bad, try a lower LR on the backbone, or unfreeze from the top blocks down, before you declare transfer learning dead.

Inference

One image, or a directory via model.evaluate. Classes come from the annotation list in the repo.

def predict_one_image(img_path, model_path):
    classes = return_classes(cfg.classes_path)
    model = load_model(model_path)
    img = image.load_img(img_path, target_size=(cfg.input_dim, cfg.input_dim))
    img_array = np.expand_dims(image.img_to_array(img), axis=0)
    prediction = model.predict(img_array)
    idx = int(np.argmax(prediction))
    return classes[idx], float(np.max(prediction))

What this page is not

  • Not 673. The imaging-ML method layer already exists.
  • Not 308. CNN vs ViT is a different 2023 run, different repo.
  • Not an iNeuron / PYCAD course. The slug is leftover. Empty Gutenberg and diary first-person are gone. The Keras snippets stayed.

If the classifier has to land next to a DICOM study in a clinic app, that is the imaging piece. Case studies.

We build custom medical imaging platforms — advanced DICOM viewers, AI segmentation, and the clinical systems around them.

Get in Touch

Copyright © 2026 PYCAD. All Rights Reserved.