PyTorch实现文本分类(非常详细)
要使用 PyTorch 实现文本分类,可以执行以下步骤:
本节将设计一个简单的网络来对文本文档进行分类。将使用 torchtext 模块提供的 AG NEWS 数据集。除此之外,还将使用 torchtext 中提供的词汇构建和其他实用程序。
首先,加载 torchtext 提供的 AG NEWS 数据集。该数据集包含 4 个不同新闻类别的文本文档。数据集分为训练数据集和测试数据集。
然后,用来自训练数据集和测试数据集的数据表征(Token)填充词汇表。通过数据 get_tokenizer() 方法从 torchtext.data 模块获得第一个初始化的分词器。初始化一个简单的分词器,用于分隔单词和标点符号。
初始化分词器后,使用 torchtext.vocab 模块中提供的 build_vocab_from_iterator() 函数填充词汇表。该函数以迭代器作为输入,每次调用迭代器时,迭代器都会返回一个表征列表。我们创建了一个迭代器作为一个简单的函数,它以数据集列表作为输入。然后,它循环遍历每个数据集及其文本示例,产生使用分词器为每个示例生成的表征列表。还要求函数使用 <UNK> 表征作为特殊表征,词汇表中不存在的表征将被映射到该表征。
接下来,创建将在训练过程中使用的训练和测试数据加载程序。创建批处理大小为256的数据加载程序。两个数据加载程序都接收可调用的 collate_fn 参数。此函数负责对一批文本文档进行向量化。实现代码如下:
该网络有 3 个线性层,分别具有 128、64 和 4 个输出单元。我们已经将 relu 激活,应用于前两个线性层的输出。该网络采用 PyTorch 的 Sequential API 进行设计。实现代码如下:
对于每个回合,它使用训练数据加载器分批循环训练数据,该加载器为每个批次返回矢量化数据及其标签。对于每个批次,我们执行前向传递网络以进行预测、计算损失(使用预测和实际目标标签)、计算梯度并更新网络参数。该函数还记录每个批次的损失,并在每个回合结束时打印平均训练损失。我们还创建了另一个辅助函数,它以输入模型、损失函数和验证数据加载器来计算验证损失和准确性。
将回合数初始化为 8,将学习率初始化为 0.0001。然后,初始化交叉熵损失、文本分类器网络和 Adam 优化器。最后,用必要的参数调用训练程序来进行训练。通过查看每个回合结束时的损失和准确性值,可以得出结论,我们的模型在文本分类任务中做得很好。可以执行各种超参数微调,以进一步提高网络的性能。
- 预处理文本数据:包括将文本标记为单个单词或子单词,将其转换为数字表示,并创建词汇表;
- 准备数据集:将数据集拆分为训练集、验证集和测试集。将文本数据转换为张量或数值表示,这些张量或数值表示可以输入模型中;
- 设计模型架构:定义用于文本分类的神经网络架构。通常包括使用词嵌入来表示单词,然后是一个或多个层,如卷积层或递归层,最后是用于实现分类的完全连接层;
- 训练模型:使用训练集来训练模型,包括正向传播、使用合适的损失函数(如交叉熵)计算损失,以及使用优化器(如 Adam 或 SGD)反向传播以更新模型的参数;
- 评估模型:使用验证集来评估训练模型的性能。计算准确性、精确度、召回率或 F1 分数等指标,以评估模型的性能;
- 测试模型:使用测试集评估模型在没见过的数据上的性能。这将使用户了解模型的泛化能力。
本节将设计一个简单的网络来对文本文档进行分类。将使用 torchtext 模块提供的 AG NEWS 数据集。除此之外,还将使用 torchtext 中提供的词汇构建和其他实用程序。
本节的主要目的是介绍如何使用 PyTorch 和 torchtext 模块设计文本分类网络。
准备数据集
接下来逐步对文本数据集进行向量化,为神经网络做好准备。将文本数据转换为神经网络所需的实数向量列表。为了做到这一点,首先用数据表征填充词汇表,然后创建数据加载程序,每次调用时返回向量化数据。使用词频方法来向量化数据。首先,加载 torchtext 提供的 AG NEWS 数据集。该数据集包含 4 个不同新闻类别的文本文档。数据集分为训练数据集和测试数据集。
from torch.utils.data import DataLoader train_dataset, test_dataset = torchtext.datasets.AG_NEWS() target_classes = ["World", "Sports", "Business", "Sci/Tec"]
然后,用来自训练数据集和测试数据集的数据表征(Token)填充词汇表。通过数据 get_tokenizer() 方法从 torchtext.data 模块获得第一个初始化的分词器。初始化一个简单的分词器,用于分隔单词和标点符号。
初始化分词器后,使用 torchtext.vocab 模块中提供的 build_vocab_from_iterator() 函数填充词汇表。该函数以迭代器作为输入,每次调用迭代器时,迭代器都会返回一个表征列表。我们创建了一个迭代器作为一个简单的函数,它以数据集列表作为输入。然后,它循环遍历每个数据集及其文本示例,产生使用分词器为每个示例生成的表征列表。还要求函数使用 <UNK> 表征作为特殊表征,词汇表中不存在的表征将被映射到该表征。
from torchtext.data import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator
tokenizer = get_tokenizer("basic_english")
def build_vocab(datasets):
for dataset in datasets:
for _, text in dataset:
yield tokenizer(text)
vocab = build_vocab_from_iterator(
build_vocab([train_dataset, test_dataset]),
specials=["<UNK>"]
)
vocab.set_default_index(vocab["<UNK>"])
接下来,创建将在训练过程中使用的训练和测试数据加载程序。创建批处理大小为256的数据加载程序。两个数据加载程序都接收可调用的 collate_fn 参数。此函数负责对一批文本文档进行向量化。实现代码如下:
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from torch.utils.data import DataLoader
from torchtext.data.functional import to_map_style_dataset
vectorizer = CountVectorizer(
vocabulary=vocab.get_itos(),
tokenizer=tokenizer
)
def vectorize_batch(batch):
Y, X = list(zip(*batch))
X = vectorizer.transform(X).todense()
return torch.tensor(X, dtype=torch.float32), torch.tensor(Y) - 1
train_dataset, test_dataset = torchtext.datasets.AG_NEWS()
train_dataset, test_dataset = to_map_style_dataset(train_dataset), to_map_style_dataset(test_dataset)
train_loader = DataLoader(
train_dataset,
batch_size=256,
collate_fn=vectorize_batch
)
test_loader = DataLoader(
test_dataset,
batch_size=256,
collate_fn=vectorize_batch
)
定义网络
接下来使用 PyTorch 设计一个简单的线性层神经网络,使用它对文本文档进行分类。该网络将矢量化数据作为输入并返回预测。该网络有 3 个线性层,分别具有 128、64 和 4 个输出单元。我们已经将 relu 激活,应用于前两个线性层的输出。该网络采用 PyTorch 的 Sequential API 进行设计。实现代码如下:
from torch import nn
from torch.nn import functional as F
class TextClassifier(nn.Module):
def __init__(self):
super(TextClassifier, self).__init__()
self.seq = nn.Sequential(
nn.Linear(len(vocab), 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 4)
)
def forward(self, X_batch):
return self.seq(X_batch)
text_classifier = TextClassifier()
for X, Y in train_loader:
Y_preds = text_classifier(X)
print(Y_preds.shape)
break
训练网络
接下来将对前面定义的网络进行训练。为了训练网络,设计了一个简单的函数,该函数将在调用时执行训练。该函数将模型、损失函数、优化器、训练数据加载程序、验证数据加载程序和回合数作为输入,然后执行训练循环若干次。对于每个回合,它使用训练数据加载器分批循环训练数据,该加载器为每个批次返回矢量化数据及其标签。对于每个批次,我们执行前向传递网络以进行预测、计算损失(使用预测和实际目标标签)、计算梯度并更新网络参数。该函数还记录每个批次的损失,并在每个回合结束时打印平均训练损失。我们还创建了另一个辅助函数,它以输入模型、损失函数和验证数据加载器来计算验证损失和准确性。
from tqdm import tqdm
from sklearn.metrics import accuracy_score
import gc
def CalcValLossAndAccuracy(model, loss_fn, val_loader):
with torch.no_grad():
Y_shuffled, Y_preds, losses = [], [], []
for X, Y in val_loader:
preds = model(X)
loss = loss_fn(preds, Y)
losses.append(loss.item())
Y_shuffled.append(Y)
Y_preds.append(preds.argmax(dim=-1))
Y_shuffled = torch.cat(Y_shuffled)
Y_preds = torch.cat(Y_preds)
print("Valid Loss : {:.3f}".format(torch.tensor(losses).mean()))
print("Valid Acc : {:.3f}".format(accuracy_score(Y_shuffled.detach().numpy(),
Y_preds.detach().numpy())))
def TrainModel(model, loss_fn, optimizer, train_loader, val_loader, epochs=10):
for i in range(1, epochs + 1):
losses = []
for X, Y in tqdm(train_loader):
Y_preds = model(X)
loss = loss_fn(Y_preds, Y)
losses.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("Train Loss : {:.3f}".format(torch.tensor(losses).mean()))
CalcValLossAndAccuracy(model, loss_fn, val_loader)
将回合数初始化为 8,将学习率初始化为 0.0001。然后,初始化交叉熵损失、文本分类器网络和 Adam 优化器。最后,用必要的参数调用训练程序来进行训练。通过查看每个回合结束时的损失和准确性值,可以得出结论,我们的模型在文本分类任务中做得很好。可以执行各种超参数微调,以进一步提高网络的性能。
from torch.optim import Adam epochs = 8 learning_rate = 1e-4 loss_fn = nn.CrossEntropyLoss() text_classifier = TextClassifier() optimizer = Adam(text_classifier.parameters(), lr=learning_rate) TrainModel(text_classifier, loss_fn, optimizer, train_loader, test_loader, epochs)
ICP备案:
公安联网备案: