基于神经网络的中文情绪分类
·
基于神经网络的中文情绪分类
文章目录
以下文字及代码仅供参考。
支持RNN/LSTM/GRU
预达到预期:
1.可视化UI界面
2.训练结果可视化
3.支持GPU加速训练
4.PyTorch实现RNN/LSTM/GRU切换
基于 PyTorch 的中文情绪分类实现,支持 RNN、LSTM 和 GRU 模型切换,并包含可视化 UI 界面、训练结果可视化和 GPU 加速训练的功能。
代码仅供参考,我的同学
1. 安装依赖
确保安装了必要的库:
pip install torch torchvision matplotlib PyQt5 jieba scikit-learn wordcloud
2. 数据准备
假设你的数据集是一个 CSV 文件,包含两列:text(文本)和 label(情绪类别)。例如:
| text | label |
|---|---|
| 这部电影太棒了! | 正面 |
| 我对这个服务很失望。 | 负面 |
2.1 数据预处理
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from collections import Counter
# 加载数据
data = pd.read_csv("sentiment_data.csv")
# 分词并生成词汇表
def tokenize(text):
return list(jieba.cut(text))
data['tokens'] = data['text'].apply(tokenize)
# 构建词汇表
all_tokens = [token for tokens in data['tokens'] for token in tokens]
vocab = Counter(all_tokens)
vocab_size = len(vocab) + 1 # +1 是为了保留一个未知词标记
word_to_idx = {word: idx + 1 for idx, word in enumerate(vocab.keys())} # 0 留给填充
idx_to_word = {idx: word for word, idx in word_to_idx.items()}
# 转换标签为数值
label_encoder = LabelEncoder()
data['label'] = label_encoder.fit_transform(data['label'])
# 划分训练集和测试集
train_texts, test_texts, train_labels, test_labels = train_test_split(
data['tokens'], data['label'], test_size=0.2, random_state=42
)

3. 模型定义
支持 RNN、LSTM 和 GRU 模型切换。
import torch
import torch.nn as nn
class SentimentModel(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim, model_type="LSTM"):
super(SentimentModel, self).__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
if model_type == "RNN":
self.rnn = nn.RNN(embed_dim, hidden_dim, batch_first=True)
elif model_type == "LSTM":
self.rnn = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
elif model_type == "GRU":
self.rnn = nn.GRU(embed_dim, hidden_dim, batch_first=True)
else:
raise ValueError("Unsupported model type")
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
embedded = self.embedding(x)
rnn_out, _ = self.rnn(embedded)
out = self.fc(rnn_out[:, -1, :]) # 取最后一个时间步的输出
return out
4. 训练与评估

4.1 数据加载器
from torch.utils.data import Dataset, DataLoader
class TextDataset(Dataset):
def __init__(self, texts, labels, word_to_idx, max_len=50):
self.texts = texts
self.labels = labels
self.word_to_idx = word_to_idx
self.max_len = max_len
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
text = self.texts.iloc[idx]
label = self.labels.iloc[idx]
seq = [self.word_to_idx.get(word, 0) for word in text][:self.max_len]
seq += [0] * (self.max_len - len(seq)) # 填充
return torch.tensor(seq), torch.tensor(label)
train_dataset = TextDataset(train_texts, train_labels, word_to_idx)
test_dataset = TextDataset(test_texts, test_labels, word_to_idx)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
4.2 训练代码
import torch.optim as optim
from tqdm import tqdm
def train_model(model, train_loader, test_loader, num_epochs=10, lr=0.001, device='cuda'):
optimizer = optim.Adam(model.parameters(), lr=lr)
criterion = nn.CrossEntropyLoss()
model.to(device)
for epoch in range(num_epochs):
model.train()
train_loss = 0.0
correct = 0
total = 0
for inputs, labels in tqdm(train_loader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
train_loss += loss.item()
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {train_loss/len(train_loader):.4f}, Accuracy: {correct/total:.4f}")
# 验证模型
evaluate_model(model, test_loader, device)
def evaluate_model(model, test_loader, device):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Validation Accuracy: {correct/total:.4f}")
5. 可视化 UI 界面
使用 PyQt5 创建一个简单的 GUI。
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QPushButton, QLabel
from PyQt5.QtGui import QPixmap
import sys
import matplotlib.pyplot as plt
from wordcloud import WordCloud
class App(QMainWindow):
def __init__(self, model, word_to_idx, label_encoder, max_len=50):
super().__init__()
self.setWindowTitle("中文情绪分类")
self.setGeometry(100, 100, 800, 600)
self.model = model
self.word_to_idx = word_to_idx
self.label_encoder = label_encoder
self.max_len = max_len
# UI 元素
self.text_edit = QTextEdit(self)
self.text_edit.setGeometry(50, 50, 700, 100)
self.btn_predict = QPushButton("预测", self)
self.btn_predict.setGeometry(50, 200, 150, 40)
self.btn_predict.clicked.connect(self.predict_sentiment)
self.label_result = QLabel(self)
self.label_result.setGeometry(50, 250, 700, 40)
def predict_sentiment(self):
text = self.text_edit.toPlainText()
tokens = tokenize(text)
seq = [self.word_to_idx.get(word, 0) for word in tokens][:self.max_len]
seq += [0] * (self.max_len - len(seq))
input_tensor = torch.tensor([seq]).to('cuda')
self.model.eval()
with torch.no_grad():
output = self.model(input_tensor)
_, predicted = torch.max(output, 1)
sentiment = self.label_encoder.inverse_transform(predicted.cpu().numpy())[0]
self.label_result.setText(f"预测情绪: {sentiment}")
if __name__ == "__main__":
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = SentimentModel(vocab_size, embed_dim=128, hidden_dim=256, output_dim=2, model_type="LSTM").to(device)
model.load_state_dict(torch.load("best_model.pth"))
app = QApplication(sys.argv)
window = App(model, word_to_idx, label_encoder)
window.show()
sys.exit(app.exec_())
同时具备可视化 UI 界面和训练结果可视化功能,我们可以分步骤进行。
以下是详细的代码实现:
1. 数据预处理
首先,我们需要对数据进行预处理,包括分词、构建词汇表等。
1.1 数据加载
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
# 加载数据
data = pd.read_csv("sentiment_data.csv")
# 分词并生成词汇表
def tokenize(text):
return list(jieba.cut(text))
data['tokens'] = data['text'].apply(tokenize)
# 构建词汇表
all_tokens = [token for tokens in data['tokens'] for token in tokens]
vocab = set(all_tokens)
word_to_idx = {word: idx + 1 for idx, word in enumerate(vocab)} # 0 留给填充
idx_to_word = {idx: word for word, idx in word_to_idx.items()}
# 转换标签为数值
label_encoder = LabelEncoder()
data['label'] = label_encoder.fit_transform(data['label'])
# 划分训练集和测试集
train_texts, test_texts, train_labels, test_labels = train_test_split(
data['tokens'], data['label'], test_size=0.2, random_state=42
)
2. 模型定义
定义一个支持 RNN、LSTM 和 GRU 的模型。
import torch
import torch.nn as nn
class SentimentModel(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim, model_type="LSTM"):
super(SentimentModel, self).__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
if model_type == "RNN":
self.rnn = nn.RNN(embed_dim, hidden_dim, batch_first=True)
elif model_type == "LSTM":
self.rnn = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
elif model_type == "GRU":
self.rnn = nn.GRU(embed_dim, hidden_dim, batch_first=True)
else:
raise ValueError("Unsupported model type")
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
embedded = self.embedding(x)
rnn_out, _ = self.rnn(embedded)
out = self.fc(rnn_out[:, -1, :]) # 取最后一个时间步的输出
return out
3. 数据加载器
定义数据加载器以方便批量处理数据。
from torch.utils.data import Dataset, DataLoader
class TextDataset(Dataset):
def __init__(self, texts, labels, word_to_idx, max_len=50):
self.texts = texts
self.labels = labels
self.word_to_idx = word_to_idx
self.max_len = max_len
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
text = self.texts[idx]
label = self.labels[idx]
seq = [self.word_to_idx.get(word, 0) for word in text][:self.max_len]
seq += [0] * (self.max_len - len(seq)) # 填充
return torch.tensor(seq), torch.tensor(label)
train_dataset = TextDataset(train_texts, train_labels, word_to_idx)
test_dataset = TextDataset(test_texts, test_labels, word_to_idx)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
4. 训练与评估
定义训练和评估函数。
import torch.optim as optim
from tqdm import tqdm
def train_model(model, train_loader, test_loader, num_epochs=10, lr=0.001, device='cuda'):
optimizer = optim.Adam(model.parameters(), lr=lr)
criterion = nn.CrossEntropyLoss()
model.to(device)
for epoch in range(num_epochs):
model.train()
train_loss = 0.0
correct = 0
total = 0
for inputs, labels in tqdm(train_loader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
train_loss += loss.item()
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {train_loss/len(train_loader):.4f}, Accuracy: {correct/total:.4f}")
# 验证模型
evaluate_model(model, test_loader, device)
def evaluate_model(model, test_loader, device):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Validation Accuracy: {correct/total:.4f}")
5. 可视化 UI 界面
使用 PyQt5 创建一个简单的 GUI。
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QPushButton, QLabel
from PyQt5.QtGui import QPixmap
import sys
import matplotlib.pyplot as plt
from wordcloud import WordCloud
class App(QMainWindow):
def __init__(self, model, word_to_idx, label_encoder, max_len=50):
super().__init__()
self.setWindowTitle("中文情绪分类")
self.setGeometry(100, 100, 800, 600)
self.model = model
self.word_to_idx = word_to_idx
self.label_encoder = label_encoder
self.max_len = max_len
# UI 元素
self.text_edit = QTextEdit(self)
self.text_edit.setGeometry(50, 50, 700, 100)
self.btn_predict = QPushButton("预测", self)
self.btn_predict.setGeometry(50, 200, 150, 40)
self.btn_predict.clicked.connect(self.predict_sentiment)
self.label_result = QLabel(self)
self.label_result.setGeometry(50, 250, 700, 40)
def predict_sentiment(self):
text = self.text_edit.toPlainText()
tokens = tokenize(text)
seq = [self.word_to_idx.get(word, 0) for word in tokens][:self.max_len]
seq += [0] * (self.max_len - len(seq))
input_tensor = torch.tensor([seq]).to('cuda')
self.model.eval()
with torch.no_grad():
output = self.model(input_tensor)
_, predicted = torch.max(output, 1)
sentiment = self.label_encoder.inverse_transform(predicted.cpu().numpy())[0]
self.label_result.setText(f"预测情绪: {sentiment}")
if __name__ == "__main__":
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = SentimentModel(len(word_to_idx) + 1, embed_dim=128, hidden_dim=256, output_dim=2, model_type="LSTM").to(device)
model.load_state_dict(torch.load("best_model.pth"))
app = QApplication(sys.argv)
window = App(model, word_to_idx, label_encoder)
window.show()
sys.exit(app.exec_())
更多推荐




所有评论(0)