Nested dropout layer proposed by Rippel et al. [2014]. Compared to typical dropout, which independently masks variables, the nested dropout masks i+1 to the end, if i is chosen. Ref: https://arxiv.org/abs/1402.0915
| 8 | |
| 9 | |
| 10 | class NestedDropout(torch.nn.Module): |
| 11 | """ |
| 12 | Nested dropout layer proposed by Rippel et al. [2014]. |
| 13 | |
| 14 | Compared to typical dropout, which independently masks variables, |
| 15 | the nested dropout masks i+1 to the end, if i is chosen. |
| 16 | |
| 17 | Ref: https://arxiv.org/abs/1402.0915 |
| 18 | """ |
| 19 | |
| 20 | def __init__(self, probs: T.Sequence[float]): |
| 21 | """ |
| 22 | Construct nested dropout layer, which drops the last dimension. |
| 23 | Note that it creates a mask of shape (B, C), so if the input x |
| 24 | has a dimension larger than 2, the first dimensions will share the |
| 25 | same mask, and different instances in the batch uses different masks. |
| 26 | |
| 27 | Args: |
| 28 | probs: |
| 29 | the probablity of the index to be chosen. If None, uniform probability. |
| 30 | |
| 31 | Input: |
| 32 | x: (*, B, C) |
| 33 | |
| 34 | Output: |
| 35 | y: (*, B, C) |
| 36 | """ |
| 37 | super().__init__() |
| 38 | self.probs = probs |
| 39 | self.rng = np.random.default_rng() |
| 40 | |
| 41 | def forward(self, x: torch.Tensor) -> torch.Tensor: |
| 42 | r""" |
| 43 | Args: |
| 44 | x: |
| 45 | `(*, B, C)` |
| 46 | |
| 47 | Returns: |
| 48 | y: |
| 49 | `(*, B, C)` |
| 50 | """ |
| 51 | if not self.training: |
| 52 | return x # no masking during inference |
| 53 | |
| 54 | ori_x_shape = x.shape |
| 55 | if len(x.shape) < 2: |
| 56 | x = x.unsqueeze(0) # (1, C) |
| 57 | batch_size = x.size(-2) |
| 58 | dim = x.size(-1) |
| 59 | x = x.reshape(-1, batch_size, dim) |
| 60 | |
| 61 | # create mask |
| 62 | chosen_idxs = self.rng.choice( |
| 63 | np.arange(dim), |
| 64 | size=[batch_size], |
| 65 | replace=True, |
| 66 | p=self.probs, |
| 67 | ) # (batch,) int |
nothing calls this directly
no outgoing calls
no test coverage detected