def _infer_metadata_entries_from_model(self, signature_name): """Infers metadata inputs and outputs.""" loaded_sig = self._loaded_model.signatures[signature_name] _, input_sig = loaded_sig.structured_input_signature output_sig = loaded_sig.structured_outputs input_mds = {} for name, tensor_spec in input_sig.items(): if tensor_spec.dtype.is_floating: input_mds[name] = explain_metadata.InputMetadata(name, name) else: input_mds[name] = explain_metadata.InputMetadata( name, name, modality=explain_metadata.Modality.CATEGORICAL) if not self._explain_output and len(output_sig) > 1: raise ValueError( "Signature has multiple outputs. You must specify which" " output to explain via 'outputs_to_explain' parameter.") for name in output_sig: if not self._explain_output or self._explain_output[0] == name: output_mds = { name: explain_metadata.OutputMetadata(name, name) } break else: raise ValueError("Specified output name cannot be found in given" " signature outputs.") return input_mds, output_mds
def _create_input_metadata( self, features_dict: Dict[Text, List[monkey_patch_utils.FeatureTensors]], crossed_columns: Set[Text], desired_columns: List[Text], drop_duplicate_features: bool = False, group_duplicate_features: bool = False): """Creates and returns a list of InputMetadata. Args: features_dict: Dictionary from feature name to FeatureTensors class. crossed_columns: A set of crossed column names. desired_columns: A list of feature column names. Only the columns in this list will be added to input metadata. drop_duplicate_features: If there are multiple inputs for the same feature column, then we will drop all but one if drop_duplicate_features is True. If False, we will include them all with unique suffix added to the input names to disambiguate. group_duplicate_features: If there are multiple inputs for the same feature column, then we will group them all as one feature group if this parameter is set to True. Returns: A list of InputMetadata. """ input_mds = [] for fc_name, tensor_groups in features_dict.items(): if fc_name in desired_columns: for tensor_group in tensor_groups: input_md = self._get_input_tensor_names_for_metadata(tensor_group) if fc_name not in crossed_columns: input_md.update( self._get_encoded_tensor_names_for_metadata(tensor_group)) input_md['name'] = fc_name if self._baselines: input_md['input_baselines'] = self._baselines.get(fc_name, None) if len(tensor_groups) == 1 or drop_duplicate_features: input_mds.append(explain_metadata.InputMetadata(**input_md)) break # Skip other tensor_groups. # There are multiple inputs for the same feature column. # Append part of the tensor name until the first '/'. This usually # specifies what kind of model it is: linear or dnn. input_tensor_name = str(input_md['input_tensor_name']) suffix = input_tensor_name.split('/')[0] input_md['name'] = '%s_%s' % (fc_name, suffix) if group_duplicate_features: input_md['group_name'] = fc_name input_mds.append(explain_metadata.InputMetadata(**input_md)) return input_mds
def _create_input_metadata( self, features_dict: Dict[Text, List[monkey_patch_utils.FeatureTensors]], crossed_columns: Set[Text], desired_columns: List[Text]): """Creates and returns a list of InputMetadata. Args: features_dict: Dictionary from feature name to FeatureTensors class. crossed_columns: A set of crossed column names. desired_columns: A list of feature column names. Only the columns in this list will be added to input metadata. Returns: A list of InputMetadata. """ input_mds = [] if self._input_mds is not None: input_mds = self._input_mds input_names_processed = set([i.name for i in input_mds]) for fc_name, tensor_groups in features_dict.items(): if fc_name in desired_columns and fc_name not in input_names_processed: for tensor_group in tensor_groups: input_md = self._get_input_tensor_names_for_metadata( tensor_group) if fc_name not in crossed_columns: input_md.update( self._get_encoded_tensor_names_for_metadata( tensor_group)) input_md['name'] = fc_name if self._baselines: input_md['input_baselines'] = self._baselines.get( fc_name, None) if (len(tensor_groups) == 1 or self._duplicate_action == DuplicateAction.DROP): input_mds.append( explain_metadata.InputMetadata(**input_md)) break # Skip other tensor_groups. # There are multiple inputs for the same feature column. # Append part of the tensor name until the first '/'. This usually # specifies what kind of model it is: linear or dnn. input_tensor_name = str(input_md['input_tensor_name']) suffix = input_tensor_name.split('/')[0] input_md['name'] = '%s_%s' % (fc_name, suffix) if self._duplicate_action == DuplicateAction.GROUP: input_md['group_name'] = fc_name input_mds.append( explain_metadata.InputMetadata(**input_md)) return input_mds
def set_numeric_metadata(self, input_name, new_name=None, input_baselines=None, index_feature_mapping=None): """Sets an existing metadata identified by input as numeric with params. Args: input_name: Input name in the metadata to be set as numeric. new_name: Optional (unique) new name for this feature. input_baselines: A list of baseline values. Each baseline value can be a single entity or of the same shape as the model_input (except for the batch dimension). index_feature_mapping: A list of feature names for each index in the input tensor. Raises: ValueError: If input_name cannot be found in the metadata. """ if input_name not in self._inputs: raise ValueError("Input with with name '%s' does not exist." % input_name) name = new_name if new_name else input_name tensor_name = self._inputs.pop(input_name).input_tensor_name if index_feature_mapping: encoding = explain_metadata.Encoding.BAG_OF_FEATURES else: encoding = explain_metadata.Encoding.IDENTITY self._inputs[name] = explain_metadata.InputMetadata( name=name, input_tensor_name=tensor_name, input_baselines=input_baselines, index_feature_mapping=index_feature_mapping, encoding=encoding)
def set_image_metadata(self, input_name, new_name=None, input_baselines=None, visualization=None): """Sets an existing metadata identified by input as image with params. Args: input_name: Input name in the metadata to be set as numeric. new_name: Optional (unique) new name for this feature. input_baselines: A list of baseline values. Each baseline value can be a single entity or of the same shape as the model_input (except for the batch dimension). visualization: A dictionary specifying visualization parameters. Check out original documentation for possible keys and values: https://cloud.google.com/ai-platform/prediction/docs/ai-explanations/visualizing-explanations Raises: ValueError: If input_name cannot be found in the metadata. """ if input_name not in self._inputs: raise ValueError("Input with with name '%s' does not exist." % input_name) name = new_name if new_name else input_name tensor_name = self._inputs.pop(input_name).input_tensor_name self._inputs[name] = explain_metadata.InputMetadata( name=name, input_tensor_name=tensor_name, input_baselines=input_baselines, modality=explain_metadata.Modality.IMAGE, visualization=visualization)
def _add_input_metadata( self, input_tensor: tf.Tensor, name: Optional[Text] = None, encoded_tensor: Optional[tf.Tensor] = None, encoding: Optional[Text] = explain_metadata.Encoding.IDENTITY, input_baselines: Optional[List[Any]] = None, encoded_baselines: Optional[List[Any]] = None, modality: Optional[Text] = None, visualization: Optional[Union[Dict[ str, str], parameters.VisualizationParameters]] = None, index_feature_mapping: Optional[List[Any]] = None, domain: Optional[parameters.DomainInfo] = None): """Creates an InputMetadata object. Args: input_tensor: Input tensor for the metadata. name: Metadata name for the given input. encoded_tensor: Encoded tensor if a tensor representing categorical input is encoded to another tensor. encoding: Encoding type. One of the values in explain_metadata.Encoding. input_baselines: A list of baselines for the input tensor. encoded_baselines: A list of baselines for the encoded tensor. modality: Modality of the input. One of the values in explain_metadata.Modality. visualization: Visualization parameters for image inputs. It can either be a dictionary of inputs or VisualizationParameters. index_feature_mapping: A list of feature names for each index in the input tensor. domain: DomainInfo object specifying the range of the input feature. """ input_name = name if name else input_tensor.op.name encoded_tensor_name = (encoded_tensor.name if encoded_tensor is not None else None) if input_tensor.name in self._inputs: raise ValueError('Input tensor %s already exists' % input_name) if input_name in [input_md.name for input_md in self._inputs.values()]: raise ValueError('Input name %s already exists' % input_name) domain_dict = domain.asdict() if domain else None if (visualization and isinstance(visualization, parameters.VisualizationParameters)): visualization = visualization.asdict() self._inputs[input_tensor.name] = explain_metadata.InputMetadata( name=input_name, input_tensor_name=input_tensor.name, encoded_tensor_name=encoded_tensor_name, encoding=encoding, input_baselines=input_baselines, encoded_baselines=encoded_baselines, modality=modality, visualization=visualization, index_feature_mapping=index_feature_mapping, domain=domain_dict)
def set_categorical_metadata( self, input_name: str, new_name: Optional[str] = None, encoded_name: Optional[str] = None, encoding: str = explain_metadata.Encoding.IDENTITY, input_baselines: Optional[List[Union[types.TensorValue, types.Tensor]]] = None, encoded_baselines: Optional[List[Union[types.TensorValue, types.Tensor]]] = None ) -> None: """Sets an existing metadata identified by input as categorical with params. Args: input_name: Input name in the metadata to be set as numeric. new_name: Optional (unique) new name for this feature. encoded_name: Optional name of the tensor, which is the encoded version of the input tensor. It is potentially an output of an encoding function such as embedding. Each encoded_name should map to a unique input. encoding: Encoding type if encoded_tensor is provided. Possible values are {identity, bag_of_features, bag_of_features_sparse, indicator, combined_embedding, concat_embedding}. input_baselines: A list of baseline values. Each baseline value can be a single entity or of the same shape as the model_input (except for the batch dimension). encoded_baselines: A list of baseline values for the encoded tensor. Raises: ValueError: If input_name cannot be found in the metadata. """ if input_name not in self._inputs: raise ValueError("Input with with name '%s' does not exist." % input_name) name = new_name if new_name else input_name tensor_name = self._inputs.pop(input_name).input_tensor_name self._inputs[name] = explain_metadata.InputMetadata( name=name, input_tensor_name=tensor_name, input_baselines=input_baselines, encoded_tensor_name=encoded_name, encoded_baselines=encoded_baselines, modality=explain_metadata.Modality.CATEGORICAL, encoding=encoding)
def _add_input_metadata(self, input_tensor, name=None, encoded_tensor=None, encoding=explain_metadata.Encoding.IDENTITY, input_baselines=None, encoded_baselines=None, modality=None, visualization=None, index_feature_mapping=None): """Internal add metadata function that creates an InputMetadata object. Args: input_tensor: Input tensor for the metadata. name: Metadata name for the given input. encoded_tensor: Encoded tensor if a tensor representing categorical input is encoded to another tensor. encoding: Encoding type. One of the values in explain_metadata.Encoding. input_baselines: A list of baselines for the input tensor. encoded_baselines: A list of baselines for the encoded tensor. modality: Modality of the input. One of the values in explain_metadata.Modality. visualization: Visualization parameters for image inputs. index_feature_mapping: A list of feature names for each index in the input tensor. """ input_name = name if name else input_tensor.op.name encoded_tensor_name = (encoded_tensor.name if encoded_tensor is not None else None) if input_tensor.name in self._inputs: raise ValueError('Input tensor %s already exists' % input_name) if input_name in [input_md.name for input_md in self._inputs.values()]: raise ValueError('Input name %s already exists' % input_name) self._inputs[input_tensor.name] = explain_metadata.InputMetadata( name=input_name, input_tensor_name=input_tensor.name, encoded_tensor_name=encoded_tensor_name, encoding=encoding, input_baselines=input_baselines, encoded_baselines=encoded_baselines, modality=modality, visualization=visualization, index_feature_mapping=index_feature_mapping)
def set_image_metadata( self, input_name: str, new_name: Optional[str] = None, input_baselines: Optional[List[Union[types.TensorValue, types.Tensor]]] = None, visualization: Optional[Union[Dict[ str, str], parameters.VisualizationParameters]] = None, domain: Optional[parameters.DomainInfo] = None) -> None: """Sets an existing metadata identified by input as image with params. Args: input_name: Input name in the metadata to be set as numeric. new_name: Optional (unique) new name for this feature. input_baselines: A list of baseline values. Each baseline value can be a single entity or of the same shape as the model_input (except for the batch dimension). visualization: Either a dictionary of visualization parameters or VisualizationParameters instance. Using VisualizationParameters is recommended. If None, a default visualization will be selected based on the explanation method (IG/XRAI). domain: DomainInfo object specifying the range of the input feature. Raises: ValueError: If input_name cannot be found in the metadata. """ if input_name not in self._inputs: raise ValueError("Input with with name '%s' does not exist." % input_name) name = new_name if new_name else input_name tensor_name = self._inputs.pop(input_name).input_tensor_name if (visualization and isinstance(visualization, parameters.VisualizationParameters)): visualization = visualization.asdict() domain_dict = domain.asdict() if domain else None self._inputs[name] = explain_metadata.InputMetadata( name=name, input_tensor_name=tensor_name, input_baselines=input_baselines, modality=explain_metadata.Modality.IMAGE, visualization=visualization, domain=domain_dict)
def _create_input_metadata( self, features_dict: Dict[Text, List[monkey_patch_utils.FeatureTensors]], crossed_columns: Set[Text], desired_columns: List[Text]): """Creates and returns a list of InputMetadata. Args: features_dict: Dictionary from feature name to FeatureTensors class. crossed_columns: A set of crossed column names. desired_columns: A list of feature column names. Only the columns in this list will be added to input metadata. Returns: A list of InputMetadata. """ input_mds = [] for fc_name, tensor_groups in features_dict.items(): if fc_name in desired_columns: for tensor_group in tensor_groups: input_md = self._get_input_tensor_names_for_metadata( tensor_group) if fc_name not in crossed_columns: input_md.update( self._get_encoded_tensor_names_for_metadata( tensor_group)) if len(tensor_groups) == 1: input_name = fc_name else: # If there are multiple inputs for the same feature column, append # part of the tensor name until the first '/'. This usually # specifies what kind of model it is: linear or dnn. input_name = '%s_%s' % ( fc_name, input_md['input_tensor_name'].split('/')[0]) input_md['name'] = input_name input_mds.append( explain_metadata.InputMetadata(**input_md)) return input_mds
def _create_input_metadata_from_signature( signature_inputs: Dict[str, tf.Tensor] ) -> Dict[str, explain_metadata.InputMetadata]: """Creates InputMetadata from signature inputs.""" return {key: explain_metadata.InputMetadata(key, tensor.name) for key, tensor in signature_inputs.items()}