Cracking Icebergs with Deep Learning: My Kaggle Statoil/C-CORE Challenge Project
Distinguishing icebergs vs ships in Synthetic Aperture Radar (SAR) imagery matters for maritime safety and offshore operations. In this project I worked on the Kaggle Statoil/C-CORE Iceberg Classifier Challenge, building image models that convert raw satellite bands into reliable predictions.
π Full code & notebook: GitHub β Statoil Iceberg Classifier
Why this matters
- Business impact: Reduces risk for vessels and offshore assets; helps allocate resources more efficiently.
- Breadth of skills: Problem framing, exploratory analysis, modeling, evaluation, and reproducible delivery.
- Transferability: Methods generalize to other imaging domains (quality control, medical, remote sensing).
Whatβs in the notebook
Data & representation
- SAR JSON inputs (
band_1,band_2,inc_angle). - Construction of three-channel tensors including a DIFF channel (
band_1 - band_2) and per-image standardization. - Side feature:
inc_angleused as a numeric input branch.

Example visualization of SAR image bands, highlighting how raw radar data is transformed into usable inputs for modeling.
Models implemented
- Baseline two-input CNN (TensorFlow/Keras) β image branch + angle branch fused at the head.
- Transfer learning with ResNet50V2 (frozen backbone) β applied to DIFF-channel RGB, plus angle branch.
Both were trained with stratified splits, early stopping, and callbacks such as learning-rate reduction.

Training curves showing how AUC improves while LogLoss decreases β evidence of a well-tuned model.
Code snippets
Baseline two-input CNN:
inp_img = tf.keras.layers.Input(shape=(75, 75, 3))
x = augment(inp_img)
x = tf.keras.layers.Conv2D(32, 3, padding="same", activation="relu")(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.MaxPooling2D()(x)
x = tf.keras.layers.Conv2D(64, 3, padding="same", activation="relu")(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.MaxPooling2D()(x)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.3)(x)
inp_ang = tf.keras.layers.Input(shape=(1,))
ang = tf.keras.layers.Normalization()(inp_ang)
ang = tf.keras.layers.Dense(16, activation="relu")(ang)
h = tf.keras.layers.Concatenate()([x, ang])
h = tf.keras.layers.Dense(128, activation="relu")(h)
h = tf.keras.layers.Dropout(0.3)(h)
out = tf.keras.layers.Dense(1, activation="sigmoid")(h)
model = tf.keras.Model([inp_img, inp_ang], out)
What I learned
- Side-feature fusion (angle + image) can materially help performance in radar imagery.
- DIFF channel emphasizes class-relevant texture/structure that plain bands may under-express.
- Frozen transfer learning provides a strong baseline; careful regularization and calibration (label smoothing) matter.
- Reproducibility: fixed seeds, stratified splits, and saved weights enable reliable iteration.
Explore the project
- π¦ Repo & notebook: GitHub β Statoil Iceberg Classifier
- π README covers environment setup, data notes, and how to run the notebook end-to-end.