✦ Machine Learning Project Lunar Surface Astroinformatics

Moon CNN: Deep Learning Lunar Phase Recognition

A 2D Convolutional Neural Network designed to classify lunar phases from scratch. Features custom data augmentation pipelines, layer optimization, and experimental validation curves.

Interactive Lunar Phase Scanner Simulation

Moon Phase Scanner Image
CNN Prediction Result 94% Confidence
Full Moon
Full Moon
94%
First Quarter
1%
Last Quarter
0%
New Moon
5%

Dataset Construction & Pipeline

To build this model, I manually created a dataset of 250 lunar training images and a validation dataset of 50 images, distributed evenly across four celestial classes:

Data Augmentation Strategy

Because astronomical datasets can be scarce, data augmentation was essential to prevent severe overfitting. The augmentation sequential layer applies:

  1. Resize: Downsampled from irregular camera dimensions to a uniform 140×140 grid.
  2. CenterCrop: Cropped to (128, 128) to eliminate peripheral background noise.
  3. RandomRotation (1.0) & RandomBrightness (0.2): Mimics variable telescope orientations and sensor exposure levels.
  4. RandomFlip (Horizontal): Enhances generalized edge detection across quarters.
  5. Rescale (1./127.5, offset=-1): Normalizes pixel tensors to the [-1, 1] range for numerical gradient stability.

CNN Architecture Implementation

The model is built using TensorFlow and Keras Sequential. Input tensors are processed in single-channel grayscale (since lunar morphology is captured primarily by luminance differentials), reducing parameter count and memory footprint:

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.Input(shape=(128, 128, 1)),
    data_augmentation,
    tf.keras.layers.Conv2D(32, kernel_size=3, padding='same', activation='relu'),
    tf.keras.layers.MaxPool2D(),
    tf.keras.layers.Conv2D(64, kernel_size=3, padding='same', activation='relu'),
    tf.keras.layers.MaxPool2D(),
    tf.keras.layers.Conv2D(128, kernel_size=3, padding='same', activation='relu'),
    tf.keras.layers.MaxPool2D(),
    tf.keras.layers.GlobalAveragePooling2D(),
    tf.keras.layers.Dense(units=128, activation="relu", kernel_initializer="he_normal"),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Dense(4, activation='softmax')
])

model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

Architecture Highlight: GlobalAveragePooling2D

Replacing a dense Flatten layer (which generated over 4.9 Million parameters) with GlobalAveragePooling2D drastically curtailed model size, reduced memory bottlenecks, and suppressed overfitting on the validation set.

Validation Tests & Empirical Results

To understand the learning dynamics, three configuration runs were executed and compared:

Test 1 • Baseline Run

Coarse Kernels & Overfitting

kernel_size = 5 optimizer = adam loss = sparse_ce

In the initial baseline run, a 5×5 kernel was too coarse for small crater edge features. The training loss converged, but validation loss exploded—a textbook case of the model memorizing training samples without generalization.

Test 1 Validation Curve
Test 2 • Layer Refinement

Global Pooling Parameter Reduction

kernel_size = 3 GlobalAveragePooling2D

Switching to 3×3 kernels and Global Average Pooling reduced millions of redundant weights. Training stability improved substantially, though validation variance remained high without data augmentation.

Test 2 Validation Curve
Test 3 • Final Optimized Pipeline

Augmentation Integration

kernel_size = 3 Data Augmentation Dropout = 0.3

Injecting stochastic rotation, brightness scaling, and center crops stabilized both training and validation losses. The validation loss curve showed sustained downward convergence and balanced multi-class recognition.

Test 3 Validation Curve
← Back to All Projects Next: Astro Py Deep Dive →