(ctx, grad_outputs)
| 52 | |
| 53 | @staticmethod |
| 54 | def backward(ctx, grad_outputs): |
| 55 | inputs, targets = ctx.saved_tensors |
| 56 | grad_inputs = None |
| 57 | if ctx.needs_input_grad[0]: |
| 58 | grad_inputs = grad_outputs.mm(ctx.features) |
| 59 | |
| 60 | batch_centers = collections.defaultdict(list) |
| 61 | for instance_feature, index in zip(inputs, targets.tolist()): |
| 62 | batch_centers[index].append(instance_feature) |
| 63 | |
| 64 | for index, features in batch_centers.items(): |
| 65 | distances = [] |
| 66 | for feature in features: |
| 67 | distance = feature.unsqueeze(0).mm(ctx.features[index].unsqueeze(0).t())[0][0] |
| 68 | distances.append(distance.cpu().numpy()) |
| 69 | |
| 70 | median = np.argmin(np.array(distances)) |
| 71 | ctx.features[index] = ctx.features[index] * ctx.momentum + (1 - ctx.momentum) * features[median] |
| 72 | ctx.features[index] /= ctx.features[index].norm() |
| 73 | |
| 74 | return grad_inputs, None, None, None |
| 75 | |
| 76 | |
| 77 | def cm_hard(inputs, indexes, features, momentum=0.5, device=None): |
nothing calls this directly
no outgoing calls
no test coverage detected