SeldonIO / alibi

Algorithms for explaining machine learning models
https://docs.seldon.io/projects/alibi/en/stable/
Other
2.35k stars 249 forks source link

CounterFactualProto does not take 3D categorical input? #320

Open tsunghao-huang opened 3 years ago

tsunghao-huang commented 3 years ago

I am using the CounterFactualProto to explain the prediction of a keras LSTM model. I have a input shape of (batch size, timestep, attributes) = (batch size, 86, 32). As indicated below.

cf_p = CounterFactualProto(model,
                         shape=(1, 86, 32),
                         beta=0.01,
                         theta = 10.,
                         cat_vars=cat_vars_ohe,
                         ohe=True,  # OHE flag
                         use_kdtree=True,
                         max_iterations=500,
                         feature_range=(0,1),
                        )

And here is the error I got.

---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\framework\ops.py in _create_c_op(graph, node_def, inputs, control_inputs, op_def)
   1811   try:
-> 1812     c_op = pywrap_tf_session.TF_FinishOperation(op_desc)
   1813   except errors.InvalidArgumentError as e:

InvalidArgumentError: Cannot reshape a tensor with 86 elements to shape [1,86,32] (2752 elements) for '{{node Reshape}} = Reshape[T=DT_FLOAT, Tshape=DT_INT32](TensorArrayStack/TensorArrayGatherV3, Reshape/shape)' with input shapes: [86], [3] and with input tensors computed as partial shapes: input[1] = [1,86,32].

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-27-f0611f2cf929> in <module>
     11                          feature_range=(0,1),
     12                          c_init = 1.,
---> 13                          c_steps = 5
     14                         )

~\Desktop\CF_BPM\venv\lib\site-packages\alibi\explainers\cfproto.py in __init__(self, predict, shape, kappa, beta, feature_range, gamma, ae_model, enc_model, theta, cat_vars, ohe, use_kdtree, learning_rate_init, max_iterations, c_init, c_steps, eps, clip, update_num_grad, write_dir, sess)
    541 
    542         if self.is_cat:  # map adv and adv_s to categories
--> 543             self.adv_cat = apply_map(self.adv, to_num=False)
    544             self.adv_cat_s = apply_map(self.adv_s, to_num=False)
    545         else:

~\Desktop\CF_BPM\venv\lib\site-packages\alibi\explainers\cfproto.py in apply_map(adv_to_map, to_num)
    467                     _, _, _, _, adv_map, _ = tf.while_loop(cond_loop, body_to_cat, loop_vars,
    468                                                            parallel_iterations=1, back_prop=True)
--> 469                 adv_map_stack = tf.reshape(adv_map.stack(), shape_adv_map)
    470                 return adv_map_stack
    471 

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\util\dispatch.py in wrapper(*args, **kwargs)
    199     """Call target, and fall back on dispatchers if there is a TypeError."""
    200     try:
--> 201       return target(*args, **kwargs)
    202     except (TypeError, ValueError):
    203       # Note: convert_to_eager_tensor currently raises a ValueError, not a

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\ops\array_ops.py in reshape(tensor, shape, name)
    193     A `Tensor`. Has the same type as `tensor`.
    194   """
--> 195   result = gen_array_ops.reshape(tensor, shape, name)
    196   tensor_util.maybe_set_static_shape(result, shape)
    197   return result

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\ops\gen_array_ops.py in reshape(tensor, shape, name)
   8232   # Add nodes to the TensorFlow graph.
   8233   _, _, _op, _outputs = _op_def_library._apply_op_helper(
-> 8234         "Reshape", tensor=tensor, shape=shape, name=name)
   8235   _result = _outputs[:]
   8236   if _execute.must_record_gradient():

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\framework\op_def_library.py in _apply_op_helper(op_type_name, name, **keywords)
    742       op = g._create_op_internal(op_type_name, inputs, dtypes=None,
    743                                  name=scope, input_types=input_types,
--> 744                                  attrs=attr_protos, op_def=op_def)
    745 
    746     # `outputs` is returned as a separate return value so that the output

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\framework\ops.py in _create_op_internal(self, op_type, inputs, dtypes, input_types, name, attrs, op_def, compute_device)
   3483           input_types=input_types,
   3484           original_op=self._default_original_op,
-> 3485           op_def=op_def)
   3486       self._create_op_helper(ret, compute_device=compute_device)
   3487     return ret

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\framework\ops.py in __init__(self, node_def, g, inputs, output_types, control_inputs, input_types, original_op, op_def)
   1973         op_def = self._graph._get_op_def(node_def.op)
   1974       self._c_op = _create_c_op(self._graph, node_def, inputs,
-> 1975                                 control_input_ops, op_def)
   1976       name = compat.as_str(node_def.name)
   1977     # pylint: enable=protected-access

~\Desktop\CF_BPM\venv\lib\site-packages\tensorflow\python\framework\ops.py in _create_c_op(graph, node_def, inputs, control_inputs, op_def)
   1813   except errors.InvalidArgumentError as e:
   1814     # Convert to ValueError for backwards compatibility.
-> 1815     raise ValueError(str(e))
   1816 
   1817   return c_op

ValueError: Cannot reshape a tensor with 86 elements to shape [1,86,32] (2752 elements) for '{{node Reshape}} = Reshape[T=DT_FLOAT, Tshape=DT_INT32](TensorArrayStack/TensorArrayGatherV3, Reshape/shape)' with input shapes: [86], [3] and with input tensors computed as partial shapes: input[1] = [1,86,32].

It seems the explainer has some problems taking 3D input. After a quick check into the source code, I think the explainer assumes 2D input only.

Would you please suggest any way around this?

Thanks.

jklaise commented 3 years ago

There shouldn't be a restriction on the dimensionality of the input, e.g. MNIST is (1, 28, 28, 1). It's possible though that we make some implicit assumptions in the source code, I'll have a look into this.

jklaise commented 3 years ago

Ah, I think the issue is that, indeed, for categorical variable support the assumption is that the input is 2D (tabular datasets). We would need to see if it's feasible to extend to more than 2D @arnaudvl .