PyTorch Ejemplo - Proyecto de Análisis de Sentimiento de Texto
El análisis de sentimiento de texto es una tarea fundamental en el procesamiento del lenguaje natural (NLP) que tiene como objetivo determinar la tendencia emocional (positiva/negativa) expresada en un texto. Este proyecto utilizará PyTorch para construir un modelo de aprendizaje profundo que realice la clasificación de sentimientos de reseñas de películas.
Escenarios de aplicación del análisis de sentimiento
- Análisis de reseñas de productos
- Monitoreo de opinión pública en redes sociales
- Clasificación de comentarios de servicio al cliente
- Predicción de tendencias de mercado
Preparación del entorno
Herramientas y bibliotecas necesarias
Ejemplo
import torch
import torch.nn as nn
import torch.optim as optim
from torchtext.data import Field, TabularDataset, BucketIterator
import spacy
import numpy as np
import torch.nn as nn
import torch.optim as optim
from torchtext.data import Field, TabularDataset, BucketIterator
import spacy
import numpy as np
Instalar dependencias
pip install torch torchtext spacy python -m spacy download en_core_web_sm
Preparación de datos
Introducción al conjunto de datos
Se utiliza el conjunto de datos de reseñas de películas IMDB, que contiene 50,000 reseñas con etiquetas de sentimiento (positivo/negativo).
Preprocesamiento de datos
Ejemplo
# Definir el procesamiento de campos
TEXT = Field(tokenize='spacy',
tokenizer_language='en_core_web_sm',
include_lengths=True)
LABEL = Field(sequential=False, use_vocab=False)
# Cargar el conjunto de datos
train_data, test_data = TabularDataset.splits(
path='./data',
train='train.csv',
test='test.csv',
format='csv',
fields=[('text', TEXT), ('label', LABEL)]
)
# Construir el vocabulario
TEXT.build_vocab(train_data,
max_size=25000,
vectors="glove.6B.100d")
TEXT = Field(tokenize='spacy',
tokenizer_language='en_core_web_sm',
include_lengths=True)
LABEL = Field(sequential=False, use_vocab=False)
# Cargar el conjunto de datos
train_data, test_data = TabularDataset.splits(
path='./data',
train='train.csv',
test='test.csv',
format='csv',
fields=[('text', TEXT), ('label', LABEL)]
)
# Construir el vocabulario
TEXT.build_vocab(train_data,
max_size=25000,
vectors="glove.6B.100d")
Construcción del modelo
Arquitectura del modelo LSTM

4.2 Código de implementación del modelo
Ejemplo
class SentimentLSTM(nn.Module):
def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim,
hidden_dim,
num_layers=n_layers,
bidirectional=True)
self.fc = nn.Linear(hidden_dim * 2, output_dim)
self.dropout = nn.Dropout(0.5)
def forward(self, text, text_lengths):
embedded = self.dropout(self.embedding(text))
packed_embedded = nn.utils.rnn.pack_padded_sequence(
embedded, text_lengths.to('cpu'))
packed_output, (hidden, cell) = self.lstm(packed_embedded)
hidden = self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim=1))
return self.fc(hidden)
def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim,
hidden_dim,
num_layers=n_layers,
bidirectional=True)
self.fc = nn.Linear(hidden_dim * 2, output_dim)
self.dropout = nn.Dropout(0.5)
def forward(self, text, text_lengths):
embedded = self.dropout(self.embedding(text))
packed_embedded = nn.utils.rnn.pack_padded_sequence(
embedded, text_lengths.to('cpu'))
packed_output, (hidden, cell) = self.lstm(packed_embedded)
hidden = self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim=1))
return self.fc(hidden)
Entrenamiento del modelo
Configuración de parámetros de entrenamiento
Ejemplo
# Parámetros del modelo
INPUT_DIM = len(TEXT.vocab)
EMBEDDING_DIM = 100
HIDDEN_DIM = 256
OUTPUT_DIM = 1
N_LAYERS = 2
# Inicializar el modelo
model = SentimentLSTM(INPUT_DIM, EMBEDDING_DIM, HIDDEN_DIM, OUTPUT_DIM, N_LAYERS)
# Optimizador y función de pérdida
optimizer = optim.Adam(model.parameters())
criterion = nn.BCEWithLogitsLoss()
INPUT_DIM = len(TEXT.vocab)
EMBEDDING_DIM = 100
HIDDEN_DIM = 256
OUTPUT_DIM = 1
N_LAYERS = 2
# Inicializar el modelo
model = SentimentLSTM(INPUT_DIM, EMBEDDING_DIM, HIDDEN_DIM, OUTPUT_DIM, N_LAYERS)
# Optimizador y función de pérdida
optimizer = optim.Adam(model.parameters())
criterion = nn.BCEWithLogitsLoss()
Bucle de entrenamiento
Ejemplo
def train(model, iterator, optimizer, criterion):
epoch_loss = 0
epoch_acc = 0
model.train()
for batch in iterator:
text, text_lengths = batch.text
predictions = model(text, text_lengths).squeeze(1)
loss = criterion(predictions, batch.label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch_loss += loss.item()
epoch_acc += accuracy(predictions, batch.label)
return epoch_loss / len(iterator), epoch_acc / len(iterator)
epoch_loss = 0
epoch_acc = 0
model.train()
for batch in iterator:
text, text_lengths = batch.text
predictions = model(text, text_lengths).squeeze(1)
loss = criterion(predictions, batch.label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch_loss += loss.item()
epoch_acc += accuracy(predictions, batch.label)
return epoch_loss / len(iterator), epoch_acc / len(iterator)
Evaluación del modelo
Función de evaluación
Ejemplo
def evaluate(model, iterator, criterion):
epoch_loss = 0
epoch_acc = 0
model.eval()
with torch.no_grad():
for batch in iterator:
text, text_lengths = batch.text
predictions = model(text, text_lengths).squeeze(1)
loss = criterion(predictions, batch.label)
epoch_loss += loss.item()
epoch_acc += accuracy(predictions, batch.label)
return epoch_loss / len(iterator), epoch_acc / len(iterator)
epoch_loss = 0
epoch_acc = 0
model.eval()
with torch.no_grad():
for batch in iterator:
text, text_lengths = batch.text
predictions = model(text, text_lengths).squeeze(1)
loss = criterion(predictions, batch.label)
epoch_loss += loss.item()
epoch_acc += accuracy(predictions, batch.label)
return epoch_loss / len(iterator), epoch_acc / len(iterator)
Cálculo de precisión
Ejemplo
def accuracy(preds, y):
rounded_preds = torch.round(torch.sigmoid(preds))
correct = (rounded_preds == y).float()
acc = correct.sum() / len(correct)
return acc
rounded_preds = torch.round(torch.sigmoid(preds))
correct = (rounded_preds == y).float()
acc = correct.sum() / len(correct)
return acc
Aplicación del modelo
Predecir texto nuevo
Ejemplo
def predict_sentiment(model, sentence):
tokenized = [tok.text for tok in nlp.tokenizer(sentence)]
indexed = [TEXT.vocab.stoi[t] for t in tokenized]
length = [len(indexed)]
tensor = torch.LongTensor(indexed).to(device)
tensor = tensor.unsqueeze(1)
length_tensor = torch.LongTensor(length)
prediction = torch.sigmoid(model(tensor, length_tensor))
return prediction.item()
tokenized = [tok.text for tok in nlp.tokenizer(sentence)]
indexed = [TEXT.vocab.stoi[t] for t in tokenized]
length = [len(indexed)]
tensor = torch.LongTensor(indexed).to(device)
tensor = tensor.unsqueeze(1)
length_tensor = torch.LongTensor(length)
prediction = torch.sigmoid(model(tensor, length_tensor))
return prediction.item()
Predicción de ejemplo
Ejemplo
positive_review = "This movie was fantastic! I really enjoyed it."
negative_review = "The film was terrible and boring."
print(f"Positive review score: {predict_sentiment(model, positive_review):.4f}")
print(f"Negative review score: {predict_sentiment(model, negative_review):.4f}")
negative_review = "The film was terrible and boring."
print(f"Positive review score: {predict_sentiment(model, positive_review):.4f}")
print(f"Negative review score: {predict_sentiment(model, negative_review):.4f}")