An optimizer which accumulates gradients across :math:`k` :meth:`minimize` executions, and apply them together in every :math:`k` th :meth:`minimize` execution. This is roughly the same as using a :math:`k` times larger batch size plus a :math:`k` times larger learning rate, but use
| 139 | |
| 140 | |
| 141 | class AccumGradOptimizer(ProxyOptimizer): |
| 142 | """ |
| 143 | An optimizer which accumulates gradients across :math:`k` :meth:`minimize` executions, |
| 144 | and apply them together in every :math:`k` th :meth:`minimize` execution. |
| 145 | This is roughly the same as using a :math:`k` times larger batch size plus a |
| 146 | :math:`k` times larger learning rate, but uses much less memory. |
| 147 | |
| 148 | This optimizer can be used in any TensorFlow code (with or without tensorpack). |
| 149 | |
| 150 | Example: |
| 151 | |
| 152 | .. code-block:: python |
| 153 | |
| 154 | from tensorpack.tfutils.optimizer import AccumGradOptimizer |
| 155 | myopt = tf.train.GradientDescentOptimizer(0.01) |
| 156 | myopt = AccumGradOptimizer(myopt, niter=5) |
| 157 | train_op = myopt.minimize(loss) |
| 158 | |
| 159 | """ |
| 160 | |
| 161 | def __init__(self, opt, niter): |
| 162 | """ |
| 163 | Args: |
| 164 | opt (tf.train.Optimizer): the underlying sub-optimizer. |
| 165 | niter (int): number of iterations to accumulate gradients. |
| 166 | """ |
| 167 | super(AccumGradOptimizer, self).__init__(opt, 'AccumGrad') |
| 168 | self._niter = int(niter) |
| 169 | |
| 170 | def _create_accum_slots(self, var_list): |
| 171 | slots = [] |
| 172 | for v in var_list: |
| 173 | # TODO an option to not colocate the accumulators with variables (to save more memory) |
| 174 | s = self._zeros_slot(v, "accum", self._name) |
| 175 | slots.append(s) |
| 176 | return slots |
| 177 | |
| 178 | @HIDE_DOC |
| 179 | def apply_gradients(self, grads_and_vars, global_step=None, name=None): |
| 180 | grads_and_vars = FilterNoneGrad().process(grads_and_vars) |
| 181 | vs = [] |
| 182 | for g, v in grads_and_vars: |
| 183 | assert isinstance(g, (tf.Tensor, tf.IndexedSlices)) and isinstance(v, tf.Variable), \ |
| 184 | "AccumGradOptimizer does not work for the gradient of {}! " \ |
| 185 | "Types of v and g are {} and {}".format(v.op.name, type(v), type(g)) |
| 186 | vs.append(v) |
| 187 | |
| 188 | with tf.control_dependencies(None): |
| 189 | slots = self._create_accum_slots(vs) |
| 190 | slots_and_vars = [(s, gv[1]) for s, gv in zip(slots, grads_and_vars)] |
| 191 | |
| 192 | with tfv1.variable_scope(self._name), tf.device('/cpu:0'): |
| 193 | counter = tf.Variable( |
| 194 | 0, name="counter", trainable=False, dtype=tf.int32) |
| 195 | |
| 196 | with tf.name_scope('AccumGradOptimizer'): |
| 197 | ops = [] |
| 198 | for s, gv in zip(slots, grads_and_vars): |
no outgoing calls
no test coverage detected