首先来看一下模型结构。
这是LSTM+Attention结构在aspect-level情感分类最早的应用。模型比较简单,输入是sentence和特定aspect,输出是sentence在这个aspect下的情感极性。我们先将Word Respresentation和Aspect Embedding连接后输入到LSTM得到隐藏向量,再将隐藏向量和Aspect Embedding连接后做一次attention,最后把结果输出到全连接层即可。
接下来是具体的实现。
导入包
import torch
import torch.nn as nn
import torch.nn.functional as F
import pandas as pd
import os
from torch.nn import init
from torchtext import data
from torchtext.vocab import Vectors
from torchtext.vocab import GloVe
import time
数据预处理
数据集是SemEval 2014 task4里的,源数据是XML格式,需要先做一些处理。
SemEval 2014数据集预处理:Python xml.etree.cElementTree解析XML文件.
现在的数据结构如下,其中text已经做过分词去停用词之类的处理。
我们用torchtext库处理数据。
torchtext预处理流程
- 定义Field:声明如何处理数据
from nltk.tokenize import word_tokenize
text = data.Field(sequential=True,lower=True,tokenize=word_tokenize)
aspect = data.Field(sequential=False,lower=True)
label = data.Field(sequential=False)
一般的文本分类只需要处理text和label两个字段,这里aspect也是要处理的。
- 定义Dataset:得到数据集,此时数据集里每一个样本是一个经过 Field声明的预处理 预处理后的wordlist
train, val = data.TabularDataset.splits(path='data/',
skip_header=True,
train='train.tsv',
validation='test.tsv',
format='tsv',
fields=[('text', text),
('aspect', aspect),
('polarity', label)])
cache = 'data/.vector_cache'
fields可简单理解为每一列数据和Field对象的绑定关系,参数顺序要和数据集中的字段顺序一致。
我在这一步遇到了一个很奇妙的bug,数据集是CSV格式时建立vocab怎么都不对,后来改成TSV格式就好了。
- 建立vocab:在这一步建立词汇表,词向量
if not os.path.exists(cache):
os.mkdir(cache)
vectors = Vectors(name='data/glove.6B/glove.6B.300d.txt')
text.build_vocab(train, val, vectors=vectors)
aspect.build_vocab(train, val, vectors=vectors)
label.build_vocab(train, val)
text_vocab_size = len(text.vocab)
aspect_vocab_size = len(aspect.vocab)
text_vector=text.vocab.vectors
aspect_vector=aspect.vocab.vectors
建好之后可以打印出来text中出现频率最高的10个词来看一下。
text.vocab.freqs.most_common(10)
print(text.vocab.vectors.shape)
[4083,300]是词汇表的大小,表示一共有4083个词,词向量维度是300。
- 构造迭代器:构造迭代器,用来分批次训练模型
batch_size=128
train_iter, val_iter = data.Iterator.splits(
(train,