¿Cómo crear un modelo de clasificación múltiple en PyTorch?
Desarrollar un modelo de clasificación múltiple es una tarea fascinante y desafiante que aumenta tus habilidades en aprendizaje automático y procesamiento de lenguaje natural. En este tutorial, exploraremos cómo construir un modelo eficiente usando PyTorch, una de las bibliotecas más populares para deep learning. ¡Comencemos!
¿Qué es un modelo de clasificación múltiple y qué componentes utiliza?
Para construir nuestro modelo, utilizamos varias capas y técnicas que hacen que nuestros modelos sean más rápidos y eficaces. Veamos los pasos clave:
Importación de librerías: Importamos Torch, Torch NN, y Torch NN Functional. Estas incluyen las funciones fundamentales para crear la estructura del modelo.
Creación de la clase del modelo: Creamos una clase llamada modelo_clasificación_texto que hereda de NN.Module. Esto nos permite definir el comportamiento y organización de nuestro modelo.
Inicialización de variables: Al inicializar el modelo, solicitamos el tamaño del vocabulario, las dimensiones del embedding y el número de clases de los datos. Estos son cruciales para configurar las dimensiones de entrada y salida del modelo.
Bloques de construcción (Lego blocks):
Embedding: Usamos NN.EmbeddingBag para calcular representaciones densamente conectadas de palabras en el vocabulario.
Batch Normalization: Esta técnica normaliza los datos para mejorar la eficiencia del entrenamiento y prevenir el sobreajuste. PyTorch la maneja con NN.BatchNorm1d.
Fully Connected Layer: Usamos una capa linear para reducir dimensiones a la cantidad necesaria para clasificar nuestros textos. Esto proyecta datos a menos dimensiones.
¿Cómo se conectan las capas para procesar datos?
El método forward se encarga de conectar las capas y controlar el flujo de datos por ellas. Involucra los siguientes pasos:
Embedding del texto: Se convierte el texto de entrada en vectores de dimensiones más altas.
Normalización: Usamos nuestro bloque de Batch Normalization para compactar los datos.
Función de activación ReLU: Aplicamos la función ReLU para introducir no linealidad en el modelo.
Proyección a través de la capa Fully Connected: Finalmente, el texto normalizado y activado se pasa por la capa linear para obtener las predicciones clasificadas.
¿Cómo determinar la configuración inicial del modelo?
Para inicializar nuestro modelo, necesitamos obtener ciertas estadísticas de nuestro dataset:
Número de Clases: Lo determinamos explorando el dataset y contando las etiquetas únicas.
Tamaño de Vocabulario: La longitud del vocabulario se obtiene a partir de los datos cargados, que indican cuántas palabras y símbolos están presentes.
Dimensiones del Embedding: Un hiperparámetro que influye en la rapidez de procesamiento y precisión del modelo. Ejemplo de selección: 100 dimensiones para procesamiento rápido.
defcount_parameters(model):returnsum(p.numel()for p in model.parameters()if p.requires_grad)modelo = ModeloClasificacionTexto(vocab_size=VOCAB_SIZE, embed_dim=EMBEDDING_DIM, num_classes=NUM_CLASSES)print(f"El modelo tiene {count_parameters(modelo)} parámetros entrenables")
¿Cuáles son los siguientes pasos?
Con un modelo sólido y eficiente de clasificación múltiple en tus manos, ¡las posibilidades son inmensas! Te animo a que explores diferentes capas y técnicas para normalizar los datos, o incluso considerar la adición de capas de LSTM para capturar dependencias complejas en secuencias de texto. La experimentación es clave en la optimización de modelos. No dudes en dejar tus ideas y resultados en los comentarios. ¡Tu viaje en el aprendizaje automático apenas comienza!
Los embeddings, en palabras simples, son una matriz que nos permite representar cualquier palabra de un text corpus (o dataset de texto) en un array de N dimensiones, donde cada dimensión será una similaridad abstracta entre varias palabras, su nacimiento original se da para comprimir la cantidad de dimensiones que resultan de hacer One Hot Encoding a los tokens, pero ha resultado ser una herramienta excelente para calcular distancias vectoriales entre palabras (o sencillamente, su correlación).
Cómo funciona un embedding
Un embedding es simplemente una capa simétrica de 1 entrada y 1 salida, donde procesaremos cada posible token y se predecirá cuál es el token que le acompañará, al hacer esto, tendremos una matriz de pesos de dimensión tamaño_vocabulario x dimensiones_embedding.
En nuestro modelo hemos usado la capa EmbeddingBag, que nos evita computar la capa de entrada y salida y directamente calcula y usa el tensor de pesos para el resto de la red (además de aplicar promedio a cada dimensión).
Tamaño del modelo
Es increíble ver que el modelo tenga más de 80 millones de parámetros, pero es natural, dado que más del 90% de estos son la capa de embedding, donde para cada token existente en el corpus debemos crear una correlación con respecto a N dimensiones, en este caso nuestro caso tenemos un vocab_size de 802.998 y una dimensión de embedding de 100, por lo tanto los parámetros entrenables de esta capa será su multiplicación.
Finalidad del modelo
Esta capa nos permitirá ver la similitud entre palabras, por lo que, al ser posteriormente normalizada y activada, la pasaremos por una capa fully connect de 14 salidas para hacer la clasificación, de esta manera haremos que el modelo abstraiga qué palabras son más frecuentes de aparecer que otras con respecto a una categoría.
Estimado profesor, usted sabe bastante, pero hace falta que explique un poco mas detallado los conceptos. Muchas gracias
Hay cursos previos a este que se tiene que llevar, recomiendo usar chat GPT para terminar de consolidar conceptos complejos. Saludos
no entiendo como se normaliza un vector de textos, osea el vocabulario son numeros que representan palabras, pero que significaria restar la media y dividir por la varianza a un vector de numeros que representan palabras? estariamos calculando la distancia entre palabras?
Segun GPT:
Normalizar un vector de palabras en el contexto de NLP (Procesamiento de Lenguaje Natural) no se refiere a la normalización estadística (restar la media y dividir por la desviación estándar) como se haría con vectores numéricos. En NLP, la normalización de texto se refiere a la preparación del texto para su procesamiento, lo cual puede incluir varias técnicas como:
1. **Tokenización:**
Separar el texto en unidades más pequeñas, como palabras o subpalabras. Esto se puede hacer utilizando técnicas como dividir por espacios en blanco, tokenización basada en reglas o tokenización basada en modelos de lenguaje como BERT.
2. **Limpieza de texto:**
Eliminar caracteres especiales, puntuación, números, espacios adicionales, y convertir el texto a minúsculas para estandarizarlo. También se pueden eliminar palabras comunes que no aportan significado (stopwords).
3. **Stemming y lematización:**
Reducir las palabras a su forma base. El stemming reduce las palabras eliminando sufijos, mientras que la lematización reduce las palabras a su forma canónica (lema).
4. **Vectorización:**
Convertir las palabras en vectores numéricos para que puedan ser procesadas por algoritmos de aprendizaje automático. Esto se puede hacer utilizando técnicas como Bag of Words (BoW), TF-IDF (Term Frequency-Inverse Document Frequency), word embeddings (como Word2Vec, GloVe, FastText), entre otros.
5. **Padding y truncado:**
Alinear las secuencias de palabras para que tengan la misma longitud, utilizando padding para añadir tokens especiales al final o truncado para eliminar palabras en secuencias más largas.
6. **Normalización lingüística:**
Aplicar reglas lingüísticas específicas del idioma, como corrección ortográfica, corrección gramatical, expansión de abreviaturas, entre otros.
Estas son algunas de las técnicas comunes de normalización de texto en NLP. El enfoque exacto dependerá del problema específico que estés abordando y de las características del texto que estés procesando.
Hola Chicos , este es un Modelo xon dos capas LSTM al modelo para capturar dependencias secuenciales. He modificado la arquitectura del ejemplo de la clase, para usar Embedding normal en lugar de EmbeddingBag, ya que LSTM necesita procesar secuencias:
from torch import nn
import torch.nn.functional as F
classTextClassifierLSTM(nn.Module):def__init__(self, vocab_size, embed_dim, hidden_dim, class_num, num_layers=2, dropout=0.3):super(TextClassifierLSTM, self).__init__()# Capa de incrustación (embedding) self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)# Dos capas LSTM bidireccionales para capturar dependencias complejas self.lstm = nn.LSTM( input_size=embed_dim, hidden_size=hidden_dim, num_layers=num_layers, batch_first=True, dropout=dropout if num_layers >1else0, bidirectional=True)# Capa de normalización por lotes self.bn1 = nn.BatchNorm1d(hidden_dim *2)# *2 porque es bidireccional# Dropout para regularización self.dropout = nn.Dropout(dropout)# Capa completamente conectada self.fc = nn.Linear(hidden_dim *2, class_num)defforward(self, text):# text shape: (batch_size, seq_length)# Incrustar el texto embedded = self.embedding(text)# (batch_size, seq_length, embed_dim)# Pasar por LSTM lstm_out,(hidden, cell)= self.lstm(embedded)# lstm_out: (batch_size, seq_length, hidden_dim * 2)# Tomar el último estado oculto (concatenar forward y backward)# hidden shape: (num_layers * 2, batch_size, hidden_dim) hidden_forward = hidden[-2,:,:]# Última capa forward hidden_backward = hidden[-1,:,:]# Última capa backward hidden_concat = torch.cat([hidden_forward, hidden_backward], dim=1)# hidden_concat shape: (batch_size, hidden_dim * 2)# Normalización por lotes normalized = self.bn1(hidden_concat)# Activación ReLU activated = F.relu(normalized)# Dropout dropped = self.dropout(activated)# Capa de salida output = self.fc(dropped)return output
Para un Ejemplo de caso:
import torch
# Parámetros del modelo
vocab_size =10000embed_dim =128hidden_dim =256class_num =4 # ParaAG_NEWSnum_layers =2# Crear modelo
model =TextClassifierLSTM( vocab_size=vocab_size, embed_dim=embed_dim, hidden_dim=hidden_dim, class_num=class_num, num_layers=num_layers, dropout=0.3)# Ejemplo de entrada(batch_size=4, seq_length=50)text = torch.randint(0, vocab_size,(4,50))# Forward pass
output =model(text)print(f"Output shape: {output.shape}") # (4,4)print(f"Total parámetros: {sum(p.numel() for p in model.parameters()):,}")
Caracteristicas::
2 capas LSTM bidireccionales - capturan contexto en ambas direcciones.
Dropout - previene overfitting.
BatchNorm - estabiliza el entrenamiento.
Hidden state concatenado - usa información de ambas direccione.
PD: Ahora el forward solo recibe text (sin offsets), ya que LSTM procesa secuencias completas. Por tanto y Habra que Ajustar pipeline de datos para pasar tensores de secuencias en lugar de usar EmbeddingBag.
Para crear un modelo de clasificación de texto utilizando PyTorch, puedes seguir un enfoque basado en redes neuronales. Aquí te mostraré cómo construir un modelo simple de clasificación de texto utilizando una red neuronal totalmente conectada (fully connected neural network) con torch.nn. Este ejemplo utilizará el conjunto de datos AG News, pero puedes adaptarlo a cualquier conjunto de datos que estés utilizando.
### Paso 1: Importar las librerías necesarias
import torch
import torch.nn as nn
import torch.optim as optim
from torchtext.datasets import AG\_NEWS
from torchtext.data.utils import get\_tokenizer
from torchtext.vocab import build\_vocab\_from\_iterator
from torch.utils.data import DataLoader
### Paso 2: Cargar y preparar el conjunto de datos
\# Cargar el conjunto de datos AG News
train\_iter = AG\_NEWS(split='train')
\# Crear un tokenizador
tokenizador = get\_tokenizer('basic\_english')
\# Función para generar tokens
defyield\_tokens(data\_iter):  for \_, texto in data\_iter:  yield tokenizador(texto)
\# Construir el vocabulario
vocab = build\_vocab\_from\_iterator(yield\_tokens(train\_iter), specials=\["\<unk>"])vocab.set\_default\_index(vocab\["\<unk>"])
\# Función para convertir texto en índices de vocabulario
def process\_text(text):  return torch.tensor(\[vocab\[token] for token in tokenizador(text)], dtype=torch.int64)
\# Cargar de nuevo el conjunto de datos
train\_iter = AG\_NEWS(split='train')\# Crear una lista de tuplas (texto procesado, etiqueta)data = \[(process\_text(text), label)for label, text in train\_iter]
\# Crear un DataLoader
batch\_size =16# Puedes ajustar el tamaño del batchdata\_loader = DataLoader(data, batch\_size=batch\_size, shuffle=True)
### Paso 3: Definir el modelo
Aquí definimos un modelo simple de red neuronal:
classTextClassifier(nn.Module):  def \_\_init\_\_(self, vocab\_size, embed\_dim, num\_classes):  super(TextClassifier, self).\_\_init\_\_()  self.embedding = nn.Embedding(vocab\_size, embed\_dim)  self.fc1 = nn.Linear(embed\_dim, 128)  self.fc2 = nn.Linear(128, num\_classes)  self.relu = nn.ReLU()  self.softmax = nn.LogSoftmax(dim=1)  def forward(self, x):  \# x: tensor de índices  x = self.embedding(x) # Obtiene las representaciones de las palabras  x = x.mean(dim=1) # Promedia los embeddings (puedes usar otras técnicas de agregación)  x = self.fc1(x)  x = self.relu(x)  x = self.fc2(x)  return self.softmax(x)
### Paso 4: Inicializar el modelo, la función de pérdida y el optimizador
\# Parámetros
vocab\_size =len(vocab)embed\_dim =64# Dimensión de los embeddingsnum\_classes =4# Número de clases en AG News
\# Inicializar el modelo
model = TextClassifier(vocab\_size, embed\_dim, num\_classes)
\# Definir la función de pérdida y el optimizador
criterion = nn.NLLLoss()# Pérdida negativa logarítmicaoptimizer = optim.Adam(model.parameters(), lr=0.001)
### Paso 5: Entrenamiento del modelo
\# Definir el número de épocas
num\_epochs =5for epoch inrange(num\_epochs):  total\_loss = 0  for texts, labels in data\_loader:  \# Zero gradients  optimizer.zero\_grad()  \# Forward pass  outputs = model(texts)  \# Compute loss  loss = criterion(outputs, labels)  \# Backward pass and optimization  loss.backward()  optimizer.step()  total\_loss += loss.item()  print(f"Epoch \[{epoch + 1}/{num\_epochs}], Loss: {total\_loss / len(data\_loader):.4f}")
### Paso 6: Evaluación del modelo
Para evaluar el modelo, puedes usar un conjunto de validación o prueba. A continuación se muestra un ejemplo básico:
def evaluate\_model(model, data\_loader):  model.eval() # Cambiar a modo evaluación  correct = 0  total = 0  with torch.no\_grad():  for texts, labels in data\_loader:  outputs = model(texts)  \_, predicted = torch.max(outputs.data, 1)  total += labels.size(0)  correct += (predicted == labels).sum().item()  print(f'Accuracy: {100 \* correct / total:.2f}%')
\# Puedes evaluar usando el mismo DataLoader de entrenamiento o uno diferente
evaluate\_model(model, data\_loader)
### Resumen
1. **Importar librerías y cargar el conjunto de datos.**
2. **Definir el modelo de clasificación.**
3. **Inicializar el modelo, la función de pérdida y el optimizador.**
4. **Entrenar el modelo.**
5. **Evaluar el modelo.**
Esto te dará una buena base para crear un modelo de clasificación de texto en PyTorch.