CutMix augmentation as described in: Sangdoo Yun, Dongyoon Han, Seong Joon Oh, Sanghyuk Chun, Junsuk Choe, Youngjoon Yoo. CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features, ICCV 2019 Class derived from :py:class:`monai.transforms.M
| 100 | |
| 101 | |
| 102 | class CutMix(Mixer): |
| 103 | """CutMix augmentation as described in: |
| 104 | Sangdoo Yun, Dongyoon Han, Seong Joon Oh, Sanghyuk Chun, Junsuk Choe, Youngjoon Yoo. |
| 105 | CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features, |
| 106 | ICCV 2019 |
| 107 | |
| 108 | Class derived from :py:class:`monai.transforms.Mixer`. See corresponding |
| 109 | documentation for details on the constructor parameters. Here, alpha not only determines |
| 110 | the mixing weight but also the size of the random rectangles used during for mixing. |
| 111 | Please refer to the paper for details. |
| 112 | |
| 113 | Please note that there is a change in behavior starting from version 1.4.0. In the previous |
| 114 | implementation, the transform would generate a different label each time it was called. |
| 115 | To ensure determinism, the new implementation will now generate the same label for |
| 116 | the same input image when using the same operation. |
| 117 | |
| 118 | The most common use case is something close to: |
| 119 | |
| 120 | .. code-block:: python |
| 121 | |
| 122 | cm = CutMix(batch_size=8, alpha=0.5) |
| 123 | for batch in loader: |
| 124 | images, labels = batch |
| 125 | augimg, auglabels = cm(images, labels) |
| 126 | output = model(augimg) |
| 127 | loss = loss_function(output, auglabels) |
| 128 | ... |
| 129 | |
| 130 | """ |
| 131 | |
| 132 | def apply(self, data: torch.Tensor): |
| 133 | weights, perm, coords = self._params |
| 134 | nsamples, _, *dims = data.shape |
| 135 | if len(weights) != nsamples: |
| 136 | raise ValueError(f"Expected batch of size: {len(weights)}, but got {nsamples}") |
| 137 | |
| 138 | mask = torch.ones_like(data) |
| 139 | for s, weight in enumerate(weights): |
| 140 | lengths = [d * sqrt(1 - weight) for d in dims] |
| 141 | idx = [slice(None)] + [slice(c, min(ceil(c + ln), d)) for c, ln, d in zip(coords, lengths, dims)] |
| 142 | mask[s][idx] = 0 |
| 143 | |
| 144 | return mask * data + (1 - mask) * data[perm, ...] |
| 145 | |
| 146 | def apply_on_labels(self, labels: torch.Tensor): |
| 147 | weights, perm, _ = self._params |
| 148 | nsamples, *dims = labels.shape |
| 149 | if len(weights) != nsamples: |
| 150 | raise ValueError(f"Expected batch of size: {len(weights)}, but got {nsamples}") |
| 151 | |
| 152 | mixweight = weights[(Ellipsis,) + (None,) * len(dims)] |
| 153 | return mixweight * labels + (1 - mixweight) * labels[perm, ...] |
| 154 | |
| 155 | def __call__(self, data: torch.Tensor, labels: torch.Tensor | None = None, randomize=True): |
| 156 | data_t = convert_to_tensor(data, track_meta=get_track_meta()) |
| 157 | augmented_label = None |
| 158 | if labels is not None: |
| 159 | labels_t = convert_to_tensor(labels, track_meta=get_track_meta()) |
no outgoing calls
searching dependent graphs…