初识IMDB分类

IMDB文本分类

案例为最基本的分本分类——情感分析,其中采用IMDB(电影影评)作为数据集。
IMDB,收录了400多万部电影,数据集共有50000项,训练测试五五开,标签为正面评价或者负面评价。
可以从Kaggle官网搜索并下载IMDB电影数据集(imdbmovies)

多的不说,开始代码部分

先将需要的包导入。

import torch
import torch.nn as nn
import torch.optim as optim
from torchtext import data
from torchtext import datasets
import random

首先我们需要torchtext这个库,因为不是pytorch自带,所以需要自己下载。

pip install torchtext

torchtext.data定义了Field的类,他可以用来定义数据读取。
这里定义了两个Field,分别用于文本和标签。

TEXT = data.Field(tokenize='spacy', tokenizer_language='en_core_web_sm')
LABEL = data.LabelField(dtype=torch.float)

我们采用torch.dataset下载IMDB数据集,并将数据集划分。

train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
train_data, valid_data = train_data.split(random_state=random.seed(SEED))
print(f'number of training examples:{len(train_data)}')
print(f'number of training examples:{len(test_data)}')
print(f'number of training examples:{len(valid_data)}')

这里的显示划分结果为
各个数据集个数
下面开始构建词表,把单词mapping到index。这里使用最大为25000个词,且下载glove.6B.100d为词向量。

TEXT.build_vocab(train_data, max_size=25000, vectors="glove.6B.100d", unk_init=torch.Tensor.normal_ )
LABEL.build_vocab(train_data)
print(f'Unique tokens in TEXT vocabulary: {len(TEXT.vocab)}')
print(f'Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}')

打印结果如下,TEXT的词表为25000个词加上unk和pad,分别表示为未知词和填充词。LABEL词表为两个,POS和NEG,即为积极影评和消极影评。
在这里插入图片描述
开始训练预处理,我们将使用GPU来跑这个模型,再定义一个64的batch,再用BucketIterator将所有文本的词替换成词的索引。

BATCH_SIZE = 64
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

train_iterator,valid_iterator,test_iterator = data.BucketIterator.splits(
    (train_data,valid_data,test_data),
    batch_size=BATCH_SIZE,
    device=device)

我们创建一个batch并显示batch的结果。

bacth = next(iter(valid_iterator))
print(bacth.text)
print(bacth.label)

结果如下,文本数据已转换为向量,标签也是0/1形式
在这里插入图片描述
定义网络模型。模型采用word averageing模型,将每个单词通过embedding投射成词向量,然后将每一句话的词向量做个平均,将平均向量传入Linear做分类。

import torch.nn.functional as F
import torch.nn as nn
class WordAVGModel(nn.Module):
    def __init__(self,vocab_size,embedding_size,output_size,pad_idx):
        super(WordAVGModel,self).__init__()
        self.embedding=nn.Embedding(vocab_size,embedding_size,padding_idx=pad_idx)
        self.linear = nn.Linear(embedding_size,output_size)
        
    def forward(self,text):
        embedded = self.embedding(text) #[seq_len, batch_size,embedding_size]
        embedded = embedded.permute(1,0,2) #[bacth,seq_len,embedding_size] 
        pooled = F.avg_pool2d(embedded,(embedded.shape[1],1)).squeeze(1)#batch,1,embedding
        return self.linear(pooled)

设置一些模型需要的参数

VOCAB_SIZE=len(TEXT.vocab)
EMBEDDING_SIZE = 100
OUTPUT_SIZE = 1
PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]

model = WordAVGModel(VOCAB_SIZE,EMBEDDING_SIZE,OUTPUT_SIZE,PAD_IDX)

模型结构如下
在这里插入图片描述
定义损失函数优化器等。

optimizer = optim.Adam(model.parameters())
criterion = nn.BCEWithLogitsLoss() #binaryCrossEntropy 二分类
model = model.to(device)
criterion = criterion.to(device)

定义一个计算精度的函数。通过预测值是否等于真实值进行计算(注意精度)

def binary_accuracy(preds,y):
    rounded_preds = torch.round(torch.sigmoid(preds))
    correct = (rounded_preds == y).float()
    acc = correct.sum()/len(correct)
    return acc

定义训练及测试过程(两者其实差不多)

def train(model,iterator,optimizer,criterion):
    epoch_loss = 0.
    epoch_acc = 0.
    model.train()
    
    for batch in iterator:       
        predictions = model(batch.text).squeeze(1)
        #print(predictions.shape,batch.label.shape)
        loss = criterion(predictions,batch.label)
        acc = binary_accuracy(predictions,batch.label)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        epoch_loss+=loss.item()
        epoch_acc +=acc.item() 
        
    return epoch_loss / len(iterator), epoch_acc / len(iterator)

def evaluate(model,iterator,criterion):
    epoch_loss = 0.
    epoch_acc = 0.
    model.eval()
    with torch.no_grad():
        for batch in iterator:
            optimizer.zero_grad()
            predictions = model(batch.text).squeeze(1)
            loss = criterion(predictions,batch.label)
            acc = binary_accuracy(predictions,batch.label)

            epoch_loss+=loss.item() 
            epoch_acc +=acc.item()
            

        return epoch_loss / len(iterator), epoch_acc / len(iterator)

开始训练,这里将训练精度高的模型保存下来。

N_EPOCHS = 10
best_valid_loss = float('inf')

for epoch in range(N_EPOCHS):
    train_loss,train_acc = train(model,train_iterator,optimizer,criterion)
    valid_loss,valid_acc = evaluate(model,valid_iterator,criterion)
    
    if valid_loss < best_valid_loss:
        best_valid_loss = valid_loss
        torch.save(model.state_dict(),'wordavg_model.pt')
        
    print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')
    print(f'\t Val. Loss: {valid_loss:.3f} |  Val. Acc: {valid_acc*100:.2f}%')

训练结果如下
在这里插入图片描述
然后将我们保存的模型导出

model.load_state_dict(torch.load('wordavg_model.pt'))

可以开始测试我们自己的句子。这里将句子进行一些处理,让它转为向量,在进行维度上加1,这个1相当于我们的batch,不然送不到网络当中去。

import spacy
nlp = spacy.load('en_core_web_sm')

def predict_sentiment(sentence):
    tokenized =[tok.text for tok in nlp.tokenizer(sentence)]
    indexed = [TEXT.vocab.stoi[t] for t in tokenized]
    tensor = torch.LongTensor(indexed).to(device)
    tensor = tensor.unsqueeze(1)
    pred = torch.sigmoid(model(tensor))
    return pred.item()

调用函数

print(predict_sentiment("This film is super-inspirational and sweet--mostly because it's true。"))
print(predict_sentiment('This film is great'))
print(predict_sentiment('This film is terrible'))

这里得到的结果为
在这里插入图片描述
前两个句子都是正面的评价,所有值会接近1也就是POS,而负面评价的值很小,接近0,则为NEG.

本文采用了很简单的网络模型,没有用RNN、LSTM这些网络结构(因为我还不是很会),可能有很多问题,望指正。

参考链接
https://blog.csdn.net/bryant_meng/article/details/81214649?ops_request_misc=&request_id=&biz_id=102&utm_source=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0
https://github.com/bentrevett/pytorch-sentiment-analysis/blob/master/2%20-%20Upgraded%20Sentiment%20Analysis.ipynb

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值