Объяснение выходов CNN (Keras) с помощью LIME - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь объяснить выходы моего сверточного нейронного сетевого блока в Керасе с помощью LIME .

Моя нейронная сеть является многоклассовым классификатором текста, где каждый класс независим. Таким образом, текст может содержать класс 1 и 2 или только 1 и т. Д. Пятый «класс» (нет) для случаев, когда в тексте нет классов.

Однако, хотя мне удалось объяснить случай двоичной классификации с помощью Keras и Lime, я просто не могу получить случай с несколькими классами с независимыми классами. Первая помощь была найдена здесь :

Однако мой код не работает, я получаю внутренние ошибки от Lime, такие как: «ValueError: Найдены входные переменные с непоследовательным количеством выборок: [5000, 100000]»

from lime.lime_text import LimeTextExplainer, TextDomainMapper
explainer = LimeTextExplainer(class_names=encoder.classes_)


chosen_text = 2

def flatten_predict(i):
    global model   
    # catch single string inputs and convert them to list
    if i.__class__ != list:
        i = [i]
        print("## Caught and transformed single string.")
    # list for predictions
    predStorage = []
    # loop through input list and predict
    for textInput in i:
        textInput = preprocess(textInput)
        textInput = make_predictable(textInput)
        pred = model.predict(textInput)
        pred = np.append(pred, 1-pred, axis=1)
        # control output of function

        predStorage.extend(pred)
    return np.asarray(predStorage)


def get_predict_proba_fn_of_class(label):
    """assuming wrapped_predict outputs an (n, d) array of prediction probabilities, where d is the number of labels"""
    def rewrapped_predict(strings): 
        preds = flatten_predict(strings)[:, np.where(flatten_predict(strings)==label)].reshape(-1, 1)
        ret = np.asarray(np.hstack([(1 - preds), preds]))
        return ret

    return rewrapped_predict

str = 'Ein sehr freundlicher Arzt.'
preds = flatten_predict(str)
labels_to_explain = preds# 
print(labels_to_explain)

explanation_for_label = {}
for label in labels_to_explain:
    wrapped = get_predict_proba_fn_of_class(label)
    explanation_for_label[label] = explainer.explain_instance(str, wrapped)
    explanation_for_label[label].show_in_notebook()

Сообщение об ошибке:

ValueError                                Traceback (most recent call last)
<ipython-input-26-8df61aaa23f4> in <module>()
     53 for label in labels_to_explain:
     54     wrapped = get_predict_proba_fn_of_class(label)
---> 55     explanation_for_label[label] = explainer.explain_instance(str, wrapped)
     56     explanation_for_label[label].show_in_notebook()
     57 

/usr/local/lib/python3.6/dist-packages/lime/lime_text.py in explain_instance(self, text_instance, classifier_fn, labels, top_labels, num_features, num_samples, distance_metric, model_regressor)
    405                 data, yss, distances, label, num_features,
    406                 model_regressor=model_regressor,
--> 407                 feature_selection=self.feature_selection)
    408         return ret_exp
    409 

/usr/local/lib/python3.6/dist-packages/lime/lime_base.py in explain_instance_with_data(self, neighborhood_data, neighborhood_labels, distances, label, num_features, feature_selection, model_regressor)
    155                                                weights,
    156                                                num_features,
--> 157                                                feature_selection)
    158 
    159         if model_regressor is None:

/usr/local/lib/python3.6/dist-packages/lime/lime_base.py in feature_selection(self, data, labels, weights, num_features, method)
    104                 n_method = 'highest_weights'
    105             return self.feature_selection(data, labels, weights,
--> 106                                           num_features, n_method)
    107 
    108     def explain_instance_with_data(self,

/usr/local/lib/python3.6/dist-packages/lime/lime_base.py in feature_selection(self, data, labels, weights, num_features, method)
     78             clf = Ridge(alpha=0, fit_intercept=True,
     79                         random_state=self.random_state)
---> 80             clf.fit(data, labels, sample_weight=weights)
     81             feature_weights = sorted(zip(range(data.shape[0]),
     82                                          clf.coef_ * data[0]),

/usr/local/lib/python3.6/dist-packages/sklearn/linear_model/ridge.py in fit(self, X, y, sample_weight)
    678         self : returns an instance of self.
    679         """
--> 680         return super(Ridge, self).fit(X, y, sample_weight=sample_weight)
    681 
    682 

/usr/local/lib/python3.6/dist-packages/sklearn/linear_model/ridge.py in fit(self, X, y, sample_weight)
    489 
    490         X, y = check_X_y(X, y, ['csr', 'csc', 'coo'], dtype=_dtype,
--> 491                          multi_output=True, y_numeric=True)
    492 
    493         if ((sample_weight is not None) and

/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in check_X_y(X, y, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, warn_on_dtype, estimator)
    764         y = y.astype(np.float64)
    765 
--> 766     check_consistent_length(X, y)
    767 
    768     return X, y

/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in check_consistent_length(*arrays)
    233     if len(uniques) > 1:
    234         raise ValueError("Found input variables with inconsistent numbers of"
--> 235                          " samples: %r" % [int(l) for l in lengths])
    236 
    237 

ValueError: Found input variables with inconsistent numbers of samples: [5000, 100000]

Кто-нибудь знает, что я делаю не так? Я почти уверен, что это связано с форматом ввода .

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Мне удалось решить проблему сейчас. Вот решение для тех, кто может быть в этом заинтересован.

Короче говоря, хитрость заключалась в том, чтобы выбрать правильные столбцы из массивов в get_predict_proba_fn_of_class. Несмотря на то, что у меня было пять независимых рейтинговых оценок, которые не в сумме составляли один, мне пришлось добавить отрицательные оценки для каждой оценки классификации каждого ярлыка в новом столбце (например, для 0,67 я добавил 1-0,67), а затем выбрать исходный и новый столбец.

from lime.lime_text import LimeTextExplainer, TextDomainMapper
print(encoder.classes_)
##https://lime-ml.readthedocs.io/en/latest/lime.html#module-lime.lime_text


def flatten_predict(i):
    global model   
    # catch single string input and convert to list
    if i.__class__ != list:
        i = [i]
    # list for predictions
    predStorage = []
    # loop through input list and predict
    for textInput in i:
        textInput = preprocess(textInput)
        textInput = make_predictable(textInput)
        pred = model.predict(textInput)
        pred = np.append(pred, 1-pred, axis=1)
        predStorage.extend(pred)

    return np.asarray(predStorage)


def get_predict_proba_fn_of_class(strings):
    def rewrapped_predict(strings): 
        pred = flatten_predict(strings)
        index = np.where(pred==label)[1][0]
        preds = pred[:, index::5]
        return preds

    return rewrapped_predict


string="Der Arzt weiß, was er tut und hat mir alles genau erklärt."
print("Simple model prediction:", model.predict(make_predictable(preprocess(string))))

labels_to_explain = flatten_predict(string)
print("labels_to_explain:", labels_to_explain)

explanation_for_label = {}
for index, label in enumerate(labels_to_explain[0]):
    if index < (len(labels_to_explain[0])/2):
        actual_classes = [encoder.classes_[index], 'None']
        explainer = LimeTextExplainer(class_names=actual_classes)
        wrapped = get_predict_proba_fn_of_class(string)  # function returns function!
        explanation_for_label[label] = explainer.explain_instance(string, wrapped)
        explanation_for_label[label].show_in_notebook()
0 голосов
/ 07 января 2019

Не совсем уверен, но, судя по вашему журналу ошибок, check_consistent_length(X, y) не работает, следовательно, ваш ввод X не имеет такую ​​же длину, как ваш y. Попробуйте и проверьте clf.fit(data, labels, sample_weight=weights) на линии 80

...