Passed
Pull Request — master (#414)
by Osma
02:37
created

annif.backend.hyperopt   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 65
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 7
eloc 37
dl 0
loc 65
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A HyperparameterOptimizer.optimize() 0 14 1
A HyperparameterOptimizer._prepare() 0 3 1
A HyperparameterOptimizer._test() 0 4 1
A HyperparameterOptimizer.get_hp_space() 0 4 1
A AnnifHyperoptBackend.get_hp_optimizer() 0 6 1
A HyperparameterOptimizer.__init__() 0 4 1
A HyperparameterOptimizer._postprocess() 0 4 1
1
"""Hyperparameter optimization functionality for backends"""
2
3
import abc
4
import collections
5
import hyperopt
6
from .backend import AnnifBackend
7
8
9
HPRecommendation = collections.namedtuple('HPRecommendation', 'lines score')
10
11
12
class HyperparameterOptimizer:
13
    """Base class for hyperparameter optimizers"""
14
15
    def __init__(self, backend, corpus, metric):
16
        self._backend = backend
17
        self._corpus = corpus
18
        self._metric = metric
19
20
    @abc.abstractmethod
21
    def get_hp_space(self):
22
        """Get the hyperparameter space definition of this backend"""
23
        pass  # pragma: no cover
24
25
    def _prepare(self):
26
        """Prepare the optimizer for hyperparameter evaluation"""
27
        pass  # pragma: no cover
28
29
    @abc.abstractmethod
30
    def _test(self, hps):
31
        """Evaluate a set of hyperparameters"""
32
        pass  # pragma: no cover
33
34
    @abc.abstractmethod
35
    def _postprocess(self, best, trials):
36
        """Convert the trial results into hyperparameter recommendations"""
37
        pass  # pragma: no cover
38
39
    def optimize(self, n_trials):
40
        """Find the optimal hyperparameters by testing up to the given number
41
        of hyperparameter combinations"""
42
43
        self._prepare()
44
        space = self.get_hp_space()
45
        trials = hyperopt.Trials()
46
        best = hyperopt.fmin(
47
            fn=self._test,
48
            space=space,
49
            algo=hyperopt.tpe.suggest,
50
            max_evals=n_trials,
51
            trials=trials)
52
        return self._postprocess(best, trials)
53
54
55
class AnnifHyperoptBackend(AnnifBackend):
56
    """Base class for Annif backends that can perform hyperparameter
57
    optimization"""
58
59
    @abc.abstractmethod
60
    def get_hp_optimizer(self, corpus):
61
        """Get a HyperparameterOptimizer object that can look for
62
        optimal hyperparameter combinations for the given corpus"""
63
64
        pass  # pragma: no cover
65