-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path02_model_architecture_cnn.py
More file actions
78 lines (63 loc) · 3.69 KB
/
02_model_architecture_cnn.py
File metadata and controls
78 lines (63 loc) · 3.69 KB
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
import tensorflow as tf
from tensorflow.keras import layers, models
def build_custom_cnn_branch(input_shape, output_dim=128, dropout_rate=0.3):
"""
Construye la rama visual del modelo (Custom CNN con TimeDistributed).
Args:
input_shape: Tupla (TimeSteps, Height, Width, Channels)
Ej: (6, 128, 128, 1)
output_dim: Tamaño del vector de características de salida (Ej: 128)
Returns:
Un modelo Keras (o sub-modelo) que toma la secuencia de imágenes
y devuelve un vector de características.
"""
# Entrada de la secuencia de video (imágenes de temperatura)
visual_input = layers.Input(shape=input_shape, name="input_visual_temp")
# --- BLOQUE 1: Extracción de Bordes y Gradientes Térmicos ---
# TimeDistributed aplica la capa a cada frame temporal independientemente
x = layers.TimeDistributed(layers.Conv2D(32, (3, 3), padding='same'))(visual_input)
x = layers.TimeDistributed(layers.BatchNormalization())(x)
x = layers.TimeDistributed(layers.Activation('relu'))(x)
x = layers.TimeDistributed(layers.MaxPooling2D((2, 2)))(x)
# Salida: (Batch, Time, 64, 64, 32)
# --- BLOQUE 2: Extracción de Formas (Nubes, Celdas) ---
x = layers.TimeDistributed(layers.Conv2D(64, (3, 3), padding='same'))(x)
x = layers.TimeDistributed(layers.BatchNormalization())(x)
x = layers.TimeDistributed(layers.Activation('relu'))(x)
x = layers.TimeDistributed(layers.MaxPooling2D((2, 2)))(x)
# Salida: (Batch, Time, 32, 32, 64)
# --- BLOQUE 3: Patrones de Mesoescala ---
x = layers.TimeDistributed(layers.Conv2D(128, (3, 3), padding='same'))(x)
x = layers.TimeDistributed(layers.BatchNormalization())(x)
x = layers.TimeDistributed(layers.Activation('relu'))(x)
x = layers.TimeDistributed(layers.MaxPooling2D((2, 2)))(x)
# Salida: (Batch, Time, 16, 16, 128)
# --- BLOQUE 4: Estructura Global del Sistema ---
x = layers.TimeDistributed(layers.Conv2D(256, (3, 3), padding='same'))(x)
x = layers.TimeDistributed(layers.BatchNormalization())(x)
x = layers.TimeDistributed(layers.Activation('relu'))(x)
x = layers.TimeDistributed(layers.MaxPooling2D((2, 2)))(x)
# Salida: (Batch, Time, 8, 8, 256)
# --- COLAPSO ESPACIAL (Feature Maps -> Vectores) ---
# Promediamos el espacio (8x8) para obtener un vector por cada instante de tiempo
x = layers.TimeDistributed(layers.GlobalAveragePooling2D())(x)
# Salida: (Batch, Time, 256) -> Tenemos 6 vectores de 256 características
x = layers.Dropout(dropout_rate)(x)
# --- COLAPSO TEMPORAL (Secuencia -> Resumen Único) ---
# Opción A: Usar LSTM/GRU si el orden secuencial estricto es vital.
# Opción B: Usar GlobalAveragePooling1D si queremos el "resumen" de la última hora.
# Para fenómenos convectivos donde la "presencia" de la nube importa más que el segundo exacto:
x = layers.GlobalAveragePooling1D()(x)
# Salida: (Batch, 256)
# --- PROYECCIÓN FINAL (Cuello de botella) ---
# Reducimos a la dimensión acordada para fusionar con la rama tabular
visual_embedding = layers.Dense(output_dim, activation="relu", name="visual_embedding")(x)
# Crear el modelo encapsulado
model = models.Model(inputs=visual_input, outputs=visual_embedding, name="Rama_Visual_CNN")
return model
if __name__ == "__main__":
# Bloque de prueba para verificar que las dimensiones cuadran
input_shape_test = (6, 128, 128, 1) # (Time, H, W, Channels)
model = build_custom_cnn_branch(input_shape_test)
model.summary()
print("\n¡Arquitectura Visual compilada correctamente!")