IsPartOfA
- class hybrid_learning.fuzzy_logic.predicates.custom_ops.IsPartOfA(in_key, *, kernel_size=10, thresh=0.1, logical_and=None, conv_hang_front=True, **other_setts)[source]
Bases:
TorchOperation
Unary predicate that calculates for each pixel location whether it is part of an object segmentation. The predicate accepts as input the segmentation mask information for objects (encoding the predicate “pixel
p
is aA
” =IsA(p)
). It returns a mask that for each pixel holds the truth value, whether that pixel is part of an object, i.e. at each pixel positionp
the output is\[\begin{split}\exists p_o: \text{IsA}(p_o) \wedge \text{IsPartOf}(p, p_o) \\ = \max_{p_o} \text{IsA}(p_o) \wedge \text{IsPartOf}(p, p_o)\end{split}\]It accepts 1D or 2D object masks of the shape
[[batch x [channels x]] height x] width
, in any format that can be parsed to atorch.Tensor
.Fuzzification
As fuzzification of the exists quantifier,
max
is used. Thelogical_and
defines the fuzzification ofAND
. The values of the predicateIsA(.)
are given by the pixel values of the input segmentation mask. The fuzzyIsPartOf
relation is chosen to calculate as a Gaussian distance, with a threshold of valuethresh
and distancethresh_radius=int(kernel_size - 1) / 2
for better computational performance:\[\begin{split}d(p, p') = \exp(- \frac{\|p - p'\|_2^2}{2 \sigma^2}) \\ \text{IsPartOf}(p, p') := \begin{cases} d(p, p') \text{if} \|p, p'\|_1 <= \text{thresh\_radius} \\ 0 \text{else} \end{cases}\end{split}\]with \(\sigma\) chosen such that \(d(p, p') = \text{thresh}\) for \(\|p - p'\|_2 = \text{thresh\_radius}\). The per-pixel values of the
IsPartOf
predicate are stored in the_ispartof_values
mask which is then convoluted with theIsA
values.Note
An even
kernel_size
will have the same_ispartof_values
pixel values as the oddkernel_size-1
, only with a row and a column added (on top/left forconv_hang_front
True
, else on bottom/right).Choosing the right ``kernel_size``
The shape of the used Gaussian can be defined by a pair of x-y-values
(r, t)
. The Gaussian then looks like\[G_{r,t}(x) = \exp\left(- \frac{ x^2 }{ \frac{r^2}{- \ln(t)}}} \right)\]As
thresh_radius
,int(kernel_size - 1) / 2
is used, which also serves as the cutoff distance. To choose thekernel_size
such that (1) the point(r, t)
lies on the Gaussian, and (2) thekernel_size
cuts at thresholdthresh
, solve \(G_{r,t}(\frac{\text{k}-1}{2}) = \text{thresh}\) for \(k\) and getskernel_size=int(k)
. E.g. to match the constraints that at 4 pixel shift (r=4
), \(G(r)\) should still be 0.8, and the kernel should only cut off at a threshold of 0.1, thekernel_size
must be2*int(12.4) + 1=25
.Visualization example
Visualization of the different logics:
>>> import hybrid_learning.fuzzy_logic as fl >>> import torch, torchvision.transforms.functional as F, matplotlib.pyplot as plt >>> # Builder for IsPartOf >>> P = fl.predicates.custom_ops.IsPartOfA.with_(kernel_size=10, thresh=0.01, conv_hang_front=False) >>> # The sample input mask >>> t = torch.zeros([1, 1, 11, 11]) >>> t[:, :, 4, 4], t[:, :, 5, 8] = 0.75, 0.5 >>> # The tensors to compare >>> figs = dict(segmask=t) # input >>> for logic in (fl.LukasiewiczLogic(), fl.ProductLogic(), fl.GoedelLogic()): ... title = f'IsPartOfA ({logic.__class__.__name__.replace("Logic", "")})' ... p = P("pedestrian", logical_and=logic.logical_('AND')) ... figs[title] = p({"pedestrian": t})[p.out_key] >>> # Plot >>> fig, axes = plt.subplots(1, len(figs), figsize=(len(figs)*3, 3), squeeze=False) >>> for i, (title, tens) in enumerate(figs.items()): ... shown_img = axes[0, i].imshow(F.to_pil_image(tens.view(t.size()[2:]))) ... _ = axes[0, i].set_title(title) >>> plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9) >>> cax = plt.axes([.85, .25, 0.01, 0.5]) >>> _ = plt.colorbar(shown_img, cax=cax, orientation='vertical') >>> plt.show()
Public Data Attributes:
The string symbol of this class (override for sub-classes).
The arity of the operation.
The size of the kernel to use.
The value the Gaussian should have at
1/2 kernel_size
.Whether the cutoff modelled by the
IsPartOfA
convolution should hang in the front dimensions in case of unequal padding.Settings to reproduce the instance.
Defaults used for settings.
Inherited from : py: class:Merge
The string symbol of this class (override for sub-classes).
The arity of the operation.
IS_COMMUTATIVE
Whether instances are equivalent to ones with permuted
in_keys
.is_variadic
Whether the instance is variadic.
Settings to reproduce the instance.
Defaults used for settings.
pretty_op_symb
Name of the operation symbol suitable for filenames etc.
children
The input keys which are child operations.
all_children
All children operations in the flattened computational tree, sorted depth first.
consts
The constant string keys in the input keys.
operation_keys
The list of keys used for this parent operation in original order (constants and children output keys).
all_in_keys
All string input keys both of self and of all child operations.
all_out_keys
Output keys of self and all child operations.
Inherited from : py: class:DictTransform
Settings to reproduce the instance.
Inherited from : py: class:Transform
IDENTITY_CLASS
The identity class or classes for composition / addition.
Settings to reproduce the instance.
Public Methods:
torch_operation
(mask)Calculate value of IsPartOfA predicate for given object segmentation mask.
Inherited from : py: class:TorchOperation
operation
(annotation_vals)Calculate the predicate output.
Inherited from : py: class:Merge
to_infix_notation
([sort_key, ...])Return an infix str encoding equal for differently sorted operations.
to_str
(**infix_notation_kwargs)Alias for
to_infix_notation()
.to_pretty_str
(**infix_notation_kwargs)Same as
to_str()
but using pretty operation names suitable for filenames etc.to_repr
([settings, defaults, sort_key, ...])Return str representation which can be used to reproduce and compare the instance.
treerecurse_replace_keys
(**replace_map)Return a new formula with all occurences of variables in
replace_map
replaced and else identical settings.treerecurse
(fun)Apply the given function recursively to this and all children instances.
apply_to
(annotations[, keep_keys])Apply this operation to the
annotations
dict.variadic_apply_to
(annotations)Return the result of operation on the values/items of a mapping or sequence of arbitrary length.
operation
(annotation_vals)Calculate the predicate output.
Inherited from : py: class:DictTransform
apply_to
(annotations[, keep_keys])Apply this operation to the
annotations
dict.Inherited from : py: class:Transform
apply_to
(annotations[, keep_keys])Apply this operation to the
annotations
dict.Special Methods:
__init__
(in_key, *[, kernel_size, thresh, ...])Init.
Inherited from : py: class:Merge
__init__
(in_key, *[, kernel_size, thresh, ...])Init.
__str__
()Return str(self).
__repr__
()Call
to_repr()
without sorting.__eq__
(other)Two merge operations are considered equal, if their normalized representations coincide.
__copy__
()Return a deep copy of self using settings.
__call__
(annotations[, keep_keys])Call method modifying a given dictionary.
Inherited from : py: class:DictTransform
__call__
(annotations[, keep_keys])Call method modifying a given dictionary.
Inherited from : py: class:Transform
__repr__
()Call
to_repr()
without sorting.__eq__
(other)Two merge operations are considered equal, if their normalized representations coincide.
__copy__
()Return a deep copy of self using settings.
__add__
(other)Return a flat composition of
self
withother
.__radd__
(other)Return a flat composition of
other
andself
.__call__
(annotations[, keep_keys])Call method modifying a given dictionary.
- Parameters
- __init__(in_key, *, kernel_size=10, thresh=0.1, logical_and=None, conv_hang_front=True, **other_setts)[source]
Init.
The parameters
kernel_size
andthresh
are specifiers for the distance function encoding the is-part-of relation. Thelogical_and
is the logicalAND
callable that accepts a list of two tensors with values in [0, 1] and returns their pixel-wise logicalAND
. Thein_key
is the key of the fuzzy mask which encodes the per-pixel membership degree to the class of interest. E.g. if “is part of a pedestrian” should be calculated,"pedestrian"
is a good choice.
- static create_ispartof_kernel(kernel_size, thresh, thresh_radius=None, conv_hang_front=True)[source]
Create the kernel tensor defining the
IsPartOf
relation. For details see_ispartof_values
.
- torch_operation(mask)[source]
Calculate value of IsPartOfA predicate for given object segmentation mask. Allowed mask shapes (1D-4D):
([[batch, [1,]] height,] width)
The output shape is that of the input mask. Invalid shapes raise aValueError
.The device of
mask
is used for calculations and will be the device of the output tensor. As a side effect, the internal storage of theIsPartOf
values is moved to that device, assuming that the device of inputs does not change frequently.
- property conv_hang_front: bool
Whether the cutoff modelled by the
IsPartOfA
convolution should hang in the front dimensions in case of unequal padding. Internals: To achieve hanging towards the back, the padding must be chosen to hang front.
- property kernel_size: int
The size of the kernel to use. The standard deviation of the gaussian is determined using this as radius and
thresh
.
- logical_and: Callable[[List[Tensor]], Tensor]
Callable accepting a list of two tensors with values in [0, 1] and returning their pixel-wise logical
AND
. Mandatory argument.
- property setting_defaults
Defaults used for settings.