# Implementation modified from torchvision: # https://github.com/pytorch/vision/blob/main/torchvision/ops/stochastic_depth.py # # License: # BSD 3-Clause License # # Copyright (c) Soumith Chintala 2016, # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import torch import torch.fx from torch import nn, Tensor def stochastic_depth( input: Tensor, p: float, mode: str, training: bool = True ) -> Tensor: """ Implements the Stochastic Depth from `"Deep Networks with Stochastic Depth" `_ used for randomly dropping residual branches of residual architectures. Args: input (Tensor[N, ...]): The input tensor or arbitrary dimensions with the first one being its batch i.e. a batch with ``N`` rows. p (float): probability of the input to be zeroed. mode (str): ``"batch"`` or ``"row"``. ``"batch"`` randomly zeroes the entire input, ``"row"`` zeroes randomly selected rows from the batch. training: apply stochastic depth if is ``True``. Default: ``True`` Returns: Tensor[N, ...]: The randomly zeroed tensor. """ if p < 0.0 or p > 1.0: raise ValueError(f"drop probability has to be between 0 and 1, but got {p}") if mode not in ["batch", "row"]: raise ValueError(f"mode has to be either 'batch' or 'row', but got {mode}") if not training or p == 0.0: return input survival_rate = 1.0 - p if mode == "row": size = [input.shape[0]] + [1] * (input.ndim - 1) else: size = [1] * input.ndim noise = torch.empty(size, dtype=input.dtype, device=input.device) noise = noise.bernoulli_(survival_rate) if survival_rate > 0.0: noise.div_(survival_rate) return input * noise torch.fx.wrap("stochastic_depth") class StochasticDepth(nn.Module): """ See :func:`stochastic_depth`. """ def __init__(self, p: float, mode: str) -> None: super().__init__() self.p = p self.mode = mode def forward(self, input: Tensor) -> Tensor: return stochastic_depth(input, self.p, self.mode, self.training) def __repr__(self) -> str: s = f"{self.__class__.__name__}(p={self.p}, mode={self.mode})" return s