Completed
Push — master ( eef17b...3c911b )
by Raphael
01:37
created

deepy/trainers/annealers.py (1 issue)

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
import numpy as np
5
6
from controllers import TrainingController
7
from deepy.utils import FLOATX, shared_scalar
8
9
import logging as loggers
10
logging = loggers.getLogger(__name__)
11
12
class LearningRateAnnealer(TrainingController):
13
    """
14
    Learning rate annealer.
15
    """
16
17
    def __init__(self, trainer, patience=3, anneal_times=4):
18
        """
19
        :type trainer: deepy.trainers.base.NeuralTrainer
20
        """
21
        super(LearningRateAnnealer, self).__init__(trainer)
22
        self._iter = -1
23
        self._annealed_iter = -1
24
        self._patience = patience
25
        self._anneal_times = anneal_times
26
        self._annealed_times = 0
27
        self._learning_rate = self._trainer.config.learning_rate
28
        if type(self._learning_rate) == float:
29
            raise Exception("use shared_scalar to wrap the value in the config.")
30
31
    def invoke(self):
32
        """
33
        Run it, return whether to end training.
34
        """
35
        self._iter += 1
36 View Code Duplication
        if self._iter - max(self._trainer.best_iter, self._annealed_iter) >= self._patience:
37
            if self._annealed_times >= self._anneal_times:
38
                logging.info("ending")
39
                return True
40
            else:
41
                self._trainer.set_params(*self._trainer.best_params)
42
                self._learning_rate.set_value(self._learning_rate.get_value() * 0.5)
43
                self._annealed_times += 1
44
                self._annealed_iter = self._iter
45
                logging.info("annealed learning rate to %f" % self._learning_rate.get_value())
46
        return False
47
48
    @staticmethod
49
    def learning_rate(value=0.01):
50
        """
51
        Wrap learning rate.
52
        """
53
        return shared_scalar(value, name="learning_rate")
54
55
56
class ScheduledLearningRateAnnealer(TrainingController):
57
    """
58
    Anneal learning rate according to pre-scripted schedule.
59
    """
60
61
    def __init__(self, trainer, start_halving_at=5, end_at=10, halving_interval=1, rollback=False):
62
        super(ScheduledLearningRateAnnealer, self).__init__(trainer)
63
        logging.info("iteration to start halving learning rate: %d" % start_halving_at)
64
        self.iter_start_halving = start_halving_at
65
        self.end_at = end_at
66
        self._learning_rate = self._trainer.config.learning_rate
67
        self._iter = 0
68
        self._halving_interval = halving_interval
69
        self._rollback = rollback
70
        self._last_halving_iter = 0
71
72
    def invoke(self):
73
        self._iter += 1
74 View Code Duplication
        if self._iter >= self.iter_start_halving and self._iter > self._last_halving_iter + self._halving_interval:
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
75
            if self._rollback:
76
                self._trainer.set_params(*self._trainer.best_params)
77
            self._learning_rate.set_value(self._learning_rate.get_value() * 0.5)
78
            logging.info("halving learning rate to %f" % self._learning_rate.get_value())
79
            self._trainer.network.train_logger.record("set learning rate to %f" % self._learning_rate.get_value())
80
            self._last_halving_iter = self._iter
81
        if self._iter >= self.end_at:
82
            logging.info("ending")
83
            return True
84
        return False
85
86
87
class ExponentialLearningRateAnnealer(TrainingController):
88
    """
89
    Exponentially decay learning rate after each update.
90
    """
91
92
    def __init__(self, trainer, decay_factor=1.000004, min_lr=.000001, debug=False):
93
        super(ExponentialLearningRateAnnealer, self).__init__(trainer)
94
        logging.info("exponentially decay learning rate with decay factor = %f" % decay_factor)
95
        self.decay_factor = np.array(decay_factor, dtype=FLOATX)
96
        self.min_lr = np.array(min_lr, dtype=FLOATX)
97
        self.debug = debug
98
        self._learning_rate = self._trainer.config.learning_rate
99
        if type(self._learning_rate) == float:
100
            raise Exception("use shared_scalar to wrap the value in the config.")
101
        self._trainer.network.training_callbacks.append(self.update_callback)
102
103
    def update_callback(self):
104
        if self._learning_rate.get_value() > self.min_lr:
105
            self._learning_rate.set_value(self._learning_rate.get_value() / self.decay_factor)
106
107
    def invoke(self):
108
        if self.debug:
109
            logging.info("learning rate: %.8f" % self._learning_rate.get_value())
110
        return False
111
112
class SimpleScheduler(TrainingController):
113
114
    """
115
    Simple scheduler with maximum patience.
116
    """
117
118
    def __init__(self, trainer, patience=10):
119
        """
120
        :type trainer: deepy.trainers.base.NeuralTrainer
121
        """
122
        super(SimpleScheduler, self).__init__(trainer)
123
        self._iter = 0
124
        self._patience = patience
125
126
    def invoke(self):
127
        """
128
        Run it, return whether to end training.
129
        """
130
        self._iter += 1
131
        logging.info("{} epochs left to run".format(self._patience - self._iter))
132
        if self._iter >= self._patience:
133
            return True
134
        else:
135
            return False