DoruC/Grounded-Segment-Anything
0
1# coding=utf-82# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.15"""PyTorch optimization for BERT model."""16 17import math18import warnings19from functools import partial20from typing import Callable, Iterable, Optional, Tuple, Union21 22import torch23from torch import nn24from torch.optim import Optimizer25from torch.optim.lr_scheduler import LambdaLR, ReduceLROnPlateau26 27from .trainer_utils import SchedulerType28from .utils import logging29from .utils.versions import require_version30 31 32logger = logging.get_logger(__name__)33 34 35def _get_constant_lambda(_=None):36 return 137 38 39def get_constant_schedule(optimizer: Optimizer, last_epoch: int = -1):40 """41 Create a schedule with a constant learning rate, using the learning rate set in optimizer.42 43 Args:44 optimizer ([`~torch.optim.Optimizer`]):45 The optimizer for which to schedule the learning rate.46 last_epoch (`int`, *optional*, defaults to -1):47 The index of the last epoch when resuming training.48 49 Return:50 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.51 """52 53 return LambdaLR(optimizer, _get_constant_lambda, last_epoch=last_epoch)54 55 56def get_reduce_on_plateau_schedule(optimizer: Optimizer):57 """58 Create a schedule with a constant learning rate that decreases when a metric has stopped improving.59 60 Args:61 optimizer ([`~torch.optim.Optimizer`]):62 The optimizer for which to schedule the learning rate.63 64 Return:65 `torch.optim.lr_scheduler.ReduceLROnPlateau` with the appropriate schedule.66 """67 68 return ReduceLROnPlateau(optimizer)69 70 71def _get_constant_schedule_with_warmup_lr_lambda(current_step: int, *, num_warmup_steps: int):72 if current_step < num_warmup_steps:73 return float(current_step) / float(max(1.0, num_warmup_steps))74 return 1.075 76 77def get_constant_schedule_with_warmup(optimizer: Optimizer, num_warmup_steps: int, last_epoch: int = -1):78 """79 Create a schedule with a constant learning rate preceded by a warmup period during which the learning rate80 increases linearly between 0 and the initial lr set in the optimizer.81 82 Args:83 optimizer ([`~torch.optim.Optimizer`]):84 The optimizer for which to schedule the learning rate.85 num_warmup_steps (`int`):86 The number of steps for the warmup phase.87 last_epoch (`int`, *optional*, defaults to -1):88 The index of the last epoch when resuming training.89 90 Return:91 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.92 """93 94 lr_lambda = partial(_get_constant_schedule_with_warmup_lr_lambda, num_warmup_steps=num_warmup_steps)95 return LambdaLR(optimizer, lr_lambda, last_epoch=last_epoch)96 97 98def _get_linear_schedule_with_warmup_lr_lambda(current_step: int, *, num_warmup_steps: int, num_training_steps: int):99 if current_step < num_warmup_steps:100 return float(current_step) / float(max(1, num_warmup_steps))101 return max(0.0, float(num_training_steps - current_step) / float(max(1, num_training_steps - num_warmup_steps)))102 103 104def get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, last_epoch=-1):105 """106 Create a schedule with a learning rate that decreases linearly from the initial lr set in the optimizer to 0, after107 a warmup period during which it increases linearly from 0 to the initial lr set in the optimizer.108 109 Args:110 optimizer ([`~torch.optim.Optimizer`]):111 The optimizer for which to schedule the learning rate.112 num_warmup_steps (`int`):113 The number of steps for the warmup phase.114 num_training_steps (`int`):115 The total number of training steps.116 last_epoch (`int`, *optional*, defaults to -1):117 The index of the last epoch when resuming training.118 119 Return:120 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.121 """122 123 lr_lambda = partial(124 _get_linear_schedule_with_warmup_lr_lambda,125 num_warmup_steps=num_warmup_steps,126 num_training_steps=num_training_steps,127 )128 return LambdaLR(optimizer, lr_lambda, last_epoch)129 130 131def _get_cosine_schedule_with_warmup_lr_lambda(132 current_step: int, *, num_warmup_steps: int, num_training_steps: int, num_cycles: float133):134 if current_step < num_warmup_steps:135 return float(current_step) / float(max(1, num_warmup_steps))136 progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))137 return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)))138 139 140def get_cosine_schedule_with_warmup(141 optimizer: Optimizer, num_warmup_steps: int, num_training_steps: int, num_cycles: float = 0.5, last_epoch: int = -1142):143 """144 Create a schedule with a learning rate that decreases following the values of the cosine function between the145 initial lr set in the optimizer to 0, after a warmup period during which it increases linearly between 0 and the146 initial lr set in the optimizer.147 148 Args:149 optimizer ([`~torch.optim.Optimizer`]):150 The optimizer for which to schedule the learning rate.151 num_warmup_steps (`int`):152 The number of steps for the warmup phase.153 num_training_steps (`int`):154 The total number of training steps.155 num_cycles (`float`, *optional*, defaults to 0.5):156 The number of waves in the cosine schedule (the defaults is to just decrease from the max value to 0157 following a half-cosine).158 last_epoch (`int`, *optional*, defaults to -1):159 The index of the last epoch when resuming training.160 161 Return:162 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.163 """164 165 lr_lambda = partial(166 _get_cosine_schedule_with_warmup_lr_lambda,167 num_warmup_steps=num_warmup_steps,168 num_training_steps=num_training_steps,169 num_cycles=num_cycles,170 )171 return LambdaLR(optimizer, lr_lambda, last_epoch)172 173 174def _get_cosine_with_hard_restarts_schedule_with_warmup_lr_lambda(175 current_step: int, *, num_warmup_steps: int, num_training_steps: int, num_cycles: int176):177 if current_step < num_warmup_steps:178 return float(current_step) / float(max(1, num_warmup_steps))179 progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))180 if progress >= 1.0:181 return 0.0182 return max(0.0, 0.5 * (1.0 + math.cos(math.pi * ((float(num_cycles) * progress) % 1.0))))183 184 185def get_cosine_with_hard_restarts_schedule_with_warmup(186 optimizer: Optimizer, num_warmup_steps: int, num_training_steps: int, num_cycles: int = 1, last_epoch: int = -1187):188 """189 Create a schedule with a learning rate that decreases following the values of the cosine function between the190 initial lr set in the optimizer to 0, with several hard restarts, after a warmup period during which it increases191 linearly between 0 and the initial lr set in the optimizer.192 193 Args:194 optimizer ([`~torch.optim.Optimizer`]):195 The optimizer for which to schedule the learning rate.196 num_warmup_steps (`int`):197 The number of steps for the warmup phase.198 num_training_steps (`int`):199 The total number of training steps.200 num_cycles (`int`, *optional*, defaults to 1):201 The number of hard restarts to use.202 last_epoch (`int`, *optional*, defaults to -1):203 The index of the last epoch when resuming training.204 205 Return:206 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.207 """208 209 lr_lambda = partial(210 _get_cosine_with_hard_restarts_schedule_with_warmup_lr_lambda,211 num_warmup_steps=num_warmup_steps,212 num_training_steps=num_training_steps,213 num_cycles=num_cycles,214 )215 return LambdaLR(optimizer, lr_lambda, last_epoch)216 217 218def _get_polynomial_decay_schedule_with_warmup_lr_lambda(219 current_step: int,220 *,221 num_warmup_steps: int,222 num_training_steps: int,223 lr_end: float,224 power: float,225 lr_init: int,226):227 if current_step < num_warmup_steps:228 return float(current_step) / float(max(1, num_warmup_steps))229 elif current_step > num_training_steps:230 return lr_end / lr_init # as LambdaLR multiplies by lr_init231 else:232 lr_range = lr_init - lr_end233 decay_steps = num_training_steps - num_warmup_steps234 pct_remaining = 1 - (current_step - num_warmup_steps) / decay_steps235 decay = lr_range * pct_remaining**power + lr_end236 return decay / lr_init # as LambdaLR multiplies by lr_init237 238 239def get_polynomial_decay_schedule_with_warmup(240 optimizer, num_warmup_steps, num_training_steps, lr_end=1e-7, power=1.0, last_epoch=-1241):242 """243 Create a schedule with a learning rate that decreases as a polynomial decay from the initial lr set in the244 optimizer to end lr defined by *lr_end*, after a warmup period during which it increases linearly from 0 to the245 initial lr set in the optimizer.246 247 Args:248 optimizer ([`~torch.optim.Optimizer`]):249 The optimizer for which to schedule the learning rate.250 num_warmup_steps (`int`):251 The number of steps for the warmup phase.252 num_training_steps (`int`):253 The total number of training steps.254 lr_end (`float`, *optional*, defaults to 1e-7):255 The end LR.256 power (`float`, *optional*, defaults to 1.0):257 Power factor.258 last_epoch (`int`, *optional*, defaults to -1):259 The index of the last epoch when resuming training.260 261 Note: *power* defaults to 1.0 as in the fairseq implementation, which in turn is based on the original BERT262 implementation at263 https://github.com/google-research/bert/blob/f39e881b169b9d53bea03d2d341b31707a6c052b/optimization.py#L37264 265 Return:266 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.267 268 """269 270 lr_init = optimizer.defaults["lr"]271 if not (lr_init > lr_end):272 raise ValueError(f"lr_end ({lr_end}) must be be smaller than initial lr ({lr_init})")273 274 lr_lambda = partial(275 _get_polynomial_decay_schedule_with_warmup_lr_lambda,276 num_warmup_steps=num_warmup_steps,277 num_training_steps=num_training_steps,278 lr_end=lr_end,279 power=power,280 lr_init=lr_init,281 )282 return LambdaLR(optimizer, lr_lambda, last_epoch)283 284 285def _get_inverse_sqrt_schedule_lr_lambda(current_step: int, *, num_warmup_steps: int, timescale: int = None):286 if current_step < num_warmup_steps:287 return float(current_step) / float(max(1, num_warmup_steps))288 shift = timescale - num_warmup_steps289 decay = 1.0 / math.sqrt((current_step + shift) / timescale)290 return decay291 292 293def get_inverse_sqrt_schedule(294 optimizer: Optimizer, num_warmup_steps: int, timescale: int = None, last_epoch: int = -1295):296 """297 Create a schedule with an inverse square-root learning rate, from the initial lr set in the optimizer, after a298 warmup period which increases lr linearly from 0 to the initial lr set in the optimizer.299 300 Args:301 optimizer ([`~torch.optim.Optimizer`]):302 The optimizer for which to schedule the learning rate.303 num_warmup_steps (`int`):304 The number of steps for the warmup phase.305 timescale (`int`, *optional*, defaults to `num_warmup_steps`):306 Time scale.307 last_epoch (`int`, *optional*, defaults to -1):308 The index of the last epoch when resuming training.309 310 Return:311 `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.312 """313 # Note: this implementation is adapted from314 # https://github.com/google-research/big_vision/blob/f071ce68852d56099437004fd70057597a95f6ef/big_vision/utils.py#L930315 316 if timescale is None:317 timescale = num_warmup_steps318 319 lr_lambda = partial(_get_inverse_sqrt_schedule_lr_lambda, num_warmup_steps=num_warmup_steps, timescale=timescale)320 return LambdaLR(optimizer, lr_lambda, last_epoch=last_epoch)321 322 323TYPE_TO_SCHEDULER_FUNCTION = {324 SchedulerType.LINEAR: get_linear_schedule_with_warmup,325 SchedulerType.COSINE: get_cosine_schedule_with_warmup,326 SchedulerType.COSINE_WITH_RESTARTS: get_cosine_with_hard_restarts_schedule_with_warmup,327 SchedulerType.POLYNOMIAL: get_polynomial_decay_schedule_with_warmup,328 SchedulerType.CONSTANT: get_constant_schedule,329 SchedulerType.CONSTANT_WITH_WARMUP: get_constant_schedule_with_warmup,330 SchedulerType.INVERSE_SQRT: get_inverse_sqrt_schedule,331 SchedulerType.REDUCE_ON_PLATEAU: get_reduce_on_plateau_schedule,332}333 334 335def get_scheduler(336 name: Union[str, SchedulerType],337 optimizer: Optimizer,338 num_warmup_steps: Optional[int] = None,339 num_training_steps: Optional[int] = None,340):341 """342 Unified API to get any scheduler from its name.343 344 Args:345 name (`str` or `SchedulerType`):346 The name of the scheduler to use.347 optimizer (`torch.optim.Optimizer`):348 The optimizer that will be used during training.349 num_warmup_steps (`int`, *optional*):350 The number of warmup steps to do. This is not required by all schedulers (hence the argument being351 optional), the function will raise an error if it's unset and the scheduler type requires it.352 num_training_steps (`int``, *optional*):353 The number of training steps to do. This is not required by all schedulers (hence the argument being354 optional), the function will raise an error if it's unset and the scheduler type requires it.355 """356 name = SchedulerType(name)357 schedule_func = TYPE_TO_SCHEDULER_FUNCTION[name]358 if name == SchedulerType.CONSTANT or name == SchedulerType.REDUCE_ON_PLATEAU:359 return schedule_func(optimizer)360 361 # All other schedulers require `num_warmup_steps`362 if num_warmup_steps is None:363 raise ValueError(f"{name} requires `num_warmup_steps`, please provide that argument.")364 365 if name == SchedulerType.CONSTANT_WITH_WARMUP:366 return schedule_func(optimizer, num_warmup_steps=num_warmup_steps)367 368 if name == SchedulerType.INVERSE_SQRT:369 return schedule_func(optimizer, num_warmup_steps=num_warmup_steps)370 371 # All other schedulers require `num_training_steps`372 if num_training_steps is None:373 raise ValueError(f"{name} requires `num_training_steps`, please provide that argument.")374 375 return schedule_func(optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=num_training_steps)376 377 378class AdamW(Optimizer):379 """380 Implements Adam algorithm with weight decay fix as introduced in [Decoupled Weight Decay381 Regularization](https://arxiv.org/abs/1711.05101).382 383 Parameters:384 params (`Iterable[nn.parameter.Parameter]`):385 Iterable of parameters to optimize or dictionaries defining parameter groups.386 lr (`float`, *optional*, defaults to 0.001):387 The learning rate to use.388 betas (`Tuple[float,float]`, *optional*, defaults to `(0.9, 0.999)`):389 Adam's betas parameters (b1, b2).390 eps (`float`, *optional*, defaults to 1e-06):391 Adam's epsilon for numerical stability.392 weight_decay (`float`, *optional*, defaults to 0.0):393 Decoupled weight decay to apply.394 correct_bias (`bool`, *optional*, defaults to `True`):395 Whether or not to correct bias in Adam (for instance, in Bert TF repository they use `False`).396 no_deprecation_warning (`bool`, *optional*, defaults to `False`):397 A flag used to disable the deprecation warning (set to `True` to disable the warning).398 """399 400 def __init__(401 self,402 params: Iterable[nn.parameter.Parameter],403 lr: float = 1e-3,404 betas: Tuple[float, float] = (0.9, 0.999),405 eps: float = 1e-6,406 weight_decay: float = 0.0,407 correct_bias: bool = True,408 no_deprecation_warning: bool = False,409 ):410 if not no_deprecation_warning:411 warnings.warn(412 "This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch"413 " implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this"414 " warning",415 FutureWarning,416 )417 require_version("torch>=1.5.0") # add_ with alpha418 if lr < 0.0:419 raise ValueError(f"Invalid learning rate: {lr} - should be >= 0.0")420 if not 0.0 <= betas[0] < 1.0:421 raise ValueError(f"Invalid beta parameter: {betas[0]} - should be in [0.0, 1.0)")422 if not 0.0 <= betas[1] < 1.0:423 raise ValueError(f"Invalid beta parameter: {betas[1]} - should be in [0.0, 1.0)")424 if not 0.0 <= eps:425 raise ValueError(f"Invalid epsilon value: {eps} - should be >= 0.0")426 defaults = {"lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay, "correct_bias": correct_bias}427 super().__init__(params, defaults)428 429 @torch.no_grad()430 def step(self, closure: Callable = None):431 """432 Performs a single optimization step.433 434 Arguments:435 closure (`Callable`, *optional*): A closure that reevaluates the model and returns the loss.436 """437 loss = None438 if closure is not None:439 loss = closure()440 441 for group in self.param_groups:442 for p in group["params"]:443 if p.grad is None:444 continue445 grad = p.grad446 if grad.is_sparse:447 raise RuntimeError("Adam does not support sparse gradients, please consider SparseAdam instead")448 449 state = self.state[p]450 451 # State initialization452 if len(state) == 0:453 state["step"] = 0454 # Exponential moving average of gradient values455 state["exp_avg"] = torch.zeros_like(p)456 # Exponential moving average of squared gradient values457 state["exp_avg_sq"] = torch.zeros_like(p)458 459 exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"]460 beta1, beta2 = group["betas"]461 462 state["step"] += 1463 464 # Decay the first and second moment running average coefficient465 # In-place operations to update the averages at the same time466 exp_avg.mul_(beta1).add_(grad, alpha=(1.0 - beta1))467 exp_avg_sq.mul_(beta2).addcmul_(grad, grad, value=1.0 - beta2)468 denom = exp_avg_sq.sqrt().add_(group["eps"])469 470 step_size = group["lr"]471 if group["correct_bias"]: # No bias correction for Bert472 bias_correction1 = 1.0 - beta1 ** state["step"]473 bias_correction2 = 1.0 - beta2 ** state["step"]474 step_size = step_size * math.sqrt(bias_correction2) / bias_correction1475 476 p.addcdiv_(exp_avg, denom, value=-step_size)477 478 # Just adding the square of the weights to the loss function is *not*479 # the correct way of using L2 regularization/weight decay with Adam,480 # since that will interact with the m and v parameters in strange ways.481 #482 # Instead we want to decay the weights in a manner that doesn't interact483 # with the m/v parameters. This is equivalent to adding the square484 # of the weights to the loss with plain (non-momentum) SGD.485 # Add weight decay at the end (fixed version)486 if group["weight_decay"] > 0.0:487 p.add_(p, alpha=(-group["lr"] * group["weight_decay"]))488 489 return loss490 491 492class Adafactor(Optimizer):493 """494 AdaFactor pytorch implementation can be used as a drop in replacement for Adam original fairseq code:495 https://github.com/pytorch/fairseq/blob/master/fairseq/optim/adafactor.py496 497 Paper: *Adafactor: Adaptive Learning Rates with Sublinear Memory Cost* https://arxiv.org/abs/1804.04235 Note that498 this optimizer internally adjusts the learning rate depending on the `scale_parameter`, `relative_step` and499 `warmup_init` options. To use a manual (external) learning rate schedule you should set `scale_parameter=False` and500 `relative_step=False`.501 502 Arguments:503 params (`Iterable[nn.parameter.Parameter]`):504 Iterable of parameters to optimize or dictionaries defining parameter groups.505 lr (`float`, *optional*):506 The external learning rate.507 eps (`Tuple[float, float]`, *optional*, defaults to `(1e-30, 0.001)`):508 Regularization constants for square gradient and parameter scale respectively509 clip_threshold (`float`, *optional*, defaults to 1.0):510 Threshold of root mean square of final gradient update511 decay_rate (`float`, *optional*, defaults to -0.8):512 Coefficient used to compute running averages of square513 beta1 (`float`, *optional*):514 Coefficient used for computing running averages of gradient515 weight_decay (`float`, *optional*, defaults to 0.0):516 Weight decay (L2 penalty)517 scale_parameter (`bool`, *optional*, defaults to `True`):518 If True, learning rate is scaled by root mean square519 relative_step (`bool`, *optional*, defaults to `True`):520 If True, time-dependent learning rate is computed instead of external learning rate521 warmup_init (`bool`, *optional*, defaults to `False`):522 Time-dependent learning rate computation depends on whether warm-up initialization is being used523 524 This implementation handles low-precision (FP16, bfloat) values, but we have not thoroughly tested.525 526 Recommended T5 finetuning settings (https://discuss.huggingface.co/t/t5-finetuning-tips/684/3):527 528 - Training without LR warmup or clip_threshold is not recommended.529 530 - use scheduled LR warm-up to fixed LR531 - use clip_threshold=1.0 (https://arxiv.org/abs/1804.04235)532 - Disable relative updates533 - Use scale_parameter=False534 - Additional optimizer operations like gradient clipping should not be used alongside Adafactor535 536 Example:537 538 ```python539 Adafactor(model.parameters(), scale_parameter=False, relative_step=False, warmup_init=False, lr=1e-3)540 ```541 542 Others reported the following combination to work well:543 544 ```python545 Adafactor(model.parameters(), scale_parameter=True, relative_step=True, warmup_init=True, lr=None)546 ```547 548 When using `lr=None` with [`Trainer`] you will most likely need to use [`~optimization.AdafactorSchedule`]549 scheduler as following:550 551 ```python552 from transformers.optimization import Adafactor, AdafactorSchedule553 554 optimizer = Adafactor(model.parameters(), scale_parameter=True, relative_step=True, warmup_init=True, lr=None)555 lr_scheduler = AdafactorSchedule(optimizer)556 trainer = Trainer(..., optimizers=(optimizer, lr_scheduler))557 ```558 559 Usage:560 561 ```python562 # replace AdamW with Adafactor563 optimizer = Adafactor(564 model.parameters(),565 lr=1e-3,566 eps=(1e-30, 1e-3),567 clip_threshold=1.0,568 decay_rate=-0.8,569 beta1=None,570 weight_decay=0.0,571 relative_step=False,572 scale_parameter=False,573 warmup_init=False,574 )575 ```"""576 577 def __init__(578 self,579 params,580 lr=None,581 eps=(1e-30, 1e-3),582 clip_threshold=1.0,583 decay_rate=-0.8,584 beta1=None,585 weight_decay=0.0,586 scale_parameter=True,587 relative_step=True,588 warmup_init=False,589 ):590 require_version("torch>=1.5.0") # add_ with alpha591 if lr is not None and relative_step:592 raise ValueError("Cannot combine manual `lr` and `relative_step=True` options")593 if warmup_init and not relative_step:594 raise ValueError("`warmup_init=True` requires `relative_step=True`")595 596 defaults = {597 "lr": lr,598 "eps": eps,599 "clip_threshold": clip_threshold,600 "decay_rate": decay_rate,601 "beta1": beta1,602 "weight_decay": weight_decay,603 "scale_parameter": scale_parameter,604 "relative_step": relative_step,605 "warmup_init": warmup_init,606 }607 super().__init__(params, defaults)608 609 @staticmethod610 def _get_lr(param_group, param_state):611 rel_step_sz = param_group["lr"]612 if param_group["relative_step"]:613 min_step = 1e-6 * param_state["step"] if param_group["warmup_init"] else 1e-2614 rel_step_sz = min(min_step, 1.0 / math.sqrt(param_state["step"]))615 param_scale = 1.0616 if param_group["scale_parameter"]:617 param_scale = max(param_group["eps"][1], param_state["RMS"])618 return param_scale * rel_step_sz619 620 @staticmethod621 def _get_options(param_group, param_shape):622 factored = len(param_shape) >= 2623 use_first_moment = param_group["beta1"] is not None624 return factored, use_first_moment625 626 @staticmethod627 def _rms(tensor):628 return tensor.norm(2) / (tensor.numel() ** 0.5)629 630 @staticmethod631 def _approx_sq_grad(exp_avg_sq_row, exp_avg_sq_col):632 # copy from fairseq's adafactor implementation:633 # https://github.com/huggingface/transformers/blob/8395f14de6068012787d83989c3627c3df6a252b/src/transformers/optimization.py#L505634 r_factor = (exp_avg_sq_row / exp_avg_sq_row.mean(dim=-1, keepdim=True)).rsqrt_().unsqueeze(-1)635 c_factor = exp_avg_sq_col.unsqueeze(-2).rsqrt()636 return torch.mul(r_factor, c_factor)637 638 @torch.no_grad()639 def step(self, closure=None):640 """641 Performs a single optimization step642 643 Arguments:644 closure (callable, optional): A closure that reevaluates the model645 and returns the loss.646 """647 loss = None648 if closure is not None:649 loss = closure()650 651 for group in self.param_groups:652 for p in group["params"]:653 if p.grad is None:654 continue655 grad = p.grad656 if grad.dtype in {torch.float16, torch.bfloat16}:657 grad = grad.float()658 if grad.is_sparse:659 raise RuntimeError("Adafactor does not support sparse gradients.")660 661 state = self.state[p]662 grad_shape = grad.shape663 664 factored, use_first_moment = self._get_options(group, grad_shape)665 # State Initialization666 if len(state) == 0:667 state["step"] = 0668 669 if use_first_moment:670 # Exponential moving average of gradient values671 state["exp_avg"] = torch.zeros_like(grad)672 if factored:673 state["exp_avg_sq_row"] = torch.zeros(grad_shape[:-1]).to(grad)674 state["exp_avg_sq_col"] = torch.zeros(grad_shape[:-2] + grad_shape[-1:]).to(grad)675 else:676 state["exp_avg_sq"] = torch.zeros_like(grad)677 678 state["RMS"] = 0679 else:680 if use_first_moment:681 state["exp_avg"] = state["exp_avg"].to(grad)682 if factored:683 state["exp_avg_sq_row"] = state["exp_avg_sq_row"].to(grad)684 state["exp_avg_sq_col"] = state["exp_avg_sq_col"].to(grad)685 else:686 state["exp_avg_sq"] = state["exp_avg_sq"].to(grad)687 688 p_data_fp32 = p689 if p.dtype in {torch.float16, torch.bfloat16}:690 p_data_fp32 = p_data_fp32.float()691 692 state["step"] += 1693 state["RMS"] = self._rms(p_data_fp32)694 lr = self._get_lr(group, state)695 696 beta2t = 1.0 - math.pow(state["step"], group["decay_rate"])697 update = (grad**2) + group["eps"][0]698 if factored:699 exp_avg_sq_row = state["exp_avg_sq_row"]700 exp_avg_sq_col = state["exp_avg_sq_col"]701 702 exp_avg_sq_row.mul_(beta2t).add_(update.mean(dim=-1), alpha=(1.0 - beta2t))703 exp_avg_sq_col.mul_(beta2t).add_(update.mean(dim=-2), alpha=(1.0 - beta2t))704 705 # Approximation of exponential moving average of square of gradient706 update = self._approx_sq_grad(exp_avg_sq_row, exp_avg_sq_col)707 update.mul_(grad)708 else:709 exp_avg_sq = state["exp_avg_sq"]710 711 exp_avg_sq.mul_(beta2t).add_(update, alpha=(1.0 - beta2t))712 update = exp_avg_sq.rsqrt().mul_(grad)713 714 update.div_((self._rms(update) / group["clip_threshold"]).clamp_(min=1.0))715 update.mul_(lr)716 717 if use_first_moment:718 exp_avg = state["exp_avg"]719 exp_avg.mul_(group["beta1"]).add_(update, alpha=(1 - group["beta1"]))720 update = exp_avg721 722 if group["weight_decay"] != 0:723 p_data_fp32.add_(p_data_fp32, alpha=(-group["weight_decay"] * lr))724 725 p_data_fp32.add_(-update)726 727 if p.dtype in {torch.float16, torch.bfloat16}:728 p.copy_(p_data_fp32)729 730 return loss731 732 733class AdafactorSchedule(LambdaLR):734 """735 Since [`~optimization.Adafactor`] performs its own scheduling, if the training loop relies on a scheduler (e.g.,736 for logging), this class creates a proxy object that retrieves the current lr values from the optimizer.737 738 It returns `initial_lr` during startup and the actual `lr` during stepping.739 """740 741 def __init__(self, optimizer, initial_lr=0.0):742 def lr_lambda(_):743 return initial_lr744 745 for group in optimizer.param_groups:746 group["initial_lr"] = initial_lr747 super().__init__(optimizer, lr_lambda)748 for group in optimizer.param_groups:749 del group["initial_lr"]750 751 def get_lr(self):752 opt = self.optimizer753 lrs = [754 opt._get_lr(group, opt.state[group["params"][0]])755 for group in opt.param_groups756 if group["params"][0].grad is not None757 ]758 if len(lrs) == 0:759 lrs = self.base_lrs # if called before stepping760 return lrs761 762 763def get_adafactor_schedule(optimizer, initial_lr=0.0):764 """765 Get a proxy schedule for [`~optimization.Adafactor`]766 767 Args:768 optimizer ([`~torch.optim.Optimizer`]):769 The optimizer for which to schedule the learning rate.770 initial_lr (`float`, *optional*, defaults to 0.0):771 Initial lr772 773 Return:774 [`~optimization.Adafactor`] proxy schedule object.775 776 777 """778 return AdafactorSchedule(optimizer, initial_lr)779 