예제 #1
0
    def run_test(train_loader, test_loader, interim):

        class Net(nn.Module):
            def __init__(self):
                super(Net, self).__init__()
                # Testing several different activations
                self.conv_layers = nn.Sequential(
                    nn.Conv2d(1, 10, kernel_size=5),
                    nn.MaxPool2d(2),
                    nn.Tanh(),
                    nn.Conv2d(10, 20, kernel_size=5),
                    nn.MaxPool2d(2),
                    nn.Softplus(),
                )
                self.fc_layers = nn.Sequential(
                    nn.Linear(320, 50),
                    nn.ReLU(),
                    nn.Linear(50, 10),
                    nn.ELU(),
                    nn.Softmax(dim=1)
                )

            def forward(self, x):
                x = self.conv_layers(x)
                x = x.view(-1, 320)
                x = self.fc_layers(x)
                return x

        model = Net()
        optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

        def train(model, device, train_loader, optimizer, epoch, cutoff=2000):
            model.train()
            num_examples = 0
            for batch_idx, (data, target) in enumerate(train_loader):
                num_examples += target.shape[0]
                data, target = data.to(device), target.to(device)
                optimizer.zero_grad()
                output = model(data)
                loss = F.mse_loss(output, torch.eye(10)[target])
                # loss = F.nll_loss(output, target)
                loss.backward()
                optimizer.step()
                if batch_idx % 10 == 0:
                    print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                        epoch, batch_idx * len(data), len(train_loader.dataset),
                               100. * batch_idx / len(train_loader), loss.item()))
                if num_examples > cutoff:
                    break

        device = torch.device('cpu')
        train(model, device, train_loader, optimizer, 1)

        next_x, next_y = next(iter(train_loader))
        np.random.seed(0)
        inds = np.random.choice(next_x.shape[0], 20, replace=False)
        if interim:
            e = shap.DeepExplainer((model, model.conv_layers[0]), next_x[inds, :, :, :])
        else:
            e = shap.DeepExplainer(model, next_x[inds, :, :, :])
        test_x, test_y = next(iter(test_loader))
        shap_values = e.shap_values(test_x[:1])

        model.eval()
        model.zero_grad()
        with torch.no_grad():
            diff = (model(test_x[:1]) - model(next_x[inds, :, :, :])).detach().numpy().mean(0)
        sums = np.array([shap_values[i].sum() for i in range(len(shap_values))])
        d = np.abs(sums - diff).sum()
        assert d / np.abs(diff).sum() < 0.001, "Sum of SHAP values does not match difference! %f" % (
                d / np.abs(diff).sum())
예제 #2
0
 def test_shap(self):
     print(Colours.yellow("--- CNN shap---"))
     source_data = unserialize_pickle(self.data_source_dump)
     stat_dict = unserialize_json(self.stat_file)
     data_flow = unserialize_numpy(self.flow_file)
     t_s_dict = unserialize_json(self.t_s_dict_file)
     model_data = DataModel(source_data, data_flow, t_s_dict, stat_dict)
     model_dict = model_data.data_source.data_config.model_dict
     n_input = int(14)
     try_cnn = TryCnn()
     data, targets = routing_cnn.to_supervised(
         model_data.load_data(model_dict), n_input)
     try_cnn.load_state_dict(
         torch.load("F:\科研类\codes\hydro-routing-cnn\checkpoint.pt"))
     # x1 = data.reshape(715, 1, -1)
     # x = x1.reshape(-1, 1, 1, x1.shape[2])
     x = data.reshape(-1, 1, data.shape[1], data.shape[2])
     x = torch.from_numpy(x).float()
     try_cnn.eval()
     # x_pred = try_cnn(x[301:306])
     # print(x[301:306])
     # print(x_pred)
     print("======计算SHAP========")
     # 新建一个解释器(模型,数据)
     background = x[np.random.choice(x.shape[0], 100, replace=False)]
     e = shap.DeepExplainer(try_cnn, background)
     # e = shap.DeepExplainer(try_cnn, x)
     shap_values = e.shap_values(x)
     shap_values_stations_days = np.abs(shap_values).sum(axis=0).reshape(
         14, data.shape[2])
     shap_days = shap_values_stations_days.sum(axis=1)
     shap_stations = shap_values_stations_days.sum(axis=0)
     # 计算base_line
     # y_base = e.expected_value
     # print("y_base的值:", y_base)
     # print("y_base+shap值的和:",y_base+shap_values.sum())
     shap_values_array = shap_values.reshape(-1,
                                             data.shape[1] * data.shape[2])
     shap_arrays_values = []
     for i in range(shap_values_array.shape[0]):
         new_array = np.zeros(
             (shap_values_array.shape[0] - 1) * data.shape[2])
         if i == 0:
             ndarray = np.append(shap_values_array[i], new_array)
         elif i == shap_values_array.shape[0] - 1:
             ndarray = np.insert(shap_values_array[i], 0, new_array)
         else:
             ndarray = np.pad(
                 shap_values_array[i],
                 (i * data.shape[2],
                  (shap_values_array.shape[0] - 1 - i) * data.shape[2]),
                 'constant')
         shap_arrays_values.append(ndarray)
     shap_arrays_values = np.array(shap_arrays_values)
     shap_arrays_values_abs = np.abs(shap_arrays_values).sum(
         axis=0).reshape(-1, data.shape[2])
     print(shap_arrays_values_abs)
     shap_values_days_stations = []
     for j in range(shap_arrays_values_abs.shape[0]):
         if j < 14:
             shap_values_day_state = shap_arrays_values_abs[j] / (j + 1)
         elif j >= shap_arrays_values_abs.shape[0] - 14:
             shap_values_day_state = shap_arrays_values_abs[j] / (
                 shap_arrays_values_abs.shape[0] - j)
         else:
             shap_values_day_state = shap_arrays_values_abs[j] / 14
         shap_values_days_stations.append(shap_values_day_state)
     shap_values_days_stations = np.array(shap_values_days_stations)
     print(shap_values_days_stations)
     serialize_numpy(shap_values_days_stations,
                     self.shap_values_days_states_file)
     serialize_numpy(shap_days, self.shap_days_file)
     serialize_numpy(shap_stations, self.shap_stations_file)
     serialize_numpy(shap_values_stations_days,
                     self.shap_values_stations_days_file)
예제 #3
0
파일: interpretation.py 프로젝트: tzom/AHLF
model.compile(optimizer=tf.keras.optimizers.Adam(),loss=tf.keras.losses.BinaryCrossentropy(from_logits=False))

#####################################################################
#####################################################################
#####################################################################

batch_size=64

model.load_weights("model/alpha_model_weights.hdf5")

from get_spectrum_as_numpy import get_spectrum
import shap 

spectrum = get_spectrum('example/example.mgf')
background_spectra = np.zeros((1,3600,2))
e = shap.DeepExplainer(model, background_spectra)

take_specific_spectrum=0
spectrum=spectrum[take_specific_spectrum,:,:]
spectrum=np.expand_dims(spectrum,0)

interpretation = np.squeeze(e.shap_values(spectrum))
spectrum = np.squeeze(spectrum)

import matplotlib.pyplot as plt

plt.title("Mirrorplot: demonstrating how SHAP values are used to interpret AHLF.")
plt.stem(spectrum[:,0]/np.max(spectrum[:,0]),linefmt='C0-',markerfmt=' ',basefmt=' ',use_line_collection=True,label='acquired peak')
plt.stem(- np.abs(interpretation[:,0])/np.max(np.abs(interpretation[:,0])),linefmt='C1-',markerfmt=' ',basefmt=' ',use_line_collection=True,label='abs. SHAP value')
plt.xlabel('feature')
plt.ylabel('Norm. abundance [a.u.]')
예제 #4
0
def deep_explain_model_summary_plot(
    model,
    datetime_start: datetime = datetime(2014, 6, 1, 0),
    test_csv_path: str = None,
    forecast_total: int = 336,
    dataset_params: Dict = {},
):
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    num_features = len(model.params["dataset_params"]["relevant_cols"])
    # If the test dataframe is none use default one supplied in params
    if test_csv_path is None:
        csv_test_loader = model.test_data
    else:
        csv_test_loader = CSVTestLoader(
            test_csv_path,
            forecast_total,
            **dataset_params,
            interpolate=dataset_params["interpolate_param"],
        )
    background_data = csv_test_loader.original_df
    background_batches = csv_test_loader.convert_real_batches(
        csv_test_loader.df.columns, background_data)
    background_tensor = (torch.stack(
        random.sample(background_batches,
                      BACKGROUND_SAMPLE_SIZE)).float().to(device))
    model.model.eval()

    # background shape (L, N, M)
    # L - batch size, N - history length, M - feature size
    deep_explainer = shap.DeepExplainer(model.model, background_tensor)
    shap_values = deep_explainer.shap_values(background_tensor)

    # summary plot shows overall feature ranking
    # by average absolute shap values
    mean_shap_values = np.concatenate(shap_values).mean(axis=0)
    plt.figure(figsize=(12, 8))
    shap.summary_plot(
        mean_shap_values,
        feature_names=csv_test_loader.df.columns,
        plot_type="bar",
        show=False,
        max_display=10,
        plot_size=(10, num_features * 2),
    )
    plt.savefig("overall_feature_ranking_by_shap_values.png")
    wandb.log({
        "Overall feature ranking by shap values":
        wandb.Image("overall_feature_ranking_by_shap_values.png")
    })
    plt.close()

    # summary plot for multi-step outputs
    multi_shap_values = list(np.stack(shap_values).mean(axis=1))
    shap.summary_plot(
        multi_shap_values,
        feature_names=csv_test_loader.df.columns,
        class_names=[
            f"time-step-{t}" for t in range(model.model.forecast_length)
        ],
        max_display=10,  # max number of features to display
        show=False,
        plot_size=(10, num_features * 2),
        sort=False,
    )
    plt.savefig("overall_feature_rank_per_time_step.png")
    wandb.log({
        "Overall feature ranking per prediction time-step":
        wandb.Image("overall_feature_rank_per_time_step.png")
    })
    plt.close()

    # summary plot for one prediction at datetime_start
    history, _, forecast_start_idx = csv_test_loader.get_from_start_date(
        datetime_start)
    to_explain = history.to(device).unsqueeze(0)
    shap_values = deep_explainer.shap_values(to_explain)
    mean_shap_values = np.concatenate(shap_values).mean(axis=0)
    shap.summary_plot(
        mean_shap_values,
        history.cpu().numpy(),
        feature_names=csv_test_loader.df.columns,
        plot_type="dot",
        max_display=10,
        plot_size=(9, num_features * 2),
        show=False,
    )
    plt.savefig("feature_ranking_for_prediction_at_timestamp.png")
    wandb.log({
        "Feature ranking for prediction at "
        f"{datetime_start.strftime('%Y-%m-%d')}":
        wandb.Image("feature_ranking_for_prediction_at_timestamp.png")
    })
    plt.close()
예제 #5
0
    def _run_pytorch_multiple_inputs_test(disconnected):
        """Testing multiple inputs
        """
        import torch
        from torch import nn
        from torch.nn import functional as F
        from torch.utils.data import TensorDataset, DataLoader
        from sklearn.datasets import load_boston
        import shap

        X, y = load_boston(return_X_y=True)
        num_features = X.shape[1]
        x1 = X[:, num_features // 2:]
        x2 = X[:, :num_features // 2]
        data = TensorDataset(torch.tensor(x1).float(),
                             torch.tensor(x2).float(),
                             torch.tensor(y).float())
        loader = DataLoader(data, batch_size=128)

        class Net(nn.Module):
            def __init__(self, num_features, disconnected):
                super(Net, self).__init__()
                self.disconnected = disconnected
                if disconnected:
                    num_features = num_features // 2 + 1
                self.linear = nn.Linear(num_features, 2)
                self.output = nn.Sequential(
                    nn.MaxPool1d(2),
                    nn.ReLU()
                )

            def forward(self, x1, x2):
                if self.disconnected:
                    x = self.linear(x1).unsqueeze(1)
                else:
                    x = self.linear(torch.cat((x1, x2), dim=-1)).unsqueeze(1)
                return self.output(x).squeeze(1)

        model = Net(num_features, disconnected)
        optimizer = torch.optim.Adam(model.parameters())

        def train(model, device, train_loader, optimizer, epoch):
            model.train()
            num_examples = 0
            for batch_idx, (data1, data2, target) in enumerate(train_loader):
                num_examples += target.shape[0]
                data1, data2, target = data1.to(device), data2.to(device), target.to(device)
                optimizer.zero_grad()
                output = model(data1, data2)
                loss = F.mse_loss(output.squeeze(1), target)
                loss.backward()
                optimizer.step()
                if batch_idx % 2 == 0:
                    print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                        epoch, batch_idx * len(data), len(train_loader.dataset),
                               100. * batch_idx / len(train_loader), loss.item()))

        device = torch.device('cpu')
        train(model, device, loader, optimizer, 1)

        next_x1, next_x2, next_y = next(iter(loader))
        np.random.seed(0)
        inds = np.random.choice(next_x1.shape[0], 20, replace=False)
        background = [next_x1[inds, :], next_x2[inds, :]]
        e = shap.DeepExplainer(model, background)
        test_x1, test_x2, test_y = next(iter(loader))
        shap_x1, shap_x2 = e.shap_values([test_x1[:1], test_x2[:1]])

        model.eval()
        model.zero_grad()
        with torch.no_grad():
            diff = (model(test_x1[:1], test_x2[:1]) - model(*background)).detach().numpy().mean(0)
        sums = np.array([shap_x1[i].sum() + shap_x2[i].sum() for i in range(len(shap_x1))])
        d = np.abs(sums - diff).sum()
        assert d / np.abs(diff).sum() < 0.001, "Sum of SHAP values does not match difference! %f" % (
                d / np.abs(diff).sum())
예제 #6
0
    def __init__(self, model, initialization_examples, explain_subset=None, nclusters=10,
                 features=None, classes=None, transformations=None, allow_all_transformations=False,
                 model_task=ModelTask.Unknown, is_classifier=None, **kwargs):
        """Initialize the DeepExplainer.

        :param model: The DNN model to explain.
        :type model: PyTorch or TensorFlow model
        :param initialization_examples: A matrix of feature vector examples (# examples x # features) for
            initializing the explainer.
        :type initialization_examples: numpy.array or pandas.DataFrame or iml.datatypes.DenseData or
            scipy.sparse.csr_matrix
        :param explain_subset: List of feature indices. If specified, only selects a subset of the
            features in the evaluation dataset for explanation. The subset can be the top-k features
            from the model summary.
        :type explain_subset: list[int]
        :param nclusters: Number of means to use for approximation. A dataset is summarized with nclusters mean
            samples weighted by the number of data points they each represent. When the number of initialization
            examples is larger than (10 x nclusters), those examples will be summarized with k-means where
            k = nclusters.
        :type nclusters: int
        :param features: A list of feature names.
        :type features: list[str]
        :param classes: Class names as a list of strings. The order of the class names should match
            that of the model output.  Only required if explaining classifier.
        :type classes: list[str]
        :param transformations: sklearn.compose.ColumnTransformer or a list of tuples describing the column name and
            transformer. When transformations are provided, explanations are of the features before the transformation.
            The format for a list of transformations is same as the one here:
            https://github.com/scikit-learn-contrib/sklearn-pandas.

            If you are using a transformation that is not in the list of sklearn.preprocessing transformations that
            are supported by the `interpret-community <https://github.com/interpretml/interpret-community>`_
            package, then this parameter cannot take a list of more than one column as input for the transformation.
            You can use the following sklearn.preprocessing  transformations with a list of columns since these are
            already one to many or one to one: Binarizer, KBinsDiscretizer, KernelCenterer, LabelEncoder, MaxAbsScaler,
            MinMaxScaler, Normalizer, OneHotEncoder, OrdinalEncoder, PowerTransformer, QuantileTransformer,
            RobustScaler, StandardScaler.

            Examples for transformations that work::

                [
                    (["col1", "col2"], sklearn_one_hot_encoder),
                    (["col3"], None) #col3 passes as is
                ]
                [
                    (["col1"], my_own_transformer),
                    (["col2"], my_own_transformer),
                ]

            An example of a transformation that would raise an error since it cannot be interpreted as one to many::

                [
                    (["col1", "col2"], my_own_transformer)
                ]

            The last example would not work since the interpret-community package can't determine whether
            my_own_transformer gives a many to many or one to many mapping when taking a sequence of columns.
        :type transformations: sklearn.compose.ColumnTransformer or list[tuple]
        :param allow_all_transformations: Allow many to many and many to one transformations
        :type allow_all_transformations: bool
        :param is_classifier: Optional parameter to specify whether the model is a classification or regression model.
            In most cases, the type of the model can be inferred based on the shape of the output, where a classifier
            has a predict_proba method and outputs a 2 dimensional array, while a regressor has a predict method and
            outputs a 1 dimensional array.
        :type is_classifier: bool
        :param model_task: Optional parameter to specify whether the model is a classification or regression model.
        :type model_task: str
        """
        self._datamapper = None
        if transformations is not None:
            self._datamapper, initialization_examples = get_datamapper_and_transformed_data(
                examples=initialization_examples, transformations=transformations,
                allow_all_transformations=allow_all_transformations)

        super(DeepExplainer, self).__init__(model, initialization_examples, **kwargs)
        self._logger.debug('Initializing DeepExplainer')
        self._method = 'shap.deep'
        self.features = features
        self.classes = classes
        self.nclusters = nclusters
        self.explain_subset = explain_subset
        self.transformations = transformations
        self.model_task = model_task
        self.framework = _get_dnn_model_framework(self.model)
        summary = _get_summary_data(self.initialization_examples, nclusters, self.framework)
        # Suppress warning message from Keras
        with logger_redirector(self._logger):
            self.explainer = shap.DeepExplainer(self.model, summary)
예제 #7
0
agent = torch.load("agents/agent_zoo/dfq5_epsexp").to(DEVICE)
player = PlayerQ(render=False)

for episode_idx in range(n_ep):
    print("\r{}/{}".format(episode_idx, n_ep), end="")
    summary = player.play(agent)
    obs.append(summary["observations"])

_grid_size = config.N_LANES * config.LANE_LENGTH

obs = np.concatenate(obs)
obs = np.array([np.concatenate([state[:_grid_size], 
                       np.sum(state[_grid_size: 2 * _grid_size].reshape(-1, config.LANE_LENGTH), axis=1), 
                       state[2 * _grid_size:]]) for state in obs])

n_obs = len(obs)

e = shap.DeepExplainer(
        agent.network, 
        torch.from_numpy(
            obs[np.random.choice(np.arange(len(obs)), 100, replace=False)]
        ).type(torch.FloatTensor).to(DEVICE))

shap_values = e.shap_values(
    torch.from_numpy(obs[np.random.choice(np.arange(len(obs)), 30, replace=False)]).type(torch.FloatTensor).to(DEVICE)
)

s = np.stack([np.sum(s, axis=0) for s in shap_values])
print(np.sum(s, axis=0))
shap.summary_plot(shap_values)
def deep_explain_model_heatmap(
        model,
        csv_test_loader: CSVTestLoader,
        datetime_start: Optional[datetime] = None) -> None:
    """Generate feature heatmap for prediction at a start time
    Args:
        model ([type]): trained model
        csv_test_loader ([CSVTestLoader]): test data loader
        datetime_start (Optional[datetime], optional): start date of the test prediction,
            Defaults to None, i.e. using model inference parameters.
    Returns:
        None
    """
    if model.params["model_name"] == "SimpleTransformer":
        print("SimpleTransformer currently not supported.")
        return
    elif "probabilistic" in model.params:
        print("Probabilistic currently not supported.")
        return
    use_wandb = model.wandb
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    if model.params["model_name"] == "DARNN" and device.type == "cuda":
        print("Currently DARNN doesn't work with shap on CUDA")
        return

    if datetime_start is None:
        datetime_start = model.params["inference_params"]["datetime_start"]

    history, _, forecast_start_idx = csv_test_loader.get_from_start_date(
        datetime_start)
    background_tensor = _prepare_background_tensor(csv_test_loader)
    background_tensor = background_tensor.to(device)
    model.model.eval()

    # background shape (L, N, M)
    # L - batch size, N - history length, M - feature size
    # for each element in each N x M batch in L,
    # attribute to each prediction in forecast len
    deep_explainer = shap.DeepExplainer(model.model, background_tensor)
    shap_values = deep_explainer.shap_values(
        background_tensor)  # forecast_len x N x L x M
    shap_values = np.stack(shap_values)
    if len(shap_values.shape) != 4:
        shap_values = np.expand_dims(shap_values, axis=0)
    shap_values = torch.tensor(
        shap_values, names=["preds", "batches", "observations", "features"])
    figs = plot_shap_value_heatmaps(shap_values)
    if use_wandb:
        for fig, feature in zip(figs, csv_test_loader.df.columns):
            wandb.log({f"Average prediction heatmaps - {feature}": fig})

    # heatmap one prediction sequence at datetime_start
    # (seq_len*forecast_len) per fop feature
    to_explain = history.to(device).unsqueeze(0)
    shap_values = deep_explainer.shap_values(to_explain)
    shap_values = np.stack(shap_values)
    if len(shap_values.shape) != 4:
        shap_values = np.expand_dims(shap_values, axis=0)
    shap_values = torch.tensor(
        shap_values, names=["preds", "batches", "observations", "features"])

    figs = plot_shap_value_heatmaps(shap_values)
    if use_wandb:
        for fig, feature in zip(figs, csv_test_loader.df.columns):
            wandb.log({
                "Heatmap for prediction "
                f"at {datetime_start} - {feature}":
                fig
            })
def deep_explain_model_summary_plot(
        model,
        csv_test_loader: CSVTestLoader,
        datetime_start: Optional[datetime] = None) -> None:
    """Generate feature summary plot for trained deep learning models
    Args:
        model (object): trained model
        csv_test_loader (CSVTestLoader): test data loader
        datetime_start (datetime, optional): start date of the test prediction,
            Defaults to None, i.e. using model inference parameters.
    """
    if model.params["model_name"] == "SimpleTransformer":
        print("SimpleTransformer currently not supported.")
        return

    use_wandb = model.wandb
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    if model.params["model_name"] == "DARNN" and device.type == "cuda":
        print("DARNN does not work with shap on CUDA")
        return

    if datetime_start is None:
        datetime_start = model.params["inference_params"]["datetime_start"]

    history, _, forecast_start_idx = csv_test_loader.get_from_start_date(
        datetime_start)
    background_tensor = _prepare_background_tensor(csv_test_loader)
    background_tensor = background_tensor.to(device)
    model.model.eval()

    # background shape (L, N, M)
    # L - batch size, N - history length, M - feature size
    deep_explainer = shap.DeepExplainer(model.model, background_tensor)
    shap_values = deep_explainer.shap_values(background_tensor)
    shap_values = np.stack(shap_values)
    # shap_values needs to be 4-dimensional
    if len(shap_values.shape) != 4:
        shap_values = np.expand_dims(shap_values, axis=0)
    shap_values = torch.tensor(
        shap_values, names=["preds", "batches", "observations", "features"])

    # summary plot shows overall feature ranking
    # by average absolute shap values
    fig = plot_summary_shap_values(shap_values, csv_test_loader.df.columns)
    if use_wandb:
        wandb.log({"Overall feature ranking by shap values": fig})

    # summary plot for multi-step outputs
    # multi_shap_values = shap_values.apply_along_axis(np.mean, 'batches')
    fig = plot_summary_shap_values_over_time_series(shap_values,
                                                    csv_test_loader.df.columns)
    if use_wandb:
        wandb.log({"Overall feature ranking per prediction time-step": fig})

    # summary plot for one prediction at datetime_start

    history = history.to(device).unsqueeze(0)
    history_numpy = torch.tensor(history.cpu().numpy(),
                                 names=["batches", "observations", "features"])

    shap_values = deep_explainer.shap_values(history)
    shap_values = np.stack(shap_values)
    if len(shap_values.shape) != 4:
        shap_values = np.expand_dims(shap_values, axis=0)
    shap_values = torch.tensor(
        shap_values, names=["preds", "batches", "observations", "features"])

    figs = plot_shap_values_from_history(shap_values, history_numpy)
    if use_wandb:
        for fig, feature in zip(figs, csv_test_loader.df.columns.tolist()):
            wandb.log({
                "Feature ranking for prediction"
                f" at {datetime_start} - {feature}":
                fig
            })
import shap

# ===============================================================
# ===                                                         ===
# ===   !!! Before run this file, Add the code below to the   ===
# ===   end of file: [shap]/explainers/_deep/deep_pytorch.py  ===
# ===   [shap] means the root path of your python shap lib    ===
# ===   such like "D:\anaconda3\Lib\site-packages\shap"       ===
# ===                                                         ===
# ===   code for supplement :                                 ===
# ===       op_handler['Chomp1d'] = passthrough               ===
# ===                                                         ===
# ===============================================================

model = torch.load('sepsis_predict.pt').cuda()

data_raw = torch.load("dataTensor.pt").cuda()
data_X = data_raw[:, :, :-1].transpose(1, 2)
X_train = data_X[:100]
X_test = data_X[-2000:-1995]

e = shap.DeepExplainer(model, X_train)
shap_values = e.shap_values(X_test)

np.save('shap_values', shap_values[0, 0])
# shap.image_plot(shap_values, X_test)

plt.imshow(shap_values[0, 0])
plt.colorbar()
plt.show()
예제 #11
0
    batch_size=50)

test_loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=5)

with torch.no_grad():
    # for mb_features in background_loader:
    #     mb_features = {k: v.to(device) for k, v in mb_features.items()}
    #     mb_alphas = torch.exp(model(**mb_features)[0])
    background_iter = iter(background_loader)
    background_features = next(
        background_iter
    )  #model expects dict with keys input ids and attention mask, value shapes Nx512
    background_features_list = [
        background_features['input_ids'].to(device),
        background_features['attention_mask'].to(device)
    ]

    test_iter = iter(test_loader)
    test_features = next(test_iter)
    test_features_list = [
        test_features['input_ids'].to(device),
        test_features['attention_mask'].to(device)
    ]

explainershap = shap.DeepExplainer(
    model, background_features_list
)  #shap requires background data to be one tensor only
shap_values_matrix = explainershap.shap_values(test_features_list)
shap.summary_plot(shap_values_matrix)  #ä,feature_names=dataset.feature_names)
print('done')
예제 #12
0
def get_instance_explanations(X, Y, subset = 1000, classifier_index = "gradient_boosting", explanation_method = "shap", shap_explainer = "kernel", text = False):
    
    """
    A set of calls for obtaining aggregates of explanations.
    """
    ## label encoding
    #lab_enc = preprocessing.LabelEncoder()
    #training_scores_encoded = lab_enc.fit_transform(Y)
    # TODO: zakaj je potreben label encoder?

    training_scores_encoded = Y
    if text:
        vectorizer = TfidfVectorizer(analyzer='word',stop_words= 'english')
        X_vectorized = vectorizer.fit_transform(X)
        #print(X_vectorized)
        X_vectorized = X_vectorized.todense()
        #print(X_vectorized)
        X = pd.DataFrame(X_vectorized)
        X.columns = vectorizer.get_feature_names()
        #X.columns = vectorizer.get_feature_names()
    logging.info("Feature pre-selection via Mutual Information ({}).".format(subset))
    #X = X.iloc[:,1:100]
    minf = mutual_info_classif(X.values, training_scores_encoded)
    top_k = np.argsort(minf)[::-1][0:subset]
    attribute_vector = X.columns[top_k]
    X = X.astype(float).values[:,top_k]
    skf = StratifiedKFold(n_splits=10)
    performances = []
    enx = 0
    t_start = time.time()
    logging.info("Starting importance estimation ..  shape: {}".format(X.shape))

    per_class_explanations = defaultdict(list)
    classifier_mapping = ["gradient_boosting", "random_forest", "svm"]
    classifiers = [GradientBoostingClassifier(), RandomForestClassifier(n_estimators=10), svm.SVC(probability=True)] ## spyct.Model()

    model_dict = dict(zip(classifier_mapping, classifiers))
    
    if explanation_method == "shap":
        logging.info("Shapley-based explanations.")
        ## for the correctly predicted instances, remember shap values and compute the expected value at the end.
        for train_index, test_index in skf.split(X, Y):
            enx+=1
            clf = model_dict[classifier_index]
            x_train = X[train_index]
            x_test = X[test_index]
            
            y_train = Y[train_index]
            y_test = Y[test_index]

            ## perform simple feature ranking
            minf = mutual_info_classif(x_train, y_train)
            top_k = np.argsort(minf)[::-1][0:subset]
            x_train = x_train[:,top_k]
            x_test = x_test[:,top_k]

            x_train = x_train.astype('float')
            y_train = y_train.astype('float')
            x_test = x_test.astype('float')
            y_test = y_test.astype('float')

            model = clf.fit(x_train, y_train)
            preds = model.predict(x_test)
            if len(np.unique(y_train)) > 1:
                average = "micro"
            perf = f1_score(preds,y_test, average = average)
            performances.append(perf)
            logging.info("Performance in fold {}, {} (F1)".format(enx, perf))
            ## different shap explainers
            if shap_explainer == "kernel":
                explainer = shap.KernelExplainer(model.predict_proba, x_train)
            if shap_explainer == "tree":
                explainer = shap.TreeExplainer(model.predict_proba, x_train)
            if shap_explainer == "gradient":
                explainer = shap.GradientExplainer(model.predict_proba, x_train)
            if shap_explainer == "deep":
                explainer = shap.DeepExplainer(model.predict_proba, x_train)
            if shap_explainer == "sampling":
                explainer = shap.SamplingExplainer(model.predict_proba, x_train)
            if shap_explainer == "partition":
                explainer = shap.PartitionExplainer(model.predict_proba, x_train)

            for unique_class in set(preds):
                cors_neg = np.array([enx for enx, pred_tuple in enumerate(zip(preds, y_test)) if pred_tuple[0] == pred_tuple[1] and pred_tuple[0] == unique_class])
                if cors_neg.size != 0:
                    shap_values = explainer.shap_values(x_test[cors_neg], nsamples = 10, verbose = False)
                    stack = np.mean(np.vstack(shap_values),axis = 0)
                    per_class_explanations[unique_class].append(stack)

        final_explanations = {}
        for class_name, explanation_set in per_class_explanations.items():
            final_explanations[class_name] = np.mean(np.matrix(explanation_set),axis = 0)
        average_perf = (np.mean(performances), np.std(performances))
        logging.info("Final performance: {}".format(average_perf))

    elif explanation_method == "class-ranking":
        logging.info("Ranking-based explanations.")
        unique_scores = np.unique(training_scores_encoded)
        final_explanations = {}
        for label in unique_scores:
            inx = np.where(training_scores_encoded == label)
            tx = VarianceThreshold().fit(X[inx]).variances_
            final_explanations[str(label)] = tx

    t_end = time.time() - t_start
    logging.info("Time spent on explanation estimation {}s.".format(t_end))


    return (final_explanations, attribute_vector)
예제 #13
0
def train(num_clients, num_rounds, train_loader, test_loader,
          backdoor_test_loader, losses_train, losses_test, acc_train, acc_test,
          backdoor_acc_test, misclassification_rates,
          targeted_misclassification_rates, attack_success_rates,
          communication_rounds, clients_local_updates, global_update, source,
          target, euclid_dist_roundwise, autoencoder_test_data_roundwise,
          shap_data_roundwise, defense):
    # Initialize model and Optimizer

    # Initialize model
    global_model = Model_FashionMNIST()
    global_model_copy = copy.copy(global_model)
    # create K (num_clients)  no. of client_models
    client_models = [Model_FashionMNIST() for _ in range(num_clients)]

    # synchronize with global_model
    for model in client_models:
        model.load_state_dict(global_model_copy.state_dict()
                              )  # initial synchronizing with global model

    # create optimizers for client_models
    optimizer = [
        optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)
        for model in client_models
    ]

    # List containing info about learning

    # Runnining FL
    #attack_success_rate = 0

    # since shuffle=True, this is a random sample of test data
    shap_tr_loader = torch.utils.data.DataLoader(shap_background,
                                                 batch_size=128,
                                                 shuffle=True)
    batch_shap = next(iter(shap_tr_loader))
    images_shap, _ = batch_shap
    background = images_shap[:100]
    #n_test_images = 5
    #test_images = images_shap[100:100+n_test_images]
    test_images = torch.zeros(1, 1, 28, 28)
    #images.size()

    for r in range(num_rounds):
        # client update
        loss = 0
        for i in tqdm(range(num_clients)):
            loss += client_update(client_models[i],
                                  train_loader[i],
                                  optimizer[i],
                                  epoch=epochs)

        #comment out today
        if (defense):

            model_to_aggregate = []
            threshold = 1.8
            print('round : {}'.format(r))
            id = 0
            shap_data_temp = []
            for model in client_models:
                e = shap.DeepExplainer(model, background)
                shap_values = e.shap_values(test_images)
                #print(shap_values)
                print('client id : {}'.format(id))
                id += 1
                shap_data_temp_model = []
                #print('length : {}'.format(len(shap_values)))
                for i in range(10):
                    #print(torch.sum(torch.tensor(shap_values[i])))
                    shap_data_temp_model.append(
                        torch.sum(torch.tensor(shap_values[i])))
                shap_data_temp.append(shap_data_temp_model)
                # rehspae the shap value array and test image array for visualization
                #shap_numpy2 = [np.swapaxes(np.swapaxes(s, 1, -1), 1, 2) for s in shap_values]
                #test_numpy2 = np.swapaxes(np.swapaxes(test_images.numpy(), 1, -1), 1, 2)
                # plot the feature attributions
                #shap.image_plot(shap_numpy2, -test_numpy2)
                temp = []
                for shap_label in shap_data_temp_model:
                    temp.append(shap_label.detach().item())
                z_score = np.abs(stats.zscore(temp))
                print(z_score)
                flag = True
                for j in range(len(z_score)):
                    if z_score[j] > threshold:
                        print('client {} not appended'.format(id))
                        flag = False
                        break

                if flag == True:
                    print('client {} is aggregated'.format(id))
                    model_to_aggregate.append(copy.copy(model))

            shap_data_roundwise.append(shap_data_temp)

            temp_updates_clients = []
            for i in range(num_clients):
                temp_updates_clients.append(copy.copy(client_models[i]))
            clients_local_updates.append(temp_updates_clients)
            global_update.append(global_model)
            losses_train.append(loss)
            communication_rounds.append(r + 1)

            server_aggregate_defense(global_model, client_models,
                                     model_to_aggregate)
        else:
            temp_updates_clients = []
            for i in range(num_clients):
                temp_updates_clients.append(copy.copy(client_models[i]))
            clients_local_updates.append(temp_updates_clients)
            global_update.append(global_model)
            losses_train.append(loss)
            communication_rounds.append(r + 1)

            server_aggregate(global_model, client_models)

        #comment out today
        #x = 0
        #for client_shap in shap_data_temp:
        #  print('client {}'.format(x))
        #  x += 1
        #  csdata = copy.copy(client_shap)
        #  med1 = torch.median(torch.tensor(csdata))
        #  for i in range(len(csdata)):
        #    csdata[i] = abs(csdata[i] - med1)
        #  md = torch.median(torch.tensor(csdata))
        #  mad = md*1.4826
        #  for i in range(len(csdata)):
        #    csdata[i] = csdata[i]/mad
        #  print(csdata)

        #print(shap_data_temp)
        '''
      #check euclidean distance

      print("checking Euclidean distances")
      for i in range(num_clients-1):
        for j in range(i+1,num_clients):
          print('distance b/w client{} and client{} : {}'.format(i,j,euclidean_distance(client_models[i],client_models[j])))
      '''

        #for i in range(len(client_models)):
        #  for j in range(i+1,len(client_models)):
        #    temp = torch.norm(torch.cdist(client_models[i].fc1.weight,client_models[j].fc1.weight))
        #    print('dist b/w client{} and client {} is {}'.format(i+1,j+1,temp))
        '''
      euclid_dist_temp = []
      for i in range(len(client_models)):
        total_dist = 0
        count = 0
        for j in range(len(client_models)):
          if i!= j:
            total_dist += torch.norm(torch.cdist(client_models[i].fc1.weight,client_models[j].fc1.weight))
            count += 1
        print('dist b/w client{} and other clients is {}'.format(i+1,total_dist/count))
        euclid_dist_temp.append(total_dist/count)
      euclid_dist_roundwise.append(euclid_dist_temp)
      
      
      
      if r < 20:
        #calculate dataset for autoencoder
        for model in client_models:
          temp = []
          for i in range(len(model.fc1.weight)):
            for j in range(32):
              temp.append(model.fc1.weight[i][j])
        #print('vector size',len(temp))
          dataAE.append(temp)

      elif r == 20:
        modelAE = AE()
        criterion_ae = nn.MSELoss()
        optimizer_ae = optim.Adam(modelAE.parameters(), lr=0.0001)
        tr_data = torch.Tensor(dataAE)
        trloader = torch.utils.data.DataLoader(tr_data, batch_size=32, shuffle=True)
        for epoch in range(20):
          ae_loss = 0
          for batch_ae in trloader:
            optimizer_ae.zero_grad()
            outputs = modelAE(batch_ae)
            tr_loss = criterion_ae(outputs, batch_ae)
            tr_loss.backward()
            optimizer_ae.step()
            ae_loss += tr_loss.item()
          ae_loss = ae_loss / len(trloader)
          print("epoch : {}/{}, reconstruction loss = {:.8f}".format(epoch + 1, epochs, ae_loss))
      else:
        ae_rounds_test_data = []
        for model in client_models:
          input_test = []
          for i in range(len(model.fc1.weight)):
            for j in range(32):
              input_test.append(model.fc1.weight[i][j])
          output_test = modelAE(torch.Tensor(input_test))
          te_loss = criterion_ae(output_test, torch.Tensor(input_test))
          print('test_loss {:.8f}'.format(te_loss))
          ae_rounds_test_data.append(te_loss)
        autoencoder_test_data_roundwise.append(ae_rounds_test_data)
      
     '''

        #append clinet models and global models at the start of every round

        #temp_updates_clients = []
        #for i in range(num_clients):
        #  temp_updates_clients.append(copy.copy(client_models[i]))

        #clients_local_updates.append(temp_updates_clients)
        #global_update.append(global_model)

        #losses_train.append(loss)
        #communication_rounds.append(r+1)

        # server aggregate
        #server_aggregate(global_model, client_models)
        #defense
        #server_aggregate_defense(global_model, client_models, model_to_aggregate)
        # calculate test accuracy after the current round
        test_loss, acc, asr, mcr, tmcr = test(global_model, test_loader,
                                              source, target)
        backdoor_test_loss, back_acc = backdoor_test(global_model,
                                                     backdoor_test_loader, 2)
        losses_test.append(test_loss)
        acc_test.append(acc)
        backdoor_acc_test.append(back_acc)
        misclassification_rates.append(mcr)
        targeted_misclassification_rates.append(tmcr)
        attack_success_rates.append(asr)
        print("attack success rate : ", asr)
        print("misclassification rate ", mcr)
        #attack_success_rate = asr

        print('%d-th round' % (r + 1))
        print('average train loss %0.3g | test loss %0.3g | test acc: %0.3f' %
              (loss / num_clients, test_loss, acc))
        print('backdoor accuracy {}'.format(back_acc))
    #    
    #    TimeDistributed(Dense(out.shape[2]*20)),
    ##    
    #    TimeDistributed(Dense(32,)),
    #    
    TimeDistributed(Dense(1), name='test'),

    Reshape((375,)),


])
# optimizer = optimizers.Adam(clipvalue=0.5)
#optimizer = optimizers.Adam(clipnorm=1.)
#     model = multi_gpu_model(model, gpus=6)
model_1.compile(loss=kl.mean_absolute_error, optimizer = 'adam',metrics=['accuracy'])
model_1.summary()

hist_1 = model_1.fit(input_bus, output_bus, epochs=30,
                              batch_size=20, verbose=1, shuffle=False)

with open('caseof.pickles','wb') as p:
    pickle.dump(model_1,p)
    pickle.dump(hist_1,p)
# In[2]
with open('caseof.pickles','rb') as p:
    model = pickle.load(p)
    hist = pickle.load(p)
valo = sequence.pad_sequences(valo)

explainer = shap.DeepExplainer(model, tf.convert_to_tensor(input_bus[:239,:,2:,:,:],dtype = 'float32'))
예제 #15
0
def test_pytorch_regression():
    """Testing regressions (i.e. single outputs)
    """
    try:
        import torch
        from torch import nn
        from torch.nn import functional as F
        from torch.utils.data import TensorDataset, ConcatDataset, DataLoader
        from sklearn.datasets import load_boston
    except Exception as e:
        print("Skipping test_pytorch_regression!")
        return
    import shap

    X, y = load_boston(return_X_y=True)
    num_features = X.shape[1]
    data = TensorDataset(torch.tensor(X).float(),
                         torch.tensor(y).float())
    loader = DataLoader(data, batch_size=128)

    class Net(nn.Module):
        def __init__(self, num_features):
            super(Net, self).__init__()
            self.linear = nn.Linear(num_features, 1)

        def forward(self, X):
            return self.linear(X)
    model = Net(num_features)
    optimizer = torch.optim.Adam(model.parameters())

    def train(model, device, train_loader, optimizer, epoch):
        model.train()
        num_examples = 0
        for batch_idx, (data, target) in enumerate(train_loader):
            num_examples += target.shape[0]
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = F.mse_loss(output.squeeze(1), target)
            loss.backward()
            optimizer.step()
            if batch_idx % 2 == 0:
                print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                    epoch, batch_idx * len(data), len(train_loader.dataset),
                           100. * batch_idx / len(train_loader), loss.item()))

    device = torch.device('cpu')
    train(model, device, loader, optimizer, 1)

    next_x, next_y = next(iter(loader))
    np.random.seed(0)
    inds = np.random.choice(next_x.shape[0], 20, replace=False)
    e = shap.DeepExplainer(model, next_x[inds, :])
    test_x, test_y = next(iter(loader))
    shap_values = e.shap_values(test_x[:1])

    model.eval()
    model.zero_grad()
    with torch.no_grad():
        diff = (model(test_x[:1]) - model(next_x[inds, :])).detach().numpy().mean(0)
    sums = np.array([shap_values[i].sum() for i in range(len(shap_values))])
    d = np.abs(sums - diff).sum()
    assert d / np.abs(diff).sum() < 0.001, "Sum of SHAP values does not match difference! %f" % (
            d / np.abs(diff).sum())
예제 #16
0
def train(num_clients, num_rounds, train_loader, test_loader,
          backdoor_test_loader, losses_train, losses_test, acc_train, acc_test,
          backdoor_acc_test, misclassification_rates,
          targeted_misclassification_rates, attack_success_rates,
          communication_rounds, clients_local_updates, global_update, source,
          target, euclid_dist_roundwise, autoencoder_test_data_roundwise,
          shap_data_roundwise, defense, defense_type):
    # Initialize model and Optimizer

    # Initialize model
    global_model = Model_FashionMNIST()
    global_model_copy = copy.copy(global_model)
    # create K (num_clients)  no. of client_models
    client_models = [Model_FashionMNIST() for _ in range(num_clients)]

    # synchronize with global_model
    for model in client_models:
        model.load_state_dict(global_model_copy.state_dict()
                              )  # initial synchronizing with global model

    # create optimizers for client_models
    optimizer = [
        optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)
        for model in client_models
    ]

    shap_tr_loader = torch.utils.data.DataLoader(shap_background,
                                                 batch_size=128,
                                                 shuffle=True)
    batch_shap = next(iter(shap_tr_loader))
    images_shap, _ = batch_shap
    background = images_shap[:100]
    test_images = torch.zeros(1, 1, 28, 28)

    for r in range(num_rounds):
        # client update
        loss = 0
        for i in tqdm(range(num_clients)):
            loss += client_update(client_models[i],
                                  train_loader[i],
                                  optimizer[i],
                                  epoch=epochs)

        if (defense):

            if defense_type == 'geomed':
                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)
                server_aggregate_GeoMed(global_model, client_models)
            elif defense_type == 'trimmedmean':
                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)
                server_aggregate_TrimmedMean(global_model, client_models)
            elif defense_type == 'fedavg':
                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)
                server_aggregate(global_model, client_models)
            elif defense_type == 'krum':
                c = 6  # corrupted worker
                n = 30  # participants in a round
                euclid_dist_temp = []
                lb = c // 2 + 1
                ub = n - c // 2 - 1
                for i in range(len(client_models)):
                    client_i_dist = []
                    for j in range(len(client_models)):
                        if i != j:
                            dist = torch.norm(
                                torch.cdist(client_models[i].fc1.weight,
                                            client_models[j].fc1.weight))
                            client_i_dist.append(dist)
                    print(client_i_dist)
                    sqdist_i = torch.sum(
                        torch.sort(torch.tensor(client_i_dist)).values[lb:ub])
                    euclid_dist_temp.append(sqdist_i)
                    print('dist of client{} and other clients is {}'.format(
                        i + 1, sqdist_i))
                mindist = euclid_dist_temp[0]
                next_client_index = 0
                for i in range(len(euclid_dist_temp)):
                    if euclid_dist_temp[i] < mindist:
                        mindist = euclid_dist_temp[i]
                        next_client_index = i
                print('min dist : {}'.format(mindist))
                print('next index : {}'.format(next_client_index + 1))
                euclid_dist_roundwise.append(euclid_dist_temp)

                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)

                global_model.load_state_dict(
                    client_models[next_client_index].state_dict())
                for model in client_models:
                    model.load_state_dict(global_model.state_dict())
                #server_aggregate(global_model, client_models)
            elif defense_type == 'moat':
                model_to_aggregate = []
                threshold = 1.8
                print('round : {}'.format(r))
                id = 0
                shap_data_temp = []
                for model in client_models:
                    e = shap.DeepExplainer(model, background)
                    shap_values = e.shap_values(test_images)
                    print('client id : {}'.format(id))
                    id += 1
                    shap_data_temp_model = []
                    for i in range(10):
                        shap_data_temp_model.append(
                            torch.sum(torch.tensor(shap_values[i])))
                    shap_data_temp.append(shap_data_temp_model)
                    temp = []
                    for shap_label in shap_data_temp_model:
                        temp.append(shap_label.detach().item())
                    z_score = np.abs(stats.zscore(temp))
                    print(z_score)
                    flag = True
                    for j in range(len(z_score)):
                        if z_score[j] > threshold:
                            print('client {} not appended'.format(id))
                            flag = False
                            break
                    if flag == True:
                        print('client {} is aggregated'.format(id))
                        model_to_aggregate.append(copy.copy(model))

                shap_data_roundwise.append(shap_data_temp)

                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)
                server_aggregate_defense(global_model, client_models,
                                         model_to_aggregate)
            elif defense_type == 'ae':
                model_to_aggregate = []
                if r < 20:
                    for model in client_models:
                        temp = []
                        for i in range(len(model.fc1.weight)):
                            for j in range(32):
                                temp.append(model.fc1.weight[i][j])
                        dataAE.append(temp)

                    #aggregate
                    temp_updates_clients = []
                    for i in range(num_clients):
                        temp_updates_clients.append(copy.copy(
                            client_models[i]))
                    clients_local_updates.append(temp_updates_clients)
                    global_update.append(global_model)
                    losses_train.append(loss)
                    communication_rounds.append(r + 1)
                    server_aggregate(global_model, client_models)
                elif r == 20:
                    modelAE = AE()
                    criterion_ae = nn.MSELoss()
                    optimizer_ae = optim.Adam(modelAE.parameters(), lr=0.0001)
                    tr_data = torch.Tensor(dataAE)
                    trloader = torch.utils.data.DataLoader(tr_data,
                                                           batch_size=32,
                                                           shuffle=True)
                    for epoch in range(20):
                        ae_loss = 0
                        for batch_ae in trloader:
                            optimizer_ae.zero_grad()
                            outputs = modelAE(batch_ae)
                            tr_loss = criterion_ae(outputs, batch_ae)
                            tr_loss.backward()
                            optimizer_ae.step()
                            ae_loss += tr_loss.item()
                        ae_loss = ae_loss / len(trloader)
                        print("epoch : {}/{}, reconstruction loss = {:.8f}".
                              format(epoch + 1, epochs, ae_loss))

                    #aggregate
                    temp_updates_clients = []
                    for i in range(num_clients):
                        temp_updates_clients.append(copy.copy(
                            client_models[i]))
                    clients_local_updates.append(temp_updates_clients)
                    global_update.append(global_model)
                    losses_train.append(loss)
                    communication_rounds.append(r + 1)
                    server_aggregate(global_model, client_models)
                else:
                    ae_rounds_test_data = []
                    for model in client_models:
                        input_test = []
                        for i in range(len(model.fc1.weight)):
                            for j in range(32):
                                input_test.append(model.fc1.weight[i][j])
                        output_test = modelAE(torch.Tensor(input_test))
                        te_loss = criterion_ae(output_test,
                                               torch.Tensor(input_test))
                        print('test_loss {:.8f}'.format(te_loss))
                        ae_rounds_test_data.append(te_loss)

                    ae_loss_round = []
                    for ae_loss in ae_rounds_test_data:
                        ae_loss_round.append(ae_loss.detach().item())
                    sigma = min(ae_loss_round)
                    anomaly_score = []
                    for el in ae_loss_round:
                        x = 1 + el
                        y = 1 + sigma
                        anomaly_score.append(x / y)
                    threshold = statistics.mean(anomaly_score)
                    for i in range(len(anomaly_score)):
                        if anomaly_score[i] < threshold:
                            print('client {} is aggregated'.format(i + 1))
                            model_to_aggregate.append(
                                copy.copy(client_models[i]))
                        else:
                            print('client {} not appended'.format(i + 1))
                    autoencoder_test_data_roundwise.append(ae_rounds_test_data)

                    temp_updates_clients = []
                    for i in range(num_clients):
                        temp_updates_clients.append(copy.copy(
                            client_models[i]))
                    clients_local_updates.append(temp_updates_clients)
                    global_update.append(global_model)
                    losses_train.append(loss)
                    communication_rounds.append(r + 1)

                    server_aggregate_defense(global_model, client_models,
                                             model_to_aggregate)
            else:
                temp_updates_clients = []
                for i in range(num_clients):
                    temp_updates_clients.append(copy.copy(client_models[i]))
                clients_local_updates.append(temp_updates_clients)
                global_update.append(global_model)
                losses_train.append(loss)
                communication_rounds.append(r + 1)
                server_aggregate(global_model, client_models)
        else:
            temp_updates_clients = []
            for i in range(num_clients):
                temp_updates_clients.append(copy.copy(client_models[i]))
            clients_local_updates.append(temp_updates_clients)
            global_update.append(global_model)
            losses_train.append(loss)
            communication_rounds.append(r + 1)
            server_aggregate(global_model, client_models)

        # calculate test accuracy after the current round
        test_loss, acc, asr, mcr, tmcr = test(global_model, test_loader,
                                              source, target)
        backdoor_test_loss, back_acc = backdoor_test(global_model,
                                                     backdoor_test_loader, 2)
        losses_test.append(test_loss)
        acc_test.append(acc)
        backdoor_acc_test.append(back_acc)
        misclassification_rates.append(mcr)
        targeted_misclassification_rates.append(tmcr)
        attack_success_rates.append(asr)
        print("attack success rate : ", asr)
        print("misclassification rate ", mcr)
        #attack_success_rate = asr

        print('%d-th round' % (r + 1))
        print('average train loss %0.3g | test loss %0.3g | test acc: %0.3f' %
              (loss / num_clients, test_loss, acc))
        print('backdoor accuracy {}'.format(back_acc))
예제 #17
0
def test_tf_keras_mnist_cnn():
    """ This is the basic mnist cnn example from keras.
    """

    try:
        from tensorflow import keras
        from tensorflow.keras.models import Sequential
        from tensorflow.keras.layers import Dense, Dropout, Flatten, Activation
        from tensorflow.keras.layers import Conv2D, MaxPooling2D
        from tensorflow.keras import backend as K
        import tensorflow as tf
    except Exception as e:
        print("Skipping test_tf_keras_mnist_cnn!")
        return
    import shap

    batch_size = 128
    num_classes = 10
    epochs = 1

    # input image dimensions
    img_rows, img_cols = 28, 28

    # the data, split between train and test sets
    (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

    if K.image_data_format() == 'channels_first':
        x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
        x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
        input_shape = (1, img_rows, img_cols)
    else:
        x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
        x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
        input_shape = (img_rows, img_cols, 1)

    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255
    x_test /= 255

    # convert class vectors to binary class matrices
    y_train = keras.utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.to_categorical(y_test, num_classes)

    model = Sequential()
    model.add(Conv2D(8, kernel_size=(3, 3),
                     activation='relu',
                     input_shape=input_shape))
    model.add(Conv2D(16, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    model.add(Flatten())
    model.add(Dense(32, activation='relu')) # 128
    model.add(Dropout(0.5))
    model.add(Dense(num_classes))
    model.add(Activation('softmax'))

    model.compile(loss=keras.losses.categorical_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])

    model.fit(x_train[:1000,:], y_train[:1000,:],
              batch_size=batch_size,
              epochs=epochs,
              verbose=1,
              validation_data=(x_test[:1000,:], y_test[:1000,:]))

    # explain by passing the tensorflow inputs and outputs
    np.random.seed(0)
    inds = np.random.choice(x_train.shape[0], 10, replace=False)
    e = shap.DeepExplainer((model.layers[0].input, model.layers[-1].input), x_train[inds,:,:])
    shap_values = e.shap_values(x_test[:1])

    sess = tf.keras.backend.get_session()
    diff = sess.run(model.layers[-1].input, feed_dict={model.layers[0].input: x_test[:1]}) - \
    sess.run(model.layers[-1].input, feed_dict={model.layers[0].input: x_train[inds,:,:]}).mean(0)

    sums = np.array([shap_values[i].sum() for i in range(len(shap_values))])
    d = np.abs(sums - diff).sum()
    assert d / np.abs(diff).sum() < 0.001, "Sum of SHAP values does not match difference! %f" % d
예제 #18
0
파일: mnist.py 프로젝트: Gouet/SHAP_MNIST
x = tf.keras.layers.Conv2D(32, (3, 3), activation='relu')(inputs)
x = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(128, activation='relu')(x)
out = tf.keras.layers.Dense(num_classes, activation='softmax')(x)

model = tf.keras.Model(inputs=[inputs], outputs=out)

model.compile(loss=tf.keras.losses.categorical_crossentropy,
              optimizer=tf.keras.optimizers.Adam(),
              metrics=['accuracy'])

model.fit(x_train,
          y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))

# select a set of background examples to take an expectation over
background = x_train[np.random.choice(x_train.shape[0], 100, replace=False)]

# explain predictions of the model on four images
e = shap.DeepExplainer(model, background)
# ...or pass tensors directly
# e = shap.DeepExplainer((model.layers[0].input, model.layers[-1].output), background)
shap_values = e.shap_values(x_test[1:5])

# plot the feature attributions
shap.image_plot(shap_values, -x_test[1:5])
예제 #19
0
def train(num_clients, num_rounds, train_loader, test_loader,
          backdoor_test_loader, losses_train, losses_test, acc_train, acc_test,
          backdoor_acc_test, misclassification_rates, attack_success_rates,
          communication_rounds, clients_local_updates, global_update, source,
          target, euclid_dist_roundwise, autoencoder_test_data_roundwise,
          shap_data_roundwise, defense):
    # Initialize model and Optimizer

    # Initialize model
    global_model = Model_FashionMNIST()
    global_model_copy = copy.copy(global_model)
    # create K (num_clients)  no. of client_models
    client_models = [Model_FashionMNIST() for _ in range(num_clients)]

    # synchronize with global_model
    for model in client_models:
        model.load_state_dict(global_model_copy.state_dict()
                              )  # initial synchronizing with global model

    # create optimizers for client_models
    optimizer = [
        optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)
        for model in client_models
    ]

    # List containing info about learning

    # Runnining FL
    #attack_success_rate = 0

    # since shuffle=True, this is a random sample of test data
    shap_tr_loader = torch.utils.data.DataLoader(shap_background,
                                                 batch_size=128,
                                                 shuffle=True)
    batch_shap = next(iter(shap_tr_loader))
    images_shap, _ = batch_shap
    background = images_shap[:100]
    #n_test_images = 5
    #test_images = images_shap[100:100+n_test_images]
    test_images = torch.zeros(1, 1, 28, 28)
    #images.size()

    for r in range(num_rounds):
        # client update
        loss = 0
        for i in tqdm(range(num_clients)):
            loss += client_update(client_models[i],
                                  train_loader[i],
                                  optimizer[i],
                                  epoch=epochs)

        if (defense):

            model_to_aggregate = []
            threshold = 2
            print('round : {}'.format(r))
            id = 0
            shap_data_temp = []
            for model in client_models:
                e = shap.DeepExplainer(model, background)
                shap_values = e.shap_values(test_images)
                #print(shap_values)
                print('client id : {}'.format(id))
                id += 1
                shap_data_temp_model = []
                #print('length : {}'.format(len(shap_values)))
                for i in range(10):
                    #print(torch.sum(torch.tensor(shap_values[i])))
                    shap_data_temp_model.append(
                        torch.sum(torch.tensor(shap_values[i])))
                shap_data_temp.append(shap_data_temp_model)
                # rehspae the shap value array and test image array for visualization
                #shap_numpy2 = [np.swapaxes(np.swapaxes(s, 1, -1), 1, 2) for s in shap_values]
                #test_numpy2 = np.swapaxes(np.swapaxes(test_images.numpy(), 1, -1), 1, 2)
                # plot the feature attributions
                #shap.image_plot(shap_numpy2, -test_numpy2)
                temp = []
                for shap_label in shap_data_temp_model:
                    temp.append(shap_label.detach().item())
                z_score = np.abs(stats.zscore(temp))
                print(z_score)
                flag = True
                for j in range(len(z_score)):
                    if z_score[j] > threshold:
                        print('client {} not appended'.format(id))
                        flag = False
                        break

                if flag == True:
                    print('client {} is aggregated'.format(id))
                    model_to_aggregate.append(copy.copy(model))

            shap_data_roundwise.append(shap_data_temp)

            temp_updates_clients = []
            for i in range(num_clients):
                temp_updates_clients.append(copy.copy(client_models[i]))
            clients_local_updates.append(temp_updates_clients)
            global_update.append(global_model)
            losses_train.append(loss)
            communication_rounds.append(r + 1)
            server_aggregate_defense(global_model, client_models,
                                     model_to_aggregate)
        else:
            temp_updates_clients = []
            for i in range(num_clients):
                temp_updates_clients.append(copy.copy(client_models[i]))
            clients_local_updates.append(temp_updates_clients)
            global_update.append(global_model)
            losses_train.append(loss)
            communication_rounds.append(r + 1)
            server_aggregate(global_model, client_models)

        test_loss, acc, asr, mcr = test(global_model, test_loader, source,
                                        target)
        backdoor_test_loss, back_acc = backdoor_test(global_model,
                                                     backdoor_test_loader, 2)
        losses_test.append(test_loss)
        acc_test.append(acc)
        backdoor_acc_test.append(back_acc)
        misclassification_rates.append(mcr)
        attack_success_rates.append(asr)
        print("attack success rate : ", asr)
        print("misclassification rate ", mcr)
        #attack_success_rate = asr

        print('%d-th round' % (r + 1))
        print('average train loss %0.3g | test loss %0.3g | test acc: %0.3f' %
              (loss / num_clients, test_loss, acc))
        print('backdoor accuracy {}'.format(back_acc))
예제 #20
0
def explain_pic(shap_value_normal_path, shap_value_plug_path):
    # 构建SHAP解释器对测试数据进行解释
    MODEL_PATH = 'model_nsh_sequence/Cnn.weights.005-0.9110.hdf5'
    train_100_path = 'data_sequence/train_data_100.json'
    x_bg = json.load(open(train_100_path))
    bg_x = [
        np.array(x_bg[0][:50]),
        np.array(x_bg[1][:50]),
        np.array(x_bg[2][:50]),
        np.array(x_bg[3][:50]),
        np.array(x_bg[4][:50])
    ]
    model = load_model(MODEL_PATH, compile=False)
    explainer = shap.DeepExplainer(model, bg_x)
    print('build explainer')

    test_path = 'data_sequence/test_data.json'
    label_path = 'data_sequence/label.json'
    voc_path = 'data_sequence/logdisign_id_voc.json'
    x_test = json.load(open(test_path))
    y = json.load(open(label_path))
    voc = json.load(open(voc_path))
    voc_re = {value: key for key, value in voc.items()}
    voc_re[0] = 'pad'
    train_end, valid_end = int(0.7 * len(y)), int(0.8 * len(y))
    r = random.random
    random.seed(2)
    role_ids = list(y.keys())
    role_ids.sort()
    random.shuffle(role_ids, random=r)
    train_id, valid_id, test_id = role_ids[:train_end], role_ids[
        train_end + 1:valid_end], role_ids[valid_end:]
    plug_file_list = os.listdir(shap_value_plug_path)
    for file in plug_file_list:
        shap_value_np = np.load(shap_value_plug_path + file)
        role_id = file.split('.')[0]
        id_index = test_id.index(role_id)
        x = [
            np.array(x_test[0][id_index]),
            np.array(x_test[1][id_index]),
            np.array(x_test[2][id_index]),
            np.array(x_test[3][id_index]),
            np.array(x_test[4][id_index])
        ]
        voc_cnt = {}
        voc_shap_value = {}
        for i in range(5):
            for j in range(x[i].shape[0]):
                id = voc_re[x[i][j]]
                shap_value = shap_value_np[i][j]
                if id not in voc_cnt:
                    voc_cnt[id] = 1
                    voc_shap_value[id] = shap_value
                else:
                    voc_cnt[id] += 1
                    voc_shap_value[id] += shap_value
        id_name = []
        data = []
        shap_values = []
        for key, value in voc_cnt.items():
            id_name.append(key)
            data.append(value)
            shap_values.append(voc_shap_value[key])
        shap.force_plot(explainer.expected_value,
                        np.array(shap_values),
                        np.array(data),
                        feature_names=id_name,
                        matplotlib=True,
                        show=False)
        plt.savefig(
            'data_sequence/cnn/balance_local_bot/{}.pdf'.format(role_id),
            dpi=100,
            bbox_inches='tight')
        plt.close()

    normal_file_list = os.listdir(shap_value_normal_path)
    for file in normal_file_list:
        shap_value_np = np.load(shap_value_normal_path + file)
        role_id = file.split('.')[0]
        id_index = test_id.index(role_id)
        x = [
            np.array(x_test[0][id_index]),
            np.array(x_test[1][id_index]),
            np.array(x_test[2][id_index]),
            np.array(x_test[3][id_index]),
            np.array(x_test[4][id_index])
        ]
        voc_cnt = {}
        voc_shap_value = {}
        for i in range(5):
            for j in range(x[i].shape[0]):
                id = voc_re[x[i][j]]
                shap_value = shap_value_np[i][j]
                if id not in voc_cnt:
                    voc_cnt[id] = 1
                    voc_shap_value[id] = shap_value
                else:
                    voc_cnt[id] += 1
                    voc_shap_value[id] += shap_value
        id_name = []
        data = []
        shap_values = []
        for key, value in voc_cnt.items():
            id_name.append(key)
            data.append(value)
            shap_values.append(voc_shap_value[key])
        shap.force_plot(explainer.expected_value,
                        np.array(shap_values),
                        np.array(data),
                        feature_names=id_name,
                        matplotlib=True,
                        show=False)
        plt.savefig(
            'data_sequence/cnn/balance_local_normal/{}.pdf'.format(role_id),
            dpi=100,
            bbox_inches='tight')
        plt.close()