一个基于用户课程评论数据,应用Bert和TextCNN进行大学生学习资源推荐系统的详细方案、实验过程和示例代码。
详细方案
1. 系统整体架构
- 数据收集:收集大学生对课程的评论数据,这些数据可以来自学校的在线学习平台、课程评价网站等。
- 数据预处理:对收集到的评论数据进行清洗、分词、标注等操作,将文本数据转换为适合模型输入的格式。
- 特征提取:使用Bert模型对课程评论进行特征提取,将文本转换为向量表示。
- 分类模型:使用TextCNN模型对课程评论进行分类,根据评论的情感倾向和主题,将课程分为不同的类别。
- 推荐算法:根据用户的历史评论数据和课程分类结果,为用户推荐相关的学习资源。
2. 数据预处理
- 清洗数据:去除评论中的特殊字符、HTML标签、停用词等。
- 分词:使用中文分词工具(如jieba)对评论进行分词。
- 标注数据:根据评论的情感倾向和主题,为每条评论标注相应的标签。
3. 特征提取
- Bert模型:使用预训练的Bert模型对课程评论进行特征提取,将文本转换为固定长度的向量表示。
4. 分类模型
- TextCNN模型:使用TextCNN模型对课程评论进行分类,根据评论的情感倾向和主题,将课程分为不同的类别。
5. 推荐算法
- 基于内容的推荐:根据用户的历史评论数据和课程分类结果,为用户推荐相关的学习资源。
实验过程
1. 数据收集
从学校的在线学习平台、课程评价网站等收集大学生对课程的评论数据。
2. 数据预处理
- 使用Python的正则表达式库和jieba分词工具对评论数据进行清洗和分词。
- 根据评论的情感倾向和主题,为每条评论标注相应的标签。
3. 特征提取
- 使用Hugging Face的transformers库加载预训练的Bert模型,对课程评论进行特征提取。
4. 分类模型训练
- 使用PyTorch构建TextCNN模型,将Bert提取的特征作为输入,对课程评论进行分类。
- 使用训练集对TextCNN模型进行训练,使用验证集对模型进行评估和调优。
5. 推荐算法实现
- 根据用户的历史评论数据和课程分类结果,为用户推荐相关的学习资源。
6. 实验评估
- 使用测试集对推荐系统进行评估,计算准确率、召回率、F1值等指标。
实验代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from transformers import BertTokenizer, BertModel
import jieba
import re
# 数据预处理
def clean_text(text):
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
return text
def tokenize_text(text):
return jieba.lcut(text)
# 自定义数据集类
class CourseReviewDataset(Dataset):
def __init__(self, reviews, labels, tokenizer, max_length):
self.reviews = reviews
self.labels = labels
self.tokenizer = tokenizer
self.max_length = max_length
def __len__(self):
return len(self.reviews)
def __getitem__(self, idx):
review = self.reviews[idx]
label = self.labels[idx]
encoding = self.tokenizer.encode_plus(
review,
add_special_tokens=True,
max_length=self.max_length,
padding='max_length',
truncation=True,
return_tensors='pt'
)
input_ids = encoding['input_ids'].flatten()
attention_mask = encoding['attention_mask'].flatten()
return {
'input_ids': input_ids,
'attention_mask': attention_mask,
'labels': torch.tensor(label, dtype=torch.long)
}
# TextCNN模型
class TextCNN(nn.Module):
def __init__(self, input_dim, num_filters, filter_sizes, num_classes):
super(TextCNN, self).__init__()
self.convs = nn.ModuleList([
nn.Conv2d(in_channels=1,
out_channels=num_filters,
kernel_size=(fs, input_dim))
for fs in filter_sizes
])
self.fc = nn.Linear(len(filter_sizes) * num_filters, num_classes)
def forward(self, x):
x = x.unsqueeze(1)
conved = [nn.functional.relu(conv(x)).squeeze(3) for conv in self.convs]
pooled = [nn.functional.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]
cat = torch.cat(pooled, dim=1)
return self.fc(cat)
# 训练模型
def train_model(model, dataloader, optimizer, criterion, device):
model.train()
total_loss = 0
for batch in dataloader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
optimizer.zero_grad()
outputs = model(input_ids, attention_mask)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
return total_loss / len(dataloader)
# 评估模型
def evaluate_model(model, dataloader, criterion, device):
model.eval()
total_loss = 0
correct = 0
total = 0
with torch.no_grad():
for batch in dataloader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids, attention_mask)
loss = criterion(outputs, labels)
total_loss += loss.item()
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = correct / total
return total_loss / len(dataloader), accuracy
# 主函数
def main():
# 超参数设置
max_length = 128
num_filters = 100
filter_sizes = [3, 4, 5]
num_classes = 5
batch_size = 32
num_epochs = 10
learning_rate = 1e-4
# 加载数据
reviews = ["这门课程非常有趣", "老师讲得很清楚", "课程内容很实用"]
labels = [1, 1, 1]
# 数据预处理
reviews = [clean_text(review) for review in reviews]
reviews = [' '.join(tokenize_text(review)) for review in reviews]
# 加载Bert分词器和模型
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
bert_model = BertModel.from_pretrained('bert-base-chinese')
# 划分数据集
train_size = int(0.8 * len(reviews))
train_reviews = reviews[:train_size]
train_labels = labels[:train_size]
test_reviews = reviews[train_size:]
test_labels = labels[train_size:]
# 创建数据集和数据加载器
train_dataset = CourseReviewDataset(train_reviews, train_labels, tokenizer, max_length)
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataset = CourseReviewDataset(test_reviews, test_labels, tokenizer, max_length)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 初始化TextCNN模型
textcnn_model = TextCNN(bert_model.config.hidden_size, num_filters, filter_sizes, num_classes)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(textcnn_model.parameters(), lr=learning_rate)
# 设备设置
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
textcnn_model.to(device)
# 训练模型
for epoch in range(num_epochs):
train_loss = train_model(textcnn_model, train_dataloader, optimizer, criterion, device)
test_loss, test_accuracy = evaluate_model(textcnn_model, test_dataloader, criterion, device)
print(f'Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}')
if __name__ == '__main__':
main()
代码说明
- 数据预处理:使用
clean_text
函数清洗评论数据,使用tokenize_text
函数对评论进行分词。 - 自定义数据集类:
CourseReviewDataset
类用于将评论数据转换为适合模型输入的格式。 - TextCNN模型:
TextCNN
类定义了TextCNN模型的结构。 - 训练和评估函数:
train_model
函数用于训练模型,evaluate_model
函数用于评估模型。 - 主函数:
main
函数实现了整个实验过程,包括数据加载、预处理、模型初始化、训练和评估。