概要
モデルの判定結果の説明方法について解説します。
はじめに
クライアントビジネスにおいても、モデルの根拠を求められる場合が多いので、その手法をご紹介したいと思います。
どうしてもAIは、入力から出力までがブラックボックス化してしまいがちですが、
AIの判定根拠をホワイトボックスに近づける作業になります。
どのようにホワイトボックス化するかというと、表データと画像系でそれぞれやり方が異なります。
表データの場合、下記を使用してモデルの判定の要因となった説明変数の重要度から判定根拠を示すことが出来ます。
- 回帰係数/Feature Importance
- ロジスティック回帰やアンサンブル系で、各説明変数の重みを取り出す。
- SHAP/LIME
- 判別結果のスコアをもとにロジスティック回帰モデルを疑似的に作成し、回帰係数を取り出す
- PeermutationImportance
- 各説明変数を1つずつ除外し、全体の精度にどのくらい影響があったのかどうかを数値化する。
画像データの場合は、判定根拠が強い部分を強調し画像化することで、
判定根拠を説明することが出来ます。
手法としては、
- Grad-cam
- DeepLearningのモデルのみ利用可能。判定結果を逆伝搬しパラメータの変化が大きさで影響度をみる
があります。
実装
SHAP(表データ)
irisデータセットで学習したロジスティック回帰モデルもとに、
SHAPで判別結果の可視化をします。
まずは、モデル作成とSHAPの初期設定
import shap import sklearn X_train,X_test,Y_train,Y_test = train_test_split(*shap.datasets.iris(), test_size=0.2, random_state=0) linear_lr = sklearn.linear_model.LogisticRegression() linear_lr.fit(X_train, Y_train) print_accuracy(linear_lr.predict) # explain all the predictions in the test set explainer = shap.KernelExplainer(linear_lr.predict_proba, X_train) shap_values = explainer.shap_values(X_test shap.initjs()
個別の結果確認
どの特徴量が判定結果に影響したのかを可視化します。
sample = 17 #explain 17th instance in the data set labels_pd = labels.as_data_frame() actual = labels_pd.iloc[sample].values[0] prediction = predictions_pd.iloc[sample]['predict'] print("Prediction for ",sample,"th instance is ",prediction," whereas its actual value is ",actual) shap.force_plot(explainer.expected_value[prediction], shap_values[prediction][sample,:], df.iloc[sample])
複数の結果確認
for idx in range(0, len(class_names)): print(class_names[idx]) shap.force_plot(explainer.expected_value[idx], shap_values[idx], df, link="logit")
モデル全体の確認
分類クラス別にどの特徴量が効いているのかを可視化します。
shap.summary_plot(shap_values, features.as_data_frame(), plot_type="bar")
特徴量別にどのクラスに影響を与えたかを可視化します。
for i in range(0, len(class_names)): current_class = class_names[i] print("Feature importances for ",current_class) shap.summary_plot(shap_values[i], features.as_data_frame(), plot_type="bar")
SHAP(画像データ)
Kerasで実装した、画像判別モデルにたいして、モデルがどこに着目したかヒートマップで表示します。
from keras.applications.vgg16 import VGG16 from keras.applications.vgg16 import preprocess_input import keras.backend as K import numpy as np import json import shap # load pre-trained model and choose two images to explain model = VGG16(weights='imagenet', include_top=True) X,y = shap.datasets.imagenet50() to_explain = X[[39,41]] # load the ImageNet class names url = "https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json" fname = shap.datasets.cache(url) with open(fname) as f: class_names = json.load(f) # explain how the input to the 7th layer of the model explains the top two classes def map2layer(x, layer): feed_dict = dict(zip([model.layers[0].input], [preprocess_input(x.copy())])) return K.get_session().run(model.layers[layer].input, feed_dict) e = shap.GradientExplainer( (model.layers[7].input, model.layers[-1].output), map2layer(X, 7), local_smoothing=0 # std dev of smoothing noise ) shap_values,indexes = e.shap_values(map2layer(to_explain, 7), ranked_outputs=2) # get the names for the classes index_names = np.vectorize(lambda x: class_names[str(x)][1])(indexes) # plot the explanations shap.image_plot(shap_values, to_explain, index_names)
Permutation Importance
上で作成した、回帰モデルの結果を使用してPermutationImportanceを確認します。
import eli5 from eli5.sklearn import PermutationImportance perm = PermutationImportance(linear_lr,random_state=2019) perm.fit(X_test,y_test) eli5.show_weights(perm,feature_names=iris.feature_names) # show importance eli5.show_weights(perm,feature_names=iris.feature_names) # show dataframe eli5.explain_weights_df(perm,feature_names=iris.feature_names)
おわりに
PermutationImportanceは、相関係数が高い特徴量のペアが存在によって、係数の結果に大きく影響するので前もって相関行列で確認する必要があります。
Grad-CAMは、実装がめんどくさいので、SHAPが手っ取り早いですね。