CoolFace
Apppublic

declare-lab/tango2

sourceHugging Faceupdated 2y agoView on Hugging Face
92likes
optimization.py305 linesDownload Raw Back to diffusers
1# coding=utf-82# Copyright 2023 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 diffusion models."""16 17import math18from enum import Enum19from typing import Optional, Union20 21from torch.optim import Optimizer22from torch.optim.lr_scheduler import LambdaLR23 24from .utils import logging25 26 27logger = logging.get_logger(__name__)28 29 30class SchedulerType(Enum):31    LINEAR = "linear"32    COSINE = "cosine"33    COSINE_WITH_RESTARTS = "cosine_with_restarts"34    POLYNOMIAL = "polynomial"35    CONSTANT = "constant"36    CONSTANT_WITH_WARMUP = "constant_with_warmup"37 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    return LambdaLR(optimizer, lambda _: 1, last_epoch=last_epoch)53 54 55def get_constant_schedule_with_warmup(optimizer: Optimizer, num_warmup_steps: int, last_epoch: int = -1):56    """57    Create a schedule with a constant learning rate preceded by a warmup period during which the learning rate58    increases linearly between 0 and the initial lr set in the optimizer.59 60    Args:61        optimizer ([`~torch.optim.Optimizer`]):62            The optimizer for which to schedule the learning rate.63        num_warmup_steps (`int`):64            The number of steps for the warmup phase.65        last_epoch (`int`, *optional*, defaults to -1):66            The index of the last epoch when resuming training.67 68    Return:69        `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.70    """71 72    def lr_lambda(current_step: int):73        if current_step < num_warmup_steps:74            return float(current_step) / float(max(1.0, num_warmup_steps))75        return 1.076 77    return LambdaLR(optimizer, lr_lambda, last_epoch=last_epoch)78 79 80def get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, last_epoch=-1):81    """82    Create a schedule with a learning rate that decreases linearly from the initial lr set in the optimizer to 0, after83    a warmup period during which it increases linearly from 0 to the initial lr set in the optimizer.84 85    Args:86        optimizer ([`~torch.optim.Optimizer`]):87            The optimizer for which to schedule the learning rate.88        num_warmup_steps (`int`):89            The number of steps for the warmup phase.90        num_training_steps (`int`):91            The total number of training steps.92        last_epoch (`int`, *optional*, defaults to -1):93            The index of the last epoch when resuming training.94 95    Return:96        `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.97    """98 99    def lr_lambda(current_step: int):100        if current_step < num_warmup_steps:101            return float(current_step) / float(max(1, num_warmup_steps))102        return max(103            0.0, float(num_training_steps - current_step) / float(max(1, num_training_steps - num_warmup_steps))104        )105 106    return LambdaLR(optimizer, lr_lambda, last_epoch)107 108 109def get_cosine_schedule_with_warmup(110    optimizer: Optimizer, num_warmup_steps: int, num_training_steps: int, num_cycles: float = 0.5, last_epoch: int = -1111):112    """113    Create a schedule with a learning rate that decreases following the values of the cosine function between the114    initial lr set in the optimizer to 0, after a warmup period during which it increases linearly between 0 and the115    initial lr set in the optimizer.116 117    Args:118        optimizer ([`~torch.optim.Optimizer`]):119            The optimizer for which to schedule the learning rate.120        num_warmup_steps (`int`):121            The number of steps for the warmup phase.122        num_training_steps (`int`):123            The total number of training steps.124        num_periods (`float`, *optional*, defaults to 0.5):125            The number of periods of the cosine function in a schedule (the default is to just decrease from the max126            value to 0 following a half-cosine).127        last_epoch (`int`, *optional*, defaults to -1):128            The index of the last epoch when resuming training.129 130    Return:131        `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.132    """133 134    def lr_lambda(current_step):135        if current_step < num_warmup_steps:136            return float(current_step) / float(max(1, num_warmup_steps))137        progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))138        return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)))139 140    return LambdaLR(optimizer, lr_lambda, last_epoch)141 142 143def get_cosine_with_hard_restarts_schedule_with_warmup(144    optimizer: Optimizer, num_warmup_steps: int, num_training_steps: int, num_cycles: int = 1, last_epoch: int = -1145):146    """147    Create a schedule with a learning rate that decreases following the values of the cosine function between the148    initial lr set in the optimizer to 0, with several hard restarts, after a warmup period during which it increases149    linearly between 0 and the initial lr set in the optimizer.150 151    Args:152        optimizer ([`~torch.optim.Optimizer`]):153            The optimizer for which to schedule the learning rate.154        num_warmup_steps (`int`):155            The number of steps for the warmup phase.156        num_training_steps (`int`):157            The total number of training steps.158        num_cycles (`int`, *optional*, defaults to 1):159            The number of hard restarts to use.160        last_epoch (`int`, *optional*, defaults to -1):161            The index of the last epoch when resuming training.162 163    Return:164        `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.165    """166 167    def lr_lambda(current_step):168        if current_step < num_warmup_steps:169            return float(current_step) / float(max(1, num_warmup_steps))170        progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))171        if progress >= 1.0:172            return 0.0173        return max(0.0, 0.5 * (1.0 + math.cos(math.pi * ((float(num_cycles) * progress) % 1.0))))174 175    return LambdaLR(optimizer, lr_lambda, last_epoch)176 177 178def get_polynomial_decay_schedule_with_warmup(179    optimizer, num_warmup_steps, num_training_steps, lr_end=1e-7, power=1.0, last_epoch=-1180):181    """182    Create a schedule with a learning rate that decreases as a polynomial decay from the initial lr set in the183    optimizer to end lr defined by *lr_end*, after a warmup period during which it increases linearly from 0 to the184    initial lr set in the optimizer.185 186    Args:187        optimizer ([`~torch.optim.Optimizer`]):188            The optimizer for which to schedule the learning rate.189        num_warmup_steps (`int`):190            The number of steps for the warmup phase.191        num_training_steps (`int`):192            The total number of training steps.193        lr_end (`float`, *optional*, defaults to 1e-7):194            The end LR.195        power (`float`, *optional*, defaults to 1.0):196            Power factor.197        last_epoch (`int`, *optional*, defaults to -1):198            The index of the last epoch when resuming training.199 200    Note: *power* defaults to 1.0 as in the fairseq implementation, which in turn is based on the original BERT201    implementation at202    https://github.com/google-research/bert/blob/f39e881b169b9d53bea03d2d341b31707a6c052b/optimization.py#L37203 204    Return:205        `torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.206 207    """208 209    lr_init = optimizer.defaults["lr"]210    if not (lr_init > lr_end):211        raise ValueError(f"lr_end ({lr_end}) must be be smaller than initial lr ({lr_init})")212 213    def lr_lambda(current_step: int):214        if current_step < num_warmup_steps:215            return float(current_step) / float(max(1, num_warmup_steps))216        elif current_step > num_training_steps:217            return lr_end / lr_init  # as LambdaLR multiplies by lr_init218        else:219            lr_range = lr_init - lr_end220            decay_steps = num_training_steps - num_warmup_steps221            pct_remaining = 1 - (current_step - num_warmup_steps) / decay_steps222            decay = lr_range * pct_remaining**power + lr_end223            return decay / lr_init  # as LambdaLR multiplies by lr_init224 225    return LambdaLR(optimizer, lr_lambda, last_epoch)226 227 228TYPE_TO_SCHEDULER_FUNCTION = {229    SchedulerType.LINEAR: get_linear_schedule_with_warmup,230    SchedulerType.COSINE: get_cosine_schedule_with_warmup,231    SchedulerType.COSINE_WITH_RESTARTS: get_cosine_with_hard_restarts_schedule_with_warmup,232    SchedulerType.POLYNOMIAL: get_polynomial_decay_schedule_with_warmup,233    SchedulerType.CONSTANT: get_constant_schedule,234    SchedulerType.CONSTANT_WITH_WARMUP: get_constant_schedule_with_warmup,235}236 237 238def get_scheduler(239    name: Union[str, SchedulerType],240    optimizer: Optimizer,241    num_warmup_steps: Optional[int] = None,242    num_training_steps: Optional[int] = None,243    num_cycles: int = 1,244    power: float = 1.0,245    last_epoch: int = -1,246):247    """248    Unified API to get any scheduler from its name.249 250    Args:251        name (`str` or `SchedulerType`):252            The name of the scheduler to use.253        optimizer (`torch.optim.Optimizer`):254            The optimizer that will be used during training.255        num_warmup_steps (`int`, *optional*):256            The number of warmup steps to do. This is not required by all schedulers (hence the argument being257            optional), the function will raise an error if it's unset and the scheduler type requires it.258        num_training_steps (`int``, *optional*):259            The number of training steps to do. This is not required by all schedulers (hence the argument being260            optional), the function will raise an error if it's unset and the scheduler type requires it.261        num_cycles (`int`, *optional*):262            The number of hard restarts used in `COSINE_WITH_RESTARTS` scheduler.263        power (`float`, *optional*, defaults to 1.0):264            Power factor. See `POLYNOMIAL` scheduler265        last_epoch (`int`, *optional*, defaults to -1):266            The index of the last epoch when resuming training.267    """268    name = SchedulerType(name)269    schedule_func = TYPE_TO_SCHEDULER_FUNCTION[name]270    if name == SchedulerType.CONSTANT:271        return schedule_func(optimizer, last_epoch=last_epoch)272 273    # All other schedulers require `num_warmup_steps`274    if num_warmup_steps is None:275        raise ValueError(f"{name} requires `num_warmup_steps`, please provide that argument.")276 277    if name == SchedulerType.CONSTANT_WITH_WARMUP:278        return schedule_func(optimizer, num_warmup_steps=num_warmup_steps, last_epoch=last_epoch)279 280    # All other schedulers require `num_training_steps`281    if num_training_steps is None:282        raise ValueError(f"{name} requires `num_training_steps`, please provide that argument.")283 284    if name == SchedulerType.COSINE_WITH_RESTARTS:285        return schedule_func(286            optimizer,287            num_warmup_steps=num_warmup_steps,288            num_training_steps=num_training_steps,289            num_cycles=num_cycles,290            last_epoch=last_epoch,291        )292 293    if name == SchedulerType.POLYNOMIAL:294        return schedule_func(295            optimizer,296            num_warmup_steps=num_warmup_steps,297            num_training_steps=num_training_steps,298            power=power,299            last_epoch=last_epoch,300        )301 302    return schedule_func(303        optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=num_training_steps, last_epoch=last_epoch304    )305