unlearning LF

This commit is contained in:
2026-06-07 10:36:03 +02:00
parent e90480adbe
commit 61c3447150
10 changed files with 395 additions and 73 deletions

View File

@@ -1,29 +1,48 @@
import torch
from Strategy import Strategy
import torch.nn as nn
from .Strategy import Strategy
class NormalizingLinearFiltration(Strategy):
def __init__(self, target_class_idx):
class LinearFiltration(Strategy):
def __init__(self, target_class_idx: int):
super().__init__() # Automatically configures 'NormalizingLinearFiltration_metrics.txt'
self.target_class_idx = target_class_idx
def apply(self, model, forget_loader, retain_loader):
def _run(self, model: nn.Module) -> nn.Module:
model.eval()
# Freeze parameters structurally
for param in model.parameters():
param.requires_grad = False
with torch.no_grad():
# we modify only classification head
# Shape: [num_classes, feature_dim]
W = model.fc.weight.data
# Compute the normalization transformation projection matrix (A)
# (In your full code, calculate A here matching Baumhauer et al.'s equations)
W = model.fc.weight.data.clone()
num_classes = W.shape[0]
A = torch.eye(num_classes, device=W.device)
# Mask/blend target class index distribution configurations here...
A[self.target_class_idx, :] = 0.0
# 3. Direct weight matrix override: W_filtered = A * W
A = self._calculate_filtration_matrix(num_classes, self.target_class_idx, W.device)
sanitized_W = torch.mm(A, W)
model.fc.weight.copy_(sanitized_W)
model.fc.weight.copy_(sanitized_W)
return model
'''@staticmethod
def _calculate_filtration_matrix(num_classes: int, forget_class: int, device: torch.device) -> torch.Tensor:
A = torch.eye(num_classes, device=device)
num_remaining_classes = num_classes - 1
for j in range(num_classes):
if j == forget_class:
A[forget_class, j] = 0.0
else:
A[forget_class, j] = 1.0 / num_remaining_classes
return A'''
@staticmethod
def _calculate_filtration_matrix(num_classes: int, forget_class: int, device: torch.device) -> torch.Tensor:
A = torch.eye(num_classes, device=device)
num_remaining = num_classes - 1
# The row of the forgotten class should average the inputs of all other classes
for j in range(num_classes):
if j == forget_class:
A[forget_class, j] = 0.0
else:
A[forget_class, j] = 1.0 / num_remaining
return A