Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor detector to allow for different standardizations of input features #562

Open
AMHermansen opened this issue Aug 4, 2023 · 0 comments
Labels
feature New feature or request

Comments

@AMHermansen
Copy link
Collaborator

AMHermansen commented Aug 4, 2023

Is your feature request related to a problem? Please describe.
Currently we are restricted to create a new detector class if we want to experiment with different standardization of input features. While it currently isn't an issue, we could easily in the future experience a large increase in detectors which for the most part are completely identical, except they do slightly different standardization.

Describe the solution you'd like
If we refactor the Detector class to contain include a class member containing the available features, and then for each feature we provide an instantiated FeatureStandardizer module, which handles the standardization of the given input feature. The classes would then look something like this:

class Detector(Model):
    @property
    @abstractmethod
    def all_features(self):
        """Returns container (List/Tuple) containing all supported features by the detector."""
    
    def __init__(self, used_features: List[str] | Tuple[str], transformations: List[FeatureStandardizer] | Tuple[FeatureStandardizer]):
        if not (len(used_features) == len(transformations)):
             raise ValueError("Length of used_features and transformations must be identical")
        for feature in used_features:
            if feature not in self.all_features:
                raise ValueError(f"{feature} not a recognized feature for this detector. Recognized features are {self.all_features}")
        self.used_features = used_features  # features used 
        self.transformations = transformations  # transformations used each index corresponds to the index in used 
        
        self.feature_map = {
            feature: transformation for feature, transformation in zip(used_features, transformations)
        }

    def forward(self, x):
         """Applies the correct transformation from feature map to each feature in x, possibly also removes redundant feature, if not already done."""
    ...

    
class FeatureStandardizer(Model):
    @abstractmethod
    def forward(self, x):
         """Applies the given standardization procedure.
             x: Contains only the correct feature. Applying the correct FeatureStandardizer to each feature should be taken care of in Detector"""

class LinearStandardizer(FeatureStandardizer):
    def __init__(self, offset, scale):
        self._offset = offset
        self._scale = scale

    def forward(self, x):
        return (x - self._offset) / self._scale

I'm not well versed enough in config files, to know exactly how those should be made, but they should contain information about which FeatureStandardizers is used for each feature, and the arguments passed to the constructor for the given FeatureStandardizer.

Describe alternatives you've considered
In the constructor for the detector, one could also pass the feature map directly. The transformations might not be needed to save internally in the Detector either, but I think keeping the used_features is beneficial.

Additional context
This feature request is inspired by comments from #558

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant