Skip to content

Commit

Permalink
Merge branch 'master' of github.com:teabolt/eli5 into keras-gradcam-text
Browse files Browse the repository at this point in the history
  • Loading branch information
teabolt committed Jun 6, 2020
2 parents c94eb52 + 017c738 commit ec0f51c
Show file tree
Hide file tree
Showing 46 changed files with 204 additions and 146 deletions.
12 changes: 12 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Changelog
=========

0.10.1 (2019-08-29)
-------------------

* Don't include typing dependency on Python 3.5+
to fix installation on Python 3.7

0.10.0 (2019-08-21)
-------------------

* Keras image classifiers: explaining predictions with Grad-CAM
(GSoC-2019 project by @teabolt).

0.9.0 (2019-07-05)
------------------

Expand Down
4 changes: 2 additions & 2 deletions eli5/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

__version__ = '0.9.0'
__version__ = '0.10.1'

from .formatters import (
format_as_html,
Expand Down Expand Up @@ -95,4 +95,4 @@
)
except ImportError:
# keras is not available
pass
pass
4 changes: 2 additions & 2 deletions eli5/_feature_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
Union, Callable, Pattern
)

import numpy as np # type: ignore
import scipy.sparse as sp # type: ignore
import numpy as np
import scipy.sparse as sp


class FeatureNames(Sized, Iterable):
Expand Down
2 changes: 1 addition & 1 deletion eli5/_feature_weights.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

import numpy as np # type: ignore
import numpy as np

from eli5.base import FeatureWeights, FeatureWeight
from .utils import argsort_k_largest_positive, argsort_k_smallest, mask
Expand Down
2 changes: 1 addition & 1 deletion eli5/_graphviz.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
import graphviz # type: ignore
import graphviz


def is_supported():
Expand Down
2 changes: 1 addition & 1 deletion eli5/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from typing import Any, List, Tuple, Union, Optional

import numpy as np # type: ignore
import numpy as np

from .base_utils import attrs
from .formatters.features import FormattedFeatureName
Expand Down
4 changes: 2 additions & 2 deletions eli5/base_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import inspect

import attr # type: ignore
import attr

try:
from functools import singledispatch # type: ignore
from functools import singledispatch
except ImportError:
from singledispatch import singledispatch # type: ignore

Expand Down
4 changes: 2 additions & 2 deletions eli5/catboost.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import absolute_import, division

import numpy as np # type: ignore
import catboost # type: ignore
import numpy as np
import catboost

from eli5.explain import explain_weights
from eli5._feature_importances import get_feature_importance_explanation
Expand Down
2 changes: 1 addition & 1 deletion eli5/formatters/as_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any, Dict, List, Optional
import warnings

import pandas as pd # type: ignore
import pandas as pd

import eli5
from eli5.base import (
Expand Down
4 changes: 2 additions & 2 deletions eli5/formatters/as_dict.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import six

import attr # type: ignore
import numpy as np # type: ignore
import attr
import numpy as np

from .features import FormattedFeatureName

Expand Down
4 changes: 2 additions & 2 deletions eli5/formatters/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from itertools import groupby
from typing import List, Optional, Tuple

import numpy as np # type: ignore
from jinja2 import Environment, PackageLoader # type: ignore
import numpy as np
from jinja2 import Environment, PackageLoader

from eli5 import _graphviz
from eli5.base import (Explanation, TargetExplanation, FeatureWeights,
Expand Down
6 changes: 3 additions & 3 deletions eli5/formatters/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from __future__ import absolute_import
from typing import Union, Optional, Callable

import numpy as np # type: ignore
from PIL import Image # type: ignore
import matplotlib.cm # type: ignore
import numpy as np
from PIL import Image
import matplotlib.cm

from eli5.base import Explanation
from eli5.nn.gradcam import (
Expand Down
7 changes: 4 additions & 3 deletions eli5/formatters/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
from __future__ import absolute_import
from itertools import chain
import six
from tabulate import tabulate
from typing import List, Optional, Iterator

from eli5.base import Explanation, FeatureImportances
from . import fields
from .features import FormattedFeatureName
from .utils import (
format_signed, format_value, format_weight, has_any_values_for_weights,
replace_spaces, should_highlight_spaces, tabulate)
replace_spaces, should_highlight_spaces)
from .utils import tabulate as eli5_tabulate
from .trees import tree2text


Expand Down Expand Up @@ -153,7 +155,6 @@ def _decision_tree_lines(explanation):

def _transition_features_lines(explanation):
# type: (Explanation) -> List[str]
from tabulate import tabulate # type: ignore
tf = explanation.transition_features
assert tf is not None
return [
Expand Down Expand Up @@ -203,7 +204,7 @@ def _targets_lines(explanation, # type: Explanation

w = target.feature_weights
assert w is not None
table = tabulate(
table = eli5_tabulate(
[table_line(fw) for fw in chain(w.pos, reversed(w.neg))],
header=table_header,
col_align=col_align,
Expand Down
2 changes: 1 addition & 1 deletion eli5/formatters/text_helpers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import Counter
from typing import List, Optional

import numpy as np # type: ignore
import numpy as np

from eli5.base import TargetExplanation, WeightedSpans, DocWeightedSpans
from eli5.base_utils import attrs
Expand Down
2 changes: 2 additions & 0 deletions eli5/formatters/trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def p(*args):
else:
assert node.left is not None
assert node.right is not None
assert node.threshold is not None

feat_name = node.feature_name

if depth > 0:
Expand Down
7 changes: 3 additions & 4 deletions eli5/formatters/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
from itertools import chain
import re
import six
from numbers import Real
from typing import Any, Union, List, Dict, Callable, Match, Optional

import numpy as np # type: ignore
import numpy as np

from eli5.base import Explanation
from .features import FormattedFeatureName
Expand Down Expand Up @@ -143,12 +142,12 @@ def tabulate(data, # type: List[List[Any]]


def format_weight(value):
# type: (Real) -> str
# type: (float) -> str
return '{:+.3f}'.format(value)


def format_value(value):
# type: (Optional[Real]) -> str
# type: (Optional[float]) -> str
if value is None:
return ''
elif np.isnan(value):
Expand Down
4 changes: 2 additions & 2 deletions eli5/ipython.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
from typing import Any, Dict, Tuple
import warnings

from IPython.display import HTML, Image # type: ignore
from IPython.display import HTML, Image

from .explain import explain_weights, explain_prediction
from .formatters import format_as_html, fields
try:
from .formatters.image import format_as_image
except ImportError as e:
# missing dependencies
format_as_image = e # type: ignore
format_as_image = e # type: ignore


FORMAT_KWARGS = {'include_styles', 'force_weights',
Expand Down
18 changes: 9 additions & 9 deletions eli5/keras/explain_prediction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
from __future__ import absolute_import
from typing import Union, Optional, Callable, List, Tuple, Generator, TYPE_CHECKING
if TYPE_CHECKING:
import PIL # type: ignore

import numpy as np # type: ignore
import keras # type: ignore
import keras.backend as K # type: ignore
from keras.models import Model # type: ignore
from keras.layers import Layer # type: ignore
from keras.layers import ( # type: ignore
import PIL

import numpy as np
import keras
import keras.backend as K
from keras.models import Model
from keras.layers import Layer
from keras.layers import (
Conv2D,
MaxPooling2D,
AveragePooling2D,
Expand All @@ -26,7 +26,7 @@
GRU,
Bidirectional,
)
from keras.preprocessing.image import array_to_img # type: ignore
from keras.preprocessing.image import array_to_img

from eli5.base import (
Explanation,
Expand Down
31 changes: 25 additions & 6 deletions eli5/keras/gradcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
from __future__ import absolute_import
from typing import Any, Optional, Tuple, List

import numpy as np # type: ignore
import keras # type: ignore
import keras.backend as K # type: ignore
from keras.models import Model # type: ignore
from keras.layers import Layer # type: ignore
import numpy as np
import keras
import keras.backend as K
from keras.models import Model
from keras.layers import Layer

from eli5.nn.gradcam import (
_validate_targets,
Expand Down Expand Up @@ -128,6 +128,25 @@ def _classification_target(model, targets):
# from the array of predictions
predicted_idx = K.argmax(model.output, axis=-1)

<<<<<<< HEAD
# access value by index
predicted_val = K.gather(model.output[0, :], predicted_idx)
return predicted_idx, predicted_val
return predicted_idx, predicted_val
=======
def _validate_target(target, output_shape):
# type: (int, tuple) -> None
"""
Check whether ``target``,
an integer index into the model's output
is valid for the given ``output_shape``.
"""
if isinstance(target, int):
output_nodes = output_shape[1:][0]
if not (0 <= target < output_nodes):
raise ValueError('Prediction target index is '
'outside the required range [0, {}). '
'Got {}'.format(output_nodes, target))
else:
raise TypeError('Prediction target must be int. '
'Got: {}'.format(target))
>>>>>>> 017c738f8dcf3e31346de49a390835ffafad3f1b
4 changes: 2 additions & 2 deletions eli5/lightgbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from collections import defaultdict
from typing import DefaultDict, Optional

import numpy as np # type: ignore
import lightgbm # type: ignore
import numpy as np
import lightgbm

from eli5.explain import explain_weights, explain_prediction
from eli5._feature_importances import get_feature_importance_explanation
Expand Down
6 changes: 3 additions & 3 deletions eli5/lightning.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

from lightning.impl.base import BaseEstimator # type: ignore
from lightning import classification, regression # type: ignore
from sklearn.multiclass import OneVsRestClassifier # type: ignore
from lightning.impl.base import BaseEstimator
from lightning import classification, regression
from sklearn.multiclass import OneVsRestClassifier

from eli5.base import Explanation
from eli5.base_utils import singledispatch
Expand Down
8 changes: 4 additions & 4 deletions eli5/lime/_vectorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from __future__ import absolute_import
from typing import Tuple, Callable, Dict, Optional, List

import numpy as np # type: ignore
from sklearn.base import BaseEstimator, TransformerMixin # type: ignore
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin

from eli5.base import DocWeightedSpans, FeatureWeights
from eli5.sklearn.text import _get_feature_weights_dict
Expand All @@ -13,8 +13,8 @@
class SingleDocumentVectorizer(BaseEstimator, TransformerMixin):
""" Fake vectorizer which converts document just to a vector of ones """

def __init__(self, token_pattern=None):
# type: (Optional[str]) -> None
def __init__(self, token_pattern):
# type: (str) -> None
self.token_pattern = token_pattern

def fit(self, X, y=None):
Expand Down
16 changes: 8 additions & 8 deletions eli5/lime/lime.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from __future__ import absolute_import
from typing import Any, Callable, Dict, Optional

import numpy as np # type: ignore
from sklearn.feature_extraction.text import CountVectorizer # type: ignore
from sklearn.linear_model import SGDClassifier # type: ignore
from sklearn.model_selection import train_test_split # type: ignore
from sklearn.utils import check_random_state # type: ignore
from sklearn.base import clone, BaseEstimator # type: ignore
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split
from sklearn.utils import check_random_state
from sklearn.base import clone, BaseEstimator

import eli5
from eli5.sklearn.utils import sklearn_version
Expand Down Expand Up @@ -148,7 +148,7 @@ def __init__(self,
rbf_sigma=None, # type: float
random_state=None,
expand_factor=10, # type: Optional[int]
token_pattern=None, # type: str
token_pattern=None, # type: Optional[str]
):
# type: (...) -> None
self.n_samples = n_samples
Expand All @@ -162,7 +162,7 @@ def __init__(self,
if char_based is None:
if token_pattern is None:
self.char_based = False # type: Optional[bool]
self.token_pattern = DEFAULT_TOKEN_PATTERN
self.token_pattern = DEFAULT_TOKEN_PATTERN # type: str
else:
self.char_based = None
self.token_pattern = token_pattern
Expand Down
Loading

0 comments on commit ec0f51c

Please sign in to comment.