ExponentialLearningRateAnnealer.invoke()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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