文章目录[隐藏]
Eli5是一个 Python 库,它让我们可视化机器学习模型所做的预测,以更好地了解我们网络的性能。这可以帮助我们了解数据的哪些部分对预测有贡献,我们可以利用这些知识来改进我们的模型。它也可以帮助我们推广我们的模型。
Eli5主要提供机器学习库(Scikit-learn、XGBoost、CatBoost、LightGBM、lightning 等)的解释功能,对深度学习库支持有限。
本文首先从torchtext 模块中获取了IMDB评论数据集,然后将使用LIME来解释PyTorch文本分类网络。
步骤1:读取数据集
加载了 IMDB 数据集创建了数据加载器,数据加载器使用逐步过程返回矢量化数据。然后利用词频向量化方法来转换文本数据为数字。
importtorchimporttorchtextimporteli5# 训练和测试数据集都有 25k 文本评论。数据集的标签是“pos”(正面评论)和“neg”(负面评论)。train_dataset, test_dataset = torchtext.datasets.IMDB()fromtorchtext.dataimportget_tokenizerfromtorchtext.vocabimportbuild_vocab_from_iterator# 然后使用 torchtext.data 模块中可用的 get_tokenizer() 函数创建了分词器tokenizer = get_tokenizer("basic_english") categories = ["Negative","Positive"]
build_vocab_from_iterator() 函数会考虑整个文本语料库中的所有单词,这会创建一个非常大的词汇表。为了稍微减少词汇量,我们要求它考虑在文本语料库中出现至少 2 次的单词。
defbuild_vocab(datasets):fordatasetindatasets:for_, textindataset:## Please make a note that in dataset first item is target class and second item is text of sample.yieldtokenizer(text) vocab = build_vocab_from_iterator(build_vocab([train_dataset, test_dataset]), specials=["" ], min_freq=2) vocab.set_default_index(vocab["" ])
为了向量化输入文本数据,我们使用了 scikit-learn 提供的 CountVectorizer。我们已经使用在之前的单元格中创建的词汇表和分词器初始化了 CountVectorizer 实例。
fromsklearn.feature_extraction.textimportTfidfVectorizer, CountVectorizerfromtorch.utils.dataimportDataLoaderfromtorchtext.data.functionalimportto_map_style_dataset vectorizer = CountVectorizer(vocabulary=vocab.get_itos(), tokenizer=tokenizer)defvectorize_batch(batch):Y, X = list(zip(*batch))## Please make a Note that labels are first.X = vectorizer.transform(X).todense() Y = [0ifi=='neg'else1foriinY]returntorch.tensor(X, dtype=torch.float32), torch.tensor(Y) train_dataset, test_dataset = torchtext.datasets.IMDB() train_dataset, test_dataset = to_map_style_dataset(train_dataset), to_map_style_dataset(test_dataset) train_loader = DataLoader(train_dataset, batch_size=256, shuffle=True, collate_fn=vectorize_batch) test_loader = DataLoader(test_dataset, batch_size=256, collate_fn=vectorize_batch)
步骤2:定义文本分类模型
设计了一个包含 3 层的简单神经网络,用于对 IMDB 评论进行分类。三个密集层有 64、32 和 2 个输出单元。前两层将 relu 激活函数应用于输出。
fromtorchimportnnfromtorch.nnimportfunctionalasFclassTextClassifier(nn.Module):def__init__(self):super(TextClassifier, self).__init__() self.seq = nn.Sequential( nn.Linear(len(vocab),64), nn.ReLU(), nn.Linear(64,32), nn.ReLU(), nn.Linear(32,2),#nn.Linear(64, 4),)defforward(self, X_batch):returnself.seq(X_batch)
步骤3:训练模型
epochs初始化为 5,将学习率初始化为 0.0001。然后初始化了网络、交叉熵损失函数和 Adam 优化器。
defTrainModel(model, loss_fn, optimizer, train_loader, val_loader, epochs=10):foriinrange(1, epochs+1): losses = []forX, Yintqdm(train_loader): Y_preds = model(X) loss = loss_fn(Y_preds, Y) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() gc.collect() print("Train Loss : {:.3f}".format(torch.tensor(losses).mean())) CalcValLossAndAccuracy(model, loss_fn, val_loader)fromtorch.optimimportAdam epochs =5learning_rate =1e-4loss_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)
步骤4:评价模型精度
可以从结果中注意到,我们的模型具有约 89% 的准确率。如果我们尝试不同的网络架构,可以进一步提高准确性。
fromsklearn.metricsimportaccuracy_score, classification_report, confusion_matrix print("Test Accuracy : {}".format(accuracy_score(Y_actual, Y_preds))) print("nClassification Report : ") print(classification_report(Y_actual, Y_preds, target_names=["Negative","Positive"])) print("nConfusion Matrix : ") print(confusion_matrix(Y_actual, Y_preds))
Test Accuracy : 0.8896 Classification Report : precision recall f1-score support Negative 0.87 0.92 0.89 12500 Positive 0.91 0.86 0.89 12500 accuracy 0.89 25000 macro avg 0.89 0.89 0.89 25000 weighted avg 0.89 0.89 0.89 25000
步骤5:ELI5解释网络
创建了一个 TextExplainer 实例。它具有下面提到的我们可以调整的参数。
- n_samples - 此参数接受整数,指定将从 fit() 调用期间给定的原始输入样本生成的样本数,以训练我们的本地机器学习分类器。默认值为 5000。
- clf - 这是一个分类器,将使用为 LIME 算法生成的样本进行训练。LIME 算法训练本地 ML 算法来模仿我们的神经网络的行为。默认情况下,使用使用 SGD (SGDClassifier) 训练的弹性网络正则化的逻辑回归。
使用自定义的模型代替已有的分类器:
def predict_proba(X_docs): X_vect = torch.tensor(vectorizer.transform(X_docs).todense(), dtype=torch.float32) preds = text_classifier(X_vect) preds = F.softmax(preds, dim=-1).detach().numpy() preds = np.array([pred / pred.sum()forpredinpreds])returnpreds explainer.fit(X_test[0], predict_proba)
原始代码链接:https://coderzcolumn.com/tutorials/artificial-intelligence/eli5-lime-explain-pytorch-text-classification-network-predictions