本文为学习Datawhale 2021.9组队学习情感分析笔记
原学习文档地址:https://github.com/datawhalechina/team-learning-nlp/tree/master/EmotionalAnalysis
主要写需要注意的点。
详细情况见原学习文档task4
多分类和之前的流程类似
1 数据读入
使用了一个六分类的文本数据集,与之前不同的是:
第一,我们不需要在 LABEL 字段中设置 dtype。在处理多类问题时,PyTorch 期望标签被数字化为LongTensor。
第二,这次我们使用的是TREC数据集而不是IMDB数据集。 fine_grained 参数允许我们使用细粒度标签(其中有50个类)或不使用(在这种情况下它们将是6个类)。
import torch
from torchtext.legacy import data
from torchtext.legacy import datasets
import random
SEED = 1234
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True
TEXT = data.Field(tokenize = 'spacy',tokenizer_language = 'en_core_web_sm')
LABEL = data.LabelField()
train_data, test_data = datasets.TREC.splits(TEXT, LABEL, fine_grained=False)
train_data, valid_data = train_data.split(random_state = random.seed(SEED))
接下来,我们将构建词汇表。 由于这个数据集很小(只有约 3800 个训练样本),它的词汇量也非常小(约 7500 个不同单词,即one-hot向量为7500维),这意味着我们不需要像以前一样在词汇表上设置“max_size”。
TEXT.build_vocab(train_data,
vectors = "glove.6B.100d",
unk_init = torch.Tensor.normal_)
LABEL.build_vocab(train_data)
2 模型
使用了之前的CNN模型,唯一不同的是fc的输出不是2维,变成了6维
import torch.nn as nn
import torch.nn.functional as F
class CNN(nn.Module):
def __init__(self, vocab_size, embedding_dim, n_filters, filter_sizes, output_dim,
dropout, pad_idx):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.convs = nn.ModuleList([
nn.Conv2d(in_channels = 1,
out_channels = n_filters,
kernel_size = (fs, embedding_dim))
for fs in filter_sizes
])
self.fc = nn.Linear(len(filter_sizes) * n_filters, output_dim)
self.dropout = nn.Dropout(dropout)
def forward(self, text):
#text = [sent len, batch size]
text = text.permute(1, 0)
#text = [batch size, sent len]
embedded = self.embedding(text)
#embedded = [batch size, sent len, emb dim]
embedded = embedded.unsqueeze(1)
#embedded = [batch size, 1, sent len, emb dim]
conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs]
#conv_n = [batch size, n_filters, sent len - filter_sizes[n] +1] 此处之前少了一个+1
pooled = [F.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]
#pooled_n = [batch size, n_filters]
cat = self.dropout(torch.cat(pooled, dim = 1))
#cat = [batch size, n_filters * len(filter_sizes)]
return self.fc(cat)
INPUT_DIM = len(TEXT.vocab)
EMBEDDING_DIM = 100
N_FILTERS = 100
FILTER_SIZES = [2,3,4]
OUTPUT_DIM = len(LABEL.vocab)
DROPOUT = 0.5
PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]
model = CNN(INPUT_DIM, EMBEDDING_DIM, N_FILTERS, FILTER_SIZES, OUTPUT_DIM, DROPOUT, PAD_IDX)
有个疑问,怎么能知道在哪里要加unsqueeze和suqueeze呢?出错了debug后才知道的吗?
3 损失函数
BCEWithLogitsLoss
一般用来做二分类,而 CrossEntropyLoss
用来做多分类,CrossEntropyLoss
对我们的模型输出执行 softmax 函数,损失由该函数和标签之间的 *交叉熵 * 给出。
criterion = nn.CrossEntropyLoss()
4 准确度的计算
def categorical_accuracy(preds, y):
"""
Returns accuracy per batch, i.e. if you get 8/10 right, this returns 0.8, NOT 8
"""
top_pred = preds.argmax(1, keepdim = True)
correct = top_pred.eq(y.view_as(top_pred)).sum()
acc = correct.float() / y.shape[0]
return acc
axis =1 跨列,axis = 0 跨行
view_as和view的用法
5 其他
如何实现模型融合,后面补!