File size: 3,426 Bytes
cdf0064
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""
Model Architecture Module
Defines the Convolutional Autoencoder architecture
"""
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D


def build_autoencoder():
    """
    Build Convolutional Autoencoder model for image denoising
    
    Autoencoder: Neural network that learns to compress (encode) and 
    reconstruct (decode) data. Used here to learn clean image representation.
    
    Architecture:
    - Encoder: Compresses noisy image to latent representation
    - Latent Space: Compressed representation capturing essential features
    - Decoder: Reconstructs clean image from latent representation
    
    Returns:
        Compiled Keras model
    """
    # Input layer: 28x28 grayscale images
    input_img = Input(shape=(28, 28, 1))
    
    # ========== ENCODER ==========
    # Encoder compresses input image to lower-dimensional latent space
    # This forces model to learn essential features while removing noise
    
    # Conv2D: Convolutional layer extracts spatial features using filters
    # - 32 filters learn different patterns (edges, textures)
    # - 3x3 kernel size for local feature detection
    # - ReLU activation introduces non-linearity
    # - padding='same' maintains spatial dimensions
    x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
    
    # MaxPooling2D: Downsamples by taking maximum value in 2x2 window
    # Reduces spatial dimensions from 28x28 to 14x14
    x = MaxPooling2D((2, 2), padding='same')(x)
    
    # Second convolutional block with fewer filters (16)
    x = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
    
    # Further downsample from 14x14 to 7x7
    encoded = MaxPooling2D((2, 2), padding='same')(x)
    
    # ========== LATENT SPACE ==========
    # At this point: 7x7x16 = 784 values (compressed from 28x28 = 784 pixels)
    # Latent space captures essential image features without noise
    
    # ========== DECODER ==========
    # Decoder reconstructs clean image from compressed representation
    
    # Convolutional layer to process latent features
    x = Conv2D(16, (3, 3), activation='relu', padding='same')(encoded)
    
    # UpSampling2D: Increases spatial dimensions by repeating values
    # Upsamples from 7x7 to 14x14
    x = UpSampling2D((2, 2))(x)
    
    # Expand feature maps back to 32 filters
    x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
    
    # Upsample from 14x14 to 28x28 (original size)
    x = UpSampling2D((2, 2))(x)
    
    # Final layer: 1 filter to produce single-channel grayscale output
    # Sigmoid activation ensures output values in range [0, 1]
    decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
    
    # Create model mapping input to decoded output
    autoencoder = Model(input_img, decoded)
    
    return autoencoder


def compile_model(model):
    """
    Compile the autoencoder model
    
    Args:
        model: Keras model to compile
    
    Returns:
        Compiled model
    """
    # Adam optimizer: Adaptive learning rate optimization algorithm
    # binary_crossentropy: Measures difference between predicted and actual pixel values
    # accuracy: Tracks how close predictions are to targets
    model.compile(optimizer='adam', 
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    return model