pytorch实现用CNN和LSTM对文本进行分类方式

1. 前言

本文将介绍如何使用PyTorch实现用CNN和LSTM对文本进行分类的方法。这个任务通常被认为是自然语言处理(NLP)领域中的一个经典问题,它可以用于许多不同的应用程序,例如电子邮件分类、情感分析和垃圾信息过滤等。

2. 数据预处理

2.1 数据集介绍

我们选择了一个已有的情感分析数据集IMDB影评数据集。该数据集包含50,000个来自Internet Movie Database(IMDB)的影评。对于所有的样本,我们需要将它们转换成数字形式,并将其用于训练我们的模型。

2.2 文本预处理

我们首先需要将影评转换成数字形式。这个过程被称为文本预处理。我们将使用Python的NLTK库来实现它。

2.3 分词

首先,我们将每个影评文本分成单词。我们可以使用NLTK的word_tokenize()函数来实现它:

import nltk

nltk.download('punkt')

from nltk.tokenize import word_tokenize

text = 'This is a sentence.'

tokens = word_tokenize(text)

print(tokens)

# ['This', 'is', 'a', 'sentence', '.']

2.4 移除停用词

接下来,我们需要移除停用词。停用词是在文本中频繁出现但通常不包含足够信息的单词。例如,“the”、“a”和“an”都是停用词。

我们将使用NLTK的stopwords列表来移除停用词。

nltk.download('stopwords')

from nltk.corpus import stopwords

stop_words = set(stopwords.words('english'))

filtered_tokens = []

for token in tokens:

if token.lower() not in stop_words:

filtered_tokens.append(token)

print(filtered_tokens)

# ['sentence', '.']

在这个例子中,“This”、“is”和“a”都被移除了,因为它们是停用词。

2.5 将单词转换为数字

现在我们需要将每个单词转换成数字形式,以便我们可以将它们用于训练我们的模型。我们将使用PyTorch的torchtext库来实现它。

首先,我们需要创建一个词汇表。词汇表将单词映射到数字。我们使用Field类来定义每个文本列的字段类型:

import torchtext

tokenizer = lambda x: x.split()

TEXT = torchtext.data.Field(sequential=True, tokenize=tokenizer, lower=True)

LABEL = torchtext.data.Field(sequential=False, use_vocab=False)

train, test = torchtext.datasets.IMDB(split=('train', 'test'), fields=(('text', TEXT), ('label', LABEL)))

TEXT.build_vocab(train, vectors="glove.6B.100d")

在这个例子中,我们使用了预训练的GloVe词向量来初始化词汇表。这个过程将创建一个包含训练数据中所有单词的词汇表,其中每个单词都映射到一个独一无二的数字。

2.6 创建迭代器

最后,我们需要创建迭代器,以便我们可以在训练期间从数据集中获取数据批次。我们将使用BucketIterator类来实现它。

BATCH_SIZE = 32

train_iterator, test_iterator = torchtext.data.BucketIterator.splits(

(train, test),

batch_size=BATCH_SIZE,

sort_key=lambda x: len(x.text),

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

在这个例子中,我们创建了两个迭代器:一个训练迭代器和一个测试迭代器。这些迭代器将采样我们的训练集和测试集,并将它们分成一批。

3. 模型架构

3.1 网络结构

我们使用一个简单的网络结构,它由CNN和LSTM组成。这个结构可以在自然语言处理(NLP)领域中得到广泛的应用,特别是在情感分析中。

我们首先使用一个卷积层来提取文本特征。这个卷积层的输出被馈送到一个LSTM层,以学习文本序列的时序信息。最后,我们将LSTM的输出馈送到一个全连接层,以获得最终的分类结果。

我们使用PyTorch建立该网络结构。具体代码如下:

import torch.nn as nn

class TextCNNLSTM(nn.Module):

def __init__(self, input_dim, embedding_dim, num_filters, filter_sizes, hidden_dim, output_dim, dropout):

super().__init__()

self.embedding = nn.Embedding(input_dim, embedding_dim)

self.convs = nn.ModuleList([

nn.Conv2d(in_channels=1, out_channels=num_filters, kernel_size=(fs, embedding_dim)) for fs in filter_sizes

])

self.lstm = nn.LSTM(embedding_dim, hidden_dim, bidirectional=True)

self.fc = nn.Linear(hidden_dim * 2, output_dim)

self.dropout = nn.Dropout(dropout)

def forward(self, text):

embedded = self.embedding(text)

embedded = embedded.unsqueeze(1)

# [batch_size, num_filters, max_sent_len - filter_sizes[n] + 1, 1]

conved = [nn.functional.relu(conv(embedded)).squeeze(3) for conv in self.convs]

# [batch_size, num_filters, max_sent_len - filter_sizes[n] + 1]

pooled = [nn.functional.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]

# [batch_size, embedding_dim, max_sent_len]

lstm_input = embedded.permute(2, 0, 1)

_, (final_hidden_state, _) = self.lstm(lstm_input)

hidden = self.dropout(torch.cat((final_hidden_state[-2, :, :], final_hidden_state[-1, :, :]), dim=1))

return self.fc(hidden)

在这个例子中,我们定义了一个名为TextCNNLSTM的类。这个类继承了nn.Module类,它是所有神经网络模型的基类。我们使用__init__()方法定义网络结构。我们在该方法中定义了一个嵌入层、卷积层、LSTM层和全连接层。我们还定义了一个dropout层,用于减少过拟合。

我们在forward()方法中实现了网络结构的前向传递。我们首先需要将输入序列转换成嵌入。接下来,我们将卷积层的输出馈送到LSTM层 中,最后,我们将LSTM的输出馈送到全连接层中,以获得最终的分类结果。

3.2 模型训练

我们将使用PyTorch来训练我们的模型。具体代码如下:

import torch.optim as optim

INPUT_DIM = len(TEXT.vocab)

EMBEDDING_DIM = 100

NUM_FILTERS = 100

FILTER_SIZES = [3, 4, 5]

HIDDEN_DIM = 256

OUTPUT_DIM = 1

DROPOUT = 0.5

model = TextCNNLSTM(INPUT_DIM, EMBEDDING_DIM, NUM_FILTERS, FILTER_SIZES, HIDDEN_DIM, OUTPUT_DIM, DROPOUT)

optimizer = optim.Adam(model.parameters(), lr=1e-4)

criterion = nn.BCEWithLogitsLoss()

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

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()

accuracy = correct.sum() / len(correct)

return accuracy

def train(model, iterator, optimizer, criterion):

epoch_loss = 0

epoch_acc = 0

model.train()

for batch in iterator:

optimizer.zero_grad()

text, labels = batch.text, batch.label

text = text.permute(1, 0)

predictions = model(text).squeeze(1)

loss = criterion(predictions, labels.float())

acc = binary_accuracy(predictions, labels.float())

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:

text, labels = batch.text, batch.label

text = text.permute(1, 0)

predictions = model(text).squeeze(1)

loss = criterion(predictions, labels.float())

acc = binary_accuracy(predictions, labels.float())

epoch_loss += loss.item()

epoch_acc += acc.item()

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

在训练前,我们需要定义一些重要的函数。首先,我们需要定义binary_accuracy()函数来计算分类的准确性。其次,我们需要定义train()函数和evaluate()函数来分别训练模型和评估模型的性能。

在train()函数中,我们使用实例迭代器中的每个批次来进行训练。对于每个批次,我们将其输入到模型中,并计算预测值。然后,我们计算损失和准确性,并对模型参数进行梯度更新。

在evaluate()函数中,我们使用与train()函数相同的步骤来评估模型的性能。不过,在这个函数中,我们不会对模型参数进行梯度更新。

3.3 模型评估

在训练模型后,我们需要评估其性能。我们可以使用二元交叉熵损失函数来度量模型的性能。具体代码如下:

N_EPOCHS = 10

best_test_loss = float('inf')

for epoch in range(N_EPOCHS):

train_loss, train_acc = train(model, train_iterator, optimizer, criterion)

test_loss, test_acc = evaluate(model, test_iterator, criterion)

if test_loss < best_test_loss:

best_test_loss = test_loss

torch.save(model.state_dict(), 'text_cnn_lstm.pt')

print(f'Epoch: {epoch+1:02}')

print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')

print(f'\t Val. Loss: {test_loss:.3f} | Val. Acc: {test_acc*100:.2f}%')

在这个例子中,我们训练模型10次,并在每个周期结束时记录训练期间的性能。我们使用if语句来检查模型的表现是否优于先前的最佳表现,并在测试集上保存模型的权重。

4. 总结

在本文中,我们介绍了如何使用PyTorch实现用CNN和LSTM对文本进行分类的方法。我们首先介绍了数据集、文本预处理和数据迭代器。接下来,我们定义了一个CNN和LSTM结构的模型,并使用PyTorch训练和评估了它。最后,我们讨论了如何使用训练好的模型进行预测。

需要注意的是,本文仅介绍了如何使用PyTorch实现用CNN和LSTM对文本进行分类的方法。在实际应用中,我们可能需要更复杂的模型、更多的数据预处理步骤和更长的训练周期。本文提供的代码只是一个示例,在实际应用中可能需要进一步进行优化。

后端开发标签