基于Python+PyTorch的多概念商品评论匹配监督式NLP方案咨询
商品评论-概念多标签分类解决方案
这是典型的多标签文本分类任务,目标是为每条评论预测是否提及K个预设概念(输出N×K的布尔数组)。针对你有数百条标注数据、零样本模型效果不佳的情况,以下是基于Python和PyTorch的落地方案:
一、数据预处理
首先将标注数据整理成结构化格式,每条数据包含:评论文本、对应K个概念的0/1标签列表。
1. 定义数据集类
用PyTorch的Dataset封装数据,方便后续加载:
import torch import numpy as np from torch.utils.data import Dataset, DataLoader from transformers import AutoTokenizer class CommentConceptDataset(Dataset): def __init__(self, texts, labels, tokenizer, max_len=128): self.texts = texts self.labels = labels self.tokenizer = tokenizer self.max_len = max_len def __len__(self): return len(self.texts) def __getitem__(self, idx): text = str(self.texts[idx]) label = self.labels[idx] encoding = self.tokenizer( text, truncation=True, padding='max_length', max_length=self.max_len, return_tensors='pt' ) return { 'input_ids': encoding['input_ids'].flatten(), 'attention_mask': encoding['attention_mask'].flatten(), 'labels': torch.tensor(label, dtype=torch.float) }
2. 数据划分
将标注数据按8:1:1划分为训练集、验证集、测试集,确保各集合的概念分布均匀。
二、模型选择与定义
选择轻量且适合小样本微调的预训练模型,推荐DistilBERT(参数量仅为BERT的1/3,性能接近)或RoBERTa-base。模型结构为:预训练模型提取文本特征,接全连接层输出K个logits(对应K个概念的二分类预测)。
from transformers import AutoModel class ConceptClassifier(torch.nn.Module): def __init__(self, model_name, num_labels): super().__init__() self.bert = AutoModel.from_pretrained(model_name) self.dropout = torch.nn.Dropout(p=0.3) self.classifier = torch.nn.Linear(self.bert.config.hidden_size, num_labels) def forward(self, input_ids, attention_mask): outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask) cls_output = outputs.last_hidden_state[:, 0, :] # 取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>token的输出作为文本表征 cls_output = self.dropout(cls_output) logits = self.classifier(cls_output) return logits
三、训练与评估
1. 训练配置
# 初始化组件 model_name = 'distilbert-base-uncased' tokenizer = AutoTokenizer.from_pretrained(model_name) num_labels = 100 # 实际场景的概念数量 model = ConceptClassifier(model_name, num_labels) # 损失函数、优化器(多标签分类用BCEWithLogitsLoss更合适) loss_fn = torch.nn.BCEWithLogitsLoss() optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5) # 数据加载器(替换为你的真实数据) train_texts = ["Great color and sound quality...", "The build feels very durable...", ...] train_labels = [[1,1,0,0,...], [0,0,0,1,...], ...] # 对应100个概念的0/1列表 train_dataset = CommentConceptDataset(train_texts, train_labels, tokenizer) train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
2. 训练循环
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) num_epochs = 5 for epoch in range(num_epochs): model.train() total_loss = 0 for batch in train_loader: input_ids = batch['input_ids'].to(device) attention_mask = batch['attention_mask'].to(device) labels = batch['labels'].to(device) optimizer.zero_grad() logits = model(input_ids, attention_mask) loss = loss_fn(logits, labels) loss.backward() optimizer.step() total_loss += loss.item() avg_loss = total_loss / len(train_loader) print(f"Epoch {epoch+1}/{num_epochs}, Average Loss: {avg_loss:.4f}") # 验证环节(可选,用验证集监控模型泛化能力) model.eval() # 验证集逻辑与训练集类似,计算F1-score等指标
3. 评估指标
多标签分类常用Micro-F1和Macro-F1评估,用sklearn实现:
from sklearn.metrics import f1_score def evaluate(model, val_loader, device): model.eval() all_preds = [] all_labels = [] with torch.no_grad(): for batch in val_loader: input_ids = batch['input_ids'].to(device) attention_mask = batch['attention_mask'].to(device) labels = batch['labels'].to(device) logits = model(input_ids, attention_mask) preds = torch.sigmoid(logits).cpu().numpy() >= 0.5 # 阈值可根据验证集调整 all_preds.extend(preds) all_labels.extend(labels.cpu().numpy()) micro_f1 = f1_score(all_labels, all_preds, average='micro') macro_f1 = f1_score(all_labels, all_preds, average='macro') print(f"Micro-F1: {micro_f1:.4f}, Macro-F1: {macro_f1:.4f}") return micro_f1, macro_f1
四、结果输出
训练完成后,用模型预测所有评论,生成N×K的布尔numpy数组:
def predict_all_comments(model, texts, tokenizer, device, max_len=128): model.eval() predictions = [] with torch.no_grad(): for text in texts: encoding = tokenizer( text, truncation=True, padding='max_length', max_length=max_len, return_tensors='pt' ) input_ids = encoding['input_ids'].to(device) attention_mask = encoding['attention_mask'].to(device) logits = model(input_ids, attention_mask) pred = torch.sigmoid(logits).cpu().numpy()[0] >= 0.5 predictions.append(pred) return np.array(predictions, dtype=bool) # 示例调用 all_comments = ["Comment 1...", "Comment 2...", ...] result_array = predict_all_comments(model, all_comments, tokenizer, device) # result_array即为N×K的布尔numpy数组
五、优化建议
- 数据增强:对标注评论做同义词替换、随机裁剪、回译等,扩充训练数据,提升模型泛化能力。
- 阈值调整:根据验证集效果调整预测阈值(不一定是0.5),平衡精准率和召回率。
- 分层学习率:预训练模型部分用较小的学习率(如1e-5),全连接层用较大的学习率(如1e-4),避免预训练特征被破坏。
- 模型轻量化:如果部署资源有限,可使用
transformers提供的动态量化方法压缩模型体积。
内容的提问来源于stack exchange,提问作者Shrayani Mondal
相关产品推荐
相关产品推荐

