文章目录[隐藏]
Eli5是一个 Python 库,它让我们可视化机器学习模型所做的预测,以更好地了解我们网络的性能。这可以帮助我们了解数据的哪些部分对预测有贡献,我们可以利用这些知识来改进我们的模型。它也可以帮助我们推广我们的模型。
Eli5主要提供机器学习库(Scikit-learn、XGBoost、CatBoost、LightGBM、lightning 等)的解释功能,对深度学习库支持有限。
本文首先从torchtext 模块中获取了IMDB评论数据集,然后将使用LIME来解释PyTorch文本分类网络。
步骤1:读取数据集
加载了 IMDB 数据集创建了数据加载器,数据加载器使用逐步过程返回矢量化数据。然后利用词频向量化方法来转换文本数据为数字。
import torch import torchtext import eli5 # 训练和测试数据集都有 25k 文本评论。数据集的标签是“pos”(正面评论)和“neg”(负面评论)。 train_dataset, test_dataset = torchtext.datasets.IMDB() from torchtext.data import get_tokenizer from torchtext.vocab import build_vocab_from_iterator # 然后使用 torchtext.data 模块中可用的 get_tokenizer() 函数创建了分词器 tokenizer = get_tokenizer("basic_english")
categories = ["Negative", "Positive"]
build_vocab_from_iterator() 函数会考虑整个文本语料库中的所有单词,这会创建一个非常大的词汇表。为了稍微减少词汇量,我们要求它考虑在文本语料库中出现至少 2 次的单词。
def build_vocab(datasets): for dataset in datasets:
for _, text in dataset: ## Please make a note that in dataset first item is target class and second item is text of sample. yield tokenizer(text)
vocab = build_vocab_from_iterator(build_vocab([train_dataset, test_dataset]), specials=["<UNK>"], min_freq=2)
vocab.set_default_index(vocab["<UNK>"])
为了向量化输入文本数据,我们使用了 scikit-learn 提供的 CountVectorizer。我们已经使用在之前的单元格中创建的词汇表和分词器初始化了 CountVectorizer 实例。
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)) ## Please make a Note that labels are first. X = vectorizer.transform(X).todense()
Y = [0 if i=='neg' else 1 for i in Y]
return torch.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 激活函数应用于输出。
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), 64),
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 2),
#nn.Linear(64, 4), )
def forward(self, X_batch): return self.seq(X_batch)
步骤3:训练模型
epochs初始化为 5,将学习率初始化为 0.0001。然后初始化了网络、交叉熵损失函数和 Adam 优化器。
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()
gc.collect()
print("Train Loss : {:.3f}".format(torch.tensor(losses).mean()))
CalcValLossAndAccuracy(model, loss_fn, val_loader)
from torch.optim import Adam
epochs = 5 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)
步骤4:评价模型精度
可以从结果中注意到,我们的模型具有约 89% 的准确率。如果我们尝试不同的网络架构,可以进一步提高准确性。
from sklearn.metrics import accuracy_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() for pred in preds])
return preds
explainer.fit(X_test[0], predict_proba)
原始代码链接:https://coderzcolumn.com/tutorials/artificial-intelligence/eli5-lime-explain-pytorch-text-classification-network-predictions