Introducción a paddle.nn y paddle.nn.functional
El módulo paddle.nn en PaddlePaddle proporciona implementaciones de capas de redes neuronales como clases, mientras que paddle.nn.functional ofrece las correspondientes funciones operativas. Aunque su funcionalidad central es similar, existen diferencias clave en su uso y alcance.
Las clases en paddle.nn (por ejemplo, paddle.nn.Conv2D) heredan de paddle.nn.Layer. Esto significa que encapsulan no solo la operación matemática, sino también los parámetros aprendibles (pesos y sesgos) y métodos del ciclo de vida del modelo, como train() y eval(). Esto facilita su integración con contenedores de alto nivel como paddle.nn.Sequential para construir modelos complejos de manera modular.
Por otro lado, las funciones de paddle.nn.functional (como paddle.nn.functional.conv2d) son operaciones puras que requieren que el usuario pase explícitamente los tensores de parámetros (pesos, sesgos) en cada invocación. Esto ofrece mayor control y flexibilidad, pero reduce la encapsulación y la reutilización directa del código.
Cuándo usar cada uno
La práctica recomendada, alineada con el diseño de PaddlePaddle y frameworks similares, es utilizar las clases de paddle.nn siempre que sea posible. Esto:
- Mejora la legibilidad: La estructura jerárquica del modelo se refleja claramente en el código.
- Simplifica la gestión de parámetros: Los parámetros se crean, almacenan y serializan automáticamente con el módulo.
- Garantiza el comportamiento correcto: Capas como
DropoutyBatchNormajustan automáticamente su comportamiento entre los modos de entrenamiento e inferencia cuando se llama amodel.eval().
Usa paddle.nn.functional cuando necesites un control explícito sobre los parámetros o estés implementando una operación personalizada que no encaje en el patrón de una capa estándar.
Ejemplo de código contrastado
Consideremos la definición de una capa convolucional simple de ambas maneras:
import paddle
import paddle.nn as nn
# Definición usando paddle.nn.Conv2D (enfoque con capa)
class ModeloConCapa(nn.Layer):
def __init__(self):
super().__init__()
self.conv = nn.Conv2D(in_channels=3, out_channels=16, kernel_size=3, padding=1)
self.activacion = nn.ReLU()
def forward(self, x):
x = self.conv(x)
return self.activacion(x)
# Definición usando paddle.nn.functional (enfoque funcional)
class ModeloFuncional(nn.Layer):
def __init__(self):
super().__init__()
# Los parámetros se deben crear y registrar explícitamente
self.peso_conv = self.create_parameter(shape=[16, 3, 3, 3])
self.sesgo_conv = self.create_parameter(shape=[16], is_bias=True)
def forward(self, x):
# Los parámetros se pasan explícitamente a la función
x = paddle.nn.functional.conv2d(x, self.peso_conv, self.sesgo_conv, padding=1)
return paddle.nn.functional.relu(x)
# Ambas definiciones son funcionalmente equivalentes para una pasada hacia adelante.
Se prefiere el primer enfoque (ModeloConCapa) para capas con parámetros entrenables.
Categorías principales de capas en paddle.nn
A continuación se describe una selección de las capas disponibles, agrupadas por función.
Contenedores
Son capas diseñadas para contenerr y organizar otras capas.
paddle.nn.Layer: Clase base para todas las capas y modelos.paddle.nn.LayerList: Contenedor de lista de subcapas. Útil cuando el número de capas es dinámico.paddle.nn.Sequential: Contenedor que ordena y aplica una secuencia de capas en orden.
# Ejemplo de uso de Sequential
modelo_secuencial = nn.Sequential(
nn.Conv2D(3, 32, 3),
nn.BatchNorm2D(32),
nn.ReLU(),
nn.MaxPool2D(2)
)
# Las capas se ejecutan en el orden en que se proporcionan.
Capas de Convolución
Aplican operaciones de convolución a tensores de entrada, comúnmente usadas en procesamiento de imágenes y series temporales.
paddle.nn.Conv1D,paddle.nn.Conv2D,paddle.nn.Conv3D: Convoluciones en 1D, 2D y 3D.paddle.nn.Conv1DTranspose, etc.: Convoluciones transpuestas, usadas para operaciones de aumento de resolución.
# Ejemplo de una capa Conv2D
capa_convolucion = nn.Conv2D(
in_channels=1, # Canales de entrada (ej., imagen en escala de grises)
out_channels=32, # Número de filtros (canales de salida)
kernel_size=5, # Tamaño del kernel
stride=1, # Paso de la convolución
padding=2 # Relleno para mantener dimensiones espaciales
)
# Entrada: [lote, 1, 28, 28] -> Salida: [lote, 32, 28, 28]
Capas de Agrupamiento (Pooling)
Reducen la dimensionalidad espacial de los tensores, resumiendo información local.
paddle.nn.MaxPool2D: Selecciona el valor máximo en una ventana.paddle.nn.AvgPool2D: Calcula el promedio en una ventana.paddle.nn.AdaptiveAvgPool2D: Promedia a un tamaño de salida específico.
Capas de Normalización
Estabilizan y aceleran el entrenamiento de redes profundas normalizando las activaciones.
paddle.nn.BatchNorm1D/2D/3D: Normalización por lotes a lo largo de la dimensión del lote.paddle.nn.LayerNorm: Normalización a lo largo de la dimensión de características.paddle.nn.GroupNorm: Divide los canales en grupos y normaliza dentro de cada grupo.
# Ejemplo de BatchNorm2D para una entrada con 64 canales
batch_norm = nn.BatchNorm2D(num_channels=64)
# Durante el entrenamiento: normaliza por lote y actualiza estadísticas.
# Durante la inferencia (tras model.eval()): usa estadísticas acumuladas.
Capas de Activación
Introducen no linealidades en la red.
paddle.nn.ReLU:f(x) = max(0, x). Ampliamente usada.paddle.nn.Sigmoid: Comprime la salida al rango (0, 1).paddle.nn.Softmax: Convierte un vector de logits en una distribución de probabilidad.paddle.nn.LeakyReLU,paddle.nn.GELU, etc.: Variantes con diferentes propiedades.
Capas de Regularización
Previenen el sobreajuste durante el entrenamiento.
paddle.nn.Dropout: Anula aleatoriamente elementos del tensor de entrada con probabilidadp.
dropout_layer = nn.Dropout(p=0.5)
# En modo entrenamiento (capa activa): anula elementos.
# En modo evaluación (capa inactiva tras model.eval()): no tiene efecto.
Capas Recurrentes (RNN)
Procesan datos secuenciales manteniendo un estado oculto.
paddle.nn.SimpleRNN,paddle.nn.LSTM,paddle.nn.GRU: Capas completas de redes recurrentes.paddle.nn.RNNCellBase,paddle.nn.LSTMCell: Unidades recurrentes individuales de bajo nivel.
Arquitectura Transformer
Componentes basados en mecanismos de atención, dominantes en NLP y más allá.
paddle.nn.MultiHeadAttention: Implementa el mecanismo de atención multiparte.paddle.nn.TransformerEncoderLayer/paddle.nn.TransformerDecoderLayer: Capas de un bloque del codificador/decodificador.paddle.nn.TransformerEncoder/paddle.nn.TransformerDecoder: Apilan múltiples capas para formar el codificador/decodificador completo.
# Ejemplo de una capa de atención multiparte
multi_atencion = nn.MultiHeadAttention(
embed_dim=128, # Dimensión del embedding
num_heads=8, # Número de cabezas de atención
dropout=0.1
)
# Entrada consulta (query): [lote, longitud_seq, 128]
consulta = paddle.rand([2, 10, 128])
salida_atencion = multi_atencion(consulta, consulta, consulta) # Atención consigo misma (self-attention)
# Salida: [lote, longitud_seq, 128]
Capas de Función de Pérdida (Loss)
Cuantifican la discrepancia entre las prediccioens del modelo y las etiquetas verdaderas.
paddle.nn.CrossEntropyLoss: Para clasificación multiclase. CombinaLogSoftmaxyNLLLoss.paddle.nn.MSELoss: Error cuadrático medio, usado en regresión.paddle.nn.BCELoss: Pérdida de entropía cruzada binaria, para clasificación binaria.
# Pérdida de entropía cruzada para clasificación
funcion_perdida = nn.CrossEntropyLoss()
# logits (salida bruta del modelo): [lote, num_clases]
logits = paddle.to_tensor([[2.0, 1.0, 0.1], [0.5, 2.5, 0.3]])
# etiquetas verdaderas: [lote] (índices de clase)
etiquetas = paddle.to_tensor([0, 1], dtype='int64')
perdida = funcion_perdida(logits, etiquetas)
Otras capas importantes
paddle.nn.Linear: Capa lineal (completamente conectada).y = xW^T + b.paddle.nn.Embedding: Capa de incrustación, mapea índices a vecotres densos.paddle.nn.Flatten: Aplana un tensor a 1D.