之前我看了一个关于“NLP的实践特性工程”的演讲。主要是关于LIME和SHAP在文本分类可解释性方面是如何工作的。
我决定写一篇关于它们的文章,因为它们很有趣、易于使用,而且视觉上很吸引人。
所有的 机器学习 模型都是在更高的维度上运行的,而不是在人脑可以直接看到的维度上运行的,这些机器学习模型都可以被称为黑盒模型,它可以归结为模型的可解释性。特别是在NLP领域中,特征的维数往往很大,说明特征的重要性变得越来越复杂。
LIME & SHAP不仅帮助我们向最终用户解释NLP模型的工作原理,而且帮助我们自己解释NLP模型是如何工作的。
利用 Stack Overflow 问题标签分类数据集,我们将构建一个多类文本分类模型,然后分别应用LIME和SHAP对模型进行解释。由于我们之前已经做过多次文本分类,所以我们将快速构建NLP模型,并着重于模型的可解释性。
数据预处理、特征工程和逻辑回归 import pandas as pd
import numpy as np
import sklearn
import sklearn.ensemble
import sklearn.metrics
from sklearn.utils import shuffle
from __future__ import print_function
from io import StringIO
import re
from bs4 import BeautifulSoup
from nltk.corpus import stopwords
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
import lime
from lime import lime_text
from lime.lime_text import LimeTextExplainer
from sklearn.pipeline import make_pipeline
df = pd.read_csv('stack-overflow-data.csv')
df = df[pd.notnull(df['tags'])]
df = df.sample(frac=0.5, random_state=99).reset_index(drop=True)
df = shuffle(df, random_state=22)
df = df.reset_index(drop=True)
df['class_label'] = df['tags'].factorize()[0]
class_label_df = df[['tags', 'class_label']].drop_duplicates().sort_values('class_label')
label_to_id = dict(class_label_df.values)
id_to_label = dict(class_label_df[['class_label', 'tags']].values)
REPLACE_BY_SPACE_RE = re.compile('[/(){}[]|@,;]')
BAD_SYMBOLS_RE = re.compile('[^0-9a-z #+_]')
# STOPWORDS = set(stopwords.words('english'))
def clean_text(text):
"""
text: a string
return: modified initial string
"""
text = BeautifulSoup(text, "lxml").text # HTML decoding. BeautifulSoup's text attribute will return a string stripped of any HTML tags and metadata.
text = text.lower() # lowercase text
text = REPLACE_BY_SPACE_RE.sub(' ', text) # replace REPLACE_BY_SPACE_RE symbols by space in text. substitute the matched string in REPLACE_BY_SPACE_RE with space.
text = BAD_SYMBOLS_RE.sub('', text) # remove symbols which are in BAD_SYMBOLS_RE from text. substitute the matched string in BAD_SYMBOLS_RE with nothing.
# text = ' '.join(word for word in text.split() if word not in STOPWORDS) # remove stopwors from text
return text
df['post'] = df['post'].apply(clean_text)
list_corpus = df["post"].tolist()
list_labels = df["class_label"].tolist()
X_train, X_test, y_train, y_test = train_test_split(list_corpus, list_labels, test_size=0.2, random_state=40)
vectorizer = CountVectorizer(analyzer='word',token_pattern=r'w{1,}', ngram_range=(1, 3), stop_words = 'english', binary=True)
train_vectors = vectorizer.fit_transform(X_train)
test_vectors = vectorizer.transform(X_test)
logreg = LogisticRegression(n_jobs=1, C=1e5)
logreg.fit(train_vectors, y_train)
pred = logreg.predict(test_vectors)
accuracy = accuracy_score(y_test, pred)
precision = precision_score(y_test, pred, average='weighted')
recall = recall_score(y_test, pred, average='weighted')f1 = f1_score(y_test, pred, average='weighted')print("accuracy = %.3f, precision = %.3f, recall = %.3f, f1 = %.3f" % (accuracy, precision, recall, f1))
我们现在目标并不是产生最好的结果。我想尽快进入LIME & SHAP,这就是接下来发生的事情。
用LIME解释文本预测
从现在开始,这是有趣的部分。下面的代码片段主要是从LIME教程中借来的。 c = make_pipeline(vectorizer, logreg)
class_names=list(df.tags.unique())
explainer = LimeTextExplainer(class_names=class_names)
idx = 1877
exp = explainer.explain_instance(X_test[idx], c.predict_proba, num_features=6, labels=[4, 8])
print('Document id: %d' % idx)
print('Predicted class =', class_names[logreg.predict(test_vectors[idx]).reshape(1,-1)[0,0]])
print('True class: %s' % class_names[y_test[idx]])
我们在测试集中随机选择一个文档,它恰好是一个标记为sql的文档,我们的模型也预测它是sql。使用这个文档,我们为标签4 (sql)和标签8 (python)生成解释。 print ('Explanation for class %s' % class_names[4])
print (''.join(map(str, exp.as_list(label=4)))) print ('Explanation for class %s' % class_names[8])
print (''.join(map(str, exp.as_list(label=8))))
很明显,这个文档对标签sql有最高的解释。我们还注意到正负号与特定的标签有关,例如单词”sql”对类sql是正的,而对类python是负的,反之亦然。
我们要为这个文档生成2类标签顶部。 exp = explainer.explain_instance(X_test[idx], c.predict_proba, num_features=6, top_labels=2)
print(exp.available_labels())
它给出了sql和python。 exp.show_in_notebook(text=False)
让我来解释一下这种可视化:
1. 对于本文档,词 “sql”对于类sql具有最高的正分数。
2. 我们的模型预测该文档应该标记为sql,其概率为100%。
3. 如果我们从文档中删除word”sql”,我们期望模型预测label sql的概率为100% – 65% = 35%。
4. 另一方面,单词”sql”对于类python是负面的,我们的模型已经了解到单词”range”对于类python有一个小的正面得分。
我们可能想放大并研究类sql的解释,以及文档本身。 exp.show_in_notebook(text=y_test[idx], labels=(4,))
使用SHAP解释文本预测
以下过程是从本教程中学到的。 「链接」 from sklearn.preprocessing import MultiLabelBinarizer
import tensorflow as tf
from tensorflow.keras.preprocessing import text
import keras.backend.tensorflow_backend as K
K.set_session
import shap
tags_split = [tags.split(',') for tags in df['tags'].values]
tag_encoder = MultiLabelBinarizer()
tags_encoded = tag_encoder.fit_transform(tags_split)
num_tags = len(tags_encoded[0])
train_size = int(len(df) * .8)
y_train = tags_encoded[: train_size]
y_test = tags_encoded[train_size:]
class TextPreprocessor(object):
def __init__(self, vocab_size):
self._vocab_size = vocab_size
self._tokenizer = None
def create_tokenizer(self, text_list):
tokenizer = text.Tokenizer(num_words = self._vocab_size)
tokenizer.fit_on_texts(text_list)
self._tokenizer = tokenizer
def transform_text(self, text_list):
text_matrix = self._tokenizer.texts_to_matrix(text_list)
return text_matrix
VOCAB_SIZE = 500
train_post = df['post'].values[: train_size]
test_post = df['post'].values[train_size: ]
processor = TextPreprocessor(VOCAB_SIZE)
processor.create_tokenizer(train_post)
X_train = processor.transform_text(train_post)
X_test = processor.transform_text(test_post)
def create_model(vocab_size, num_tags):
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(50, input_shape = (VOCAB_SIZE,), activation='relu'))
model.add(tf.keras.layers.Dense(25, activation='relu'))
model.add(tf.keras.layers.Dense(num_tags, activation='sigmoid'))
model.compile(loss = 'binary_crossentropy', optimizer='adam', metrics = ['accuracy'])
return model
model = create_model(VOCAB_SIZE, num_tags)
model.fit(X_train, y_train, epochs = 2, batch_size=128, validation_split=0.1)
print('Eval loss/accuracy:{}'.format(model.evaluate(X_test, y_test, batch_size = 128))) 模型训练完成后,我们使用前200个训练文档作为背景数据集进行集成,并创建一个SHAP explainer对象。 我们在测试集的子集上获得各个预测的属性值。 将索引转换为单词。 使用SHAP的summary_plot方法来显示影响模型预测的主要特性。 attrib_data = X_train[:200]
explainer = shap.DeepExplainer(model, attrib_data)
num_explanations = 20
shap_vals = explainer.shap_values(X_test[:num_explanations])
words = processor._tokenizer.word_index
word_lookup = list()
for i in words.keys():
word_lookup.append(i)
word_lookup = [''] + word_lookup
shap.summary_plot(shap_vals, feature_names=word_lookup, class_names=tag_encoder.classes_) 单词”want”是我们模型使用的最大信号词,对类jquery预测贡献最大。 单词”php”是我们模型使用的第四大信号词,当然对PHP类贡献最大。 另一方面,单词”php”可能对另一个类有负面信号,因为它不太可能在python文档中看到单词”php”。
关于LIME & SHAP的机器学习可解释性,还有很多需要学习的地方。我只介绍了一小部分NLP。其余的可以在Github上找到。 NLP-with-Python/LIME_SHAP_StackOverflow.ipynb at master · susanli2016/NLP-with-Python · GitHub
来自:AI中国
本文采用「CC BY-SA 4.0 CN」协议转载自互联网、仅供学习交流,内容版权归原作者所有,如涉作品、版权和其他问题请给「 我们 」留言处理。
本文转载自数据派THU
作者:MOHD SANAD ZAKI RIZVI
本文主要介绍了: TensorFlow.js (deeplearn.js)使我们能够在浏览器中构建 机器学习 和 深度学习 模型,而无需任何复杂的安装步骤。 TensorFlow.js的两个组件——Core API和Layer API。 了解如何构建一个很棒的使用Tensorflow.js对网络摄像头中的图像进行分类的模型。
概述
你最喜欢用什么工具来编写机器学习模型?数据科学家们对这个永恒的问题会给出各种不同的答案。一些人喜欢RStudio,另一些人更喜欢Jupyter Notebooks。我绝对属于后者。
所以,当我第一次遇到TensorFlow.js(以前是deeplearn.js)时,我的心都要炸开了。在浏览器中构建机器学习模型?使用JavaScript?听起来好得令人难以置信!
超过43亿人使用网络浏览器——约占世界人口的55%。——维基百科(2019年3月)
谷歌的TensorFlow.js不仅将机器学习引入浏览器中,使机器学习大众化,而且对于经常使用JavaScript的开发人员来说,它也是一个完美的机器学习门户。
我们的网络浏览器是最容易访问的平台之一。这就是为什么构建不仅能够训练机器学习模型而且能够在浏览器本身中“学习”或“迁移学习”的应用程序是有意义的。
在本文中,我们将首先了解使用TensorFlow.js的重要性及其它的不同组件。然后,我们将深入讨论使用TensorFlow.js在浏览器中构建我们自己的机器学习模型。然后我们将构建一个应用程序,来使用计算机的网络摄像头检测你的身体姿势!
如果你是TensorFlow的新手,你可以在下面文章中了解更多: TensorFlow 101: Understanding Tensors and Graphs to get you Started with Deep Learning Introduction to Implementing Neural Networks using TensorFlow
目录
一、为什么你应该使用TensorFlow.js?
1.1 使用网络摄像头在浏览器中进行图像分类
1.2 TensorFlow.js的特征
二、了解浏览器中的机器学习
2.1 Core API:使用Tensors工作
2.2 Layer API:像Keras一样构建模型
三、利用谷歌的预训练模型:PoseNet
为什么要使用TensorFlow.js
我将用一种独特的方法来回答这个问题。我不会深入研究TensorFlow.js的理论方面,也不会列出它为什么是一个如此不可思议的工具。
相反,我将简单地向你展示如果不使用TensorFlow.js将会错过什么。那么,让我们在5分钟内构建一个应用程序,来使用你的网络摄像头对图像进行分类。没错——我们将直接进入代码部分!
这是最好的部分——你不需要安装任何东西来做这个!只要一个文本编辑器和一个网络浏览器即可。下面的动图展示了我们将要构建的应用程序:
这多酷啊!我在浏览器里几分钟就完成了。那么,让我们看一下步骤和代码,以帮助你在Web浏览器中构建自己的图像分类模型。
使用网络摄像头在浏览器中构建图像分类模型
打开你选择的文本编辑器并创建一个文件index.html。将以下代码保存于此文件内:
image_classification
接下来,创建另一个文件index.js并在其中编写以下代码: let mobilenet; let video; let label = ”; // when model is ready make predictions function modelReady() { console.log(‘Model is ready!!!’); mobilenet.predict(gotResults); } function gotResults(error, results) { if (error) { console.error(error); } else { label = results[0].className; // loop the inference by calling itself mobilenet.predict(gotResults); } } // setup function function setup() { createCanvas(640, 550); // ml5 to create video capture video = createCapture(VIDEO); video.hide(); background(0); // load the MobileNet and apply it on video feed mobilenet = ml5.imageClassifier(‘MobileNet’, video, modelReady); } function draw() { background(0); // show video image(video, 0, 0); fill(255); textSize(32); // show prediction label text(label, 10, height – 20); }
保存这两个文件,然后在谷歌Chrome或Mozilla Firefox等浏览器中打开index.html文件。就是这样!你现在已经创建了一个可以使用你的网络摄像头在浏览器本身实时分类图像的应用程序!下面是它在我的计算机上的样子:
视频连接:
https://s3-ap-south-1.amazonaws.com/av-blog-media/wp-content/uploads/2019/05/mobilenet_demo.mp4_=1
在这个例子中需要注意的要点: 在上面的例子中,我们使用了一个预先训练的图像分类模型MobileNet(https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html) 我们使用ml5.js(https://ml5js.org/)一个构建在TensorFlow之上的库。它将MobileNet模型加载到浏览器中,并对视频提要执行推理。 我们还利用P5.js(https://p5js.org/)库来处理视频输入并在视频本身上显示标签。
我不需要在电脑上安装任何东西。这个例子应该适用于任何现代系统,不管它是Linux、Windows还是MacOS——这就是使用JavaScript在web上构建模型的强大功能。
现在,让我们看看TensorFlow.js提供的强大功能,以及如何利用它们在浏览器中部署机器学习模型。
TensorFlow.js的特征
TensorFlow.js是一个库,用于JavaScript开发和训练ML模型,并在浏览器或Node.js上部署。
TensorFlow.js提供了许多的功能来供我们使用。
它是TensorFlow在JavaScript中的扩展,JavaScript是我们在互联网上使用的几乎所有网站、浏览器或应用程序逻辑背后的编程语言。JavaScript和 Python 一样用途广泛,所以使用它来开发机器学习模型给我们带来了很多好处: 如果ML模型是用web语言编写的,则更容易部署。 由于所有主流浏览器都支持JavaScript,所以你可以无处不在地使用它,而不必担心平台类型或其他兼容性问题。对于你的用户也是如此。 TensorFlow.js是一个客户端库,这意味着它可以在用户的浏览器中训练或运行ML模型。这减轻了与数据隐私有关的任何担忧。 在你的客户端上运行实时推断可使你的应用程序更具交互性,因为它们可以立即响应用户输入(例如我们前面构建的webcam应用程序)。
TensorFlow.js以其当前的形式提供了以下主要功能: 浏览器中的机器学习:你可以使用TensorFlow.js在浏览器中创建和训练ML模型。 谷歌的预训练模型:TensorFlow.js配备了一套由谷歌预训练的模型,用于对象检测、图像分割、语音识别、文本毒性分类等任务。 迁移学习:你可以通过对已经训练过的模型的部分进行再训练来执行转移学习,比如TensorFlow.js中的MobileNet。 部署python模型:使用Keras或TensorFlow训练的模型可以很容易地导入浏览器/使用TensorFlow.js的部署。
在本文中,我们将关注前两个功能。在本系列的第二部分(即将推出!)中,我们将讨论如何在Python中转移学习和部署我们的模型。
浏览器中的机器学习
TensorFlow.js提供了两种方法来训练模型(非常类似于TensorFlow): 第一种方法是使用Core API使用低级张量操作来定义模型。 第二种方法是使用Layers API定义模型,类似于Keras。
让我们通过几个例子来理解这两种方法。毕竟,学习一个概念最好的方法就是把它付诸实践!
首先,设置你的HTML文件:
在你的电脑上建立一个新的index.html文件,并在其中编写以下代码: Tensorflow.js Core API
–>
我们创建了一个基本的HTML页面,并从云URL中加载了Tensorflow.js(第7行)。
关于安装TensorFlow.js(deeplearn.js)的说明:
由于TensorFlow.js是为浏览器而设计的,所以安装和使用TensorFlow.js最简单的方法就是根本不安装它。你可以简单地从HTML中的URL加载它即可。
如果你想在本地工作怎么办呢?实际上,你可以在Jupyter Notebook中使用TensorFlow.js,就像你在Python或R中通常做的那样。这是一个适合每个人的解决方案!
这种本地方法稍微长一些,并且需要一些时间,所以本文不会使用它。如果你确实想学习如何操作,可以从为Jupyter安装ijavascript内核开始。下面是我的Jupyter Notebook的截图:
现在,使用TensorFlow.js的推荐方法是使用库的官方URL直接加载它。你只需将以下行添加到HTML文件中:
完成了!这真的很简单。
Core API:使用Tensors工作
Core API与TensorFlowCore非常相似,我们可以使用低级张量运算和线性代数定义模型。
如果我们想要构建自定义模型或想要从头开始构建神经网络,这非常有用。让我们举一个在浏览器中使用张量的例子。
首先在index.html文件中的 Tensorflow.js Core API
–>