def kl_divergence(self, q: collections.Mapping): """ Return the Kullback-Leibler divergence with probability distribution. This is given by the formula: $KL = \sum_i p_i \ln \frac {p_i} {q_i},$ in which p_i comes from the probability object and q_i comes from the argument. """ prob = self._data.get divergence = 0.0 visited = 0 for k, q in q.items(): visited += 1 p = prob(k, 0.0) if p: try: divergence += p and p * log(p / q) except ZeroDivisionError: return float('inf') if len(self._data) != visited: return float('inf') return divergence
def split_in_2_batches(batch: collections.Mapping, first_batch_size: int): """ Split a single batch into 2 batches. The first batch will have a fixed size. If there is not enough sample to split the batch, return (batch, None) Args: batch: the batch to split first_batch_size: the batch size of the first batch. The remaining samples will be in the second batch Returns: a tuple (first batch, second batch) """ batch_size = len_batch(batch) if batch_size <= first_batch_size: return batch, None # actually, split! batch_1 = type(batch)() batch_2 = type(batch)() for name, value in batch.items(): if isinstance(value, (np.ndarray, torch.Tensor, list)): # split the array/list batch_1[name] = value[:first_batch_size] batch_2[name] = value[first_batch_size:] else: # for other types, simply duplicate batch_1[name] = value batch_2[name] = value return batch_1, batch_2
def nested_dict_contains_key(ndict: collections.Mapping, key): if key in ndict: return True else: for k, v in ndict.items(): if isinstance(v, collections.Mapping): if nested_dict_contains_key(v, key): return True return False
def flatten_dict_by_joining( d: collections.Mapping, parent_key: Optional[str] = "", sep: Optional[str] = "-" ) -> collections.Mapping: items = [] for k, v in d.items(): new_k = sep.join([parent_key, k]) if parent_key else k if isinstance(v, collections.Mapping): items.extend(flatten_dict_by_joining(v, new_k, sep=sep).items()) else: items.append((new_k, v)) return dict(items)
def _check_event_handlers(self, value: collections.Mapping, level: int): if level > 0: for k, v in value.items(): if k.startswith('_on_'): assert 'name' in v, f'Missing name for the event handler \'{k}\'.' assert type( v['name'] ) == str, f'The name of event handler \'{k}\' MUST be a string.' assert 'args' in v, f'Missing args for the event handler \'{k}\'.' assert isinstance( v, collections.Mapping ), f'The args of event handler \'{k}\' MUST be an object.' if isinstance(v, collections.Mapping): self._check_event_handlers(v, level - 1)
def list_classes_from_mapping(mappinginv: collections.Mapping, default_name='unknown'): """ Create a contiguous list of label names ordered from 0..N from the class mapping :param mappinginv: a dictionary like structure encoded as (class id, class_name) :param default_name: if there is no class name, use this as default :return: a list of class names ordered from class id = 0 to class id = N. If `mappinginv` is None, returns None """ if mappinginv is None: return None nb_classes = max(mappinginv.keys()) + 1 classes = [default_name] * nb_classes for class_id, name in mappinginv.items(): classes[class_id] = name return classes
def nested_update(self, current: collections.Mapping, defaults: Dict[str, Any] = ...) -> Dict[str, Any]: """Robust updater for nested dictionaries If no defaults are passed, then the instance attribute 'defaults' will be used. """ if defaults is ...: defaults = self.defaults for key, value in current.items(): if isinstance(value, collections.Mapping): result = self.nested_update(value, defaults.get(key, {})) defaults[key] = result else: defaults[key] = deepcopy(current[key]) return defaults