resolved
This commit is contained in:
7
LinearFiltration_metrics.txt
Normal file
7
LinearFiltration_metrics.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
execution_time_sec
|
||||||
|
0.000996
|
||||||
|
0.030071
|
||||||
|
0.001182
|
||||||
|
0.001176
|
||||||
|
0.001229
|
||||||
|
0.001257
|
||||||
48
OOP.py
Normal file
48
OOP.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
# This is from wikipedia pseudocode implementation of a single
|
||||||
|
# ThresholdLogic Unit.
|
||||||
|
# done to make me understand OOP the Python way
|
||||||
|
|
||||||
|
|
||||||
|
# no need for brackets if not inheriting
|
||||||
|
class ThresholdLogicUnit:
|
||||||
|
|
||||||
|
# define members in init
|
||||||
|
def __init__(self, threshold, weights):
|
||||||
|
self.threshold = threshold
|
||||||
|
self.weights = weights
|
||||||
|
|
||||||
|
|
||||||
|
# If a function has to make use of member variables
|
||||||
|
# it has to have self as param
|
||||||
|
def fire(self,inputs):
|
||||||
|
tots = 0
|
||||||
|
#for i in range(0,inputs.size()):
|
||||||
|
for val, weight in zip(inputs, self.weights):
|
||||||
|
if val:
|
||||||
|
tots+= weight
|
||||||
|
|
||||||
|
return tots > self.threshold
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# data
|
||||||
|
weights = [0.5, -0.2, 0.8]
|
||||||
|
threshold = 1.0
|
||||||
|
|
||||||
|
# Instantiate the class
|
||||||
|
tlu = ThresholdLogicUnit(threshold, weights)
|
||||||
|
|
||||||
|
# Test
|
||||||
|
test_inputs = [1, 1, 0]
|
||||||
|
result = tlu.fire(test_inputs)
|
||||||
|
|
||||||
|
print(f"The unit fired: {result}")
|
||||||
|
|
||||||
|
# The "Guard"
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +50,6 @@ class WeightFiltration(Strategy):
|
|||||||
for epoch in range(self.epochs):
|
for epoch in range(self.epochs):
|
||||||
t_loss_r, t_loss_f = 0.0, 0.0
|
t_loss_r, t_loss_f = 0.0, 0.0
|
||||||
steps = 0
|
steps = 0
|
||||||
|
|
||||||
# forget and retain
|
# forget and retain
|
||||||
for (r_inputs, r_labels), (f_inputs, f_labels) in zip(retain_loader, forget_loader):
|
for (r_inputs, r_labels), (f_inputs, f_labels) in zip(retain_loader, forget_loader):
|
||||||
r_inputs, r_labels = r_inputs.to(device), r_labels.to(device)
|
r_inputs, r_labels = r_inputs.to(device), r_labels.to(device)
|
||||||
|
|||||||
86
unlearning/wf/WF_Net.py
Normal file
86
unlearning/wf/WF_Net.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
import torch.nn.functional as F
|
||||||
|
|
||||||
|
class WF_Net(nn.Module):
|
||||||
|
"""
|
||||||
|
Implements Poppi et al.'s WF Model structure.
|
||||||
|
Wraps a pre-trained ResNet-18 and dynamically applies
|
||||||
|
weight-space gating matrix multiplication during the forward step.
|
||||||
|
"""
|
||||||
|
def __init__(self, original_model: nn.Module, num_classes: int):
|
||||||
|
super().__init__()
|
||||||
|
# Extract the sequence of blocks/layers L from the original model
|
||||||
|
self.conv1 = original_model.conv1
|
||||||
|
self.bn1 = original_model.bn1
|
||||||
|
self.relu = original_model.relu
|
||||||
|
self.maxpool = original_model.maxpool
|
||||||
|
|
||||||
|
self.layer1 = original_model.layer1
|
||||||
|
self.layer2 = original_model.layer2
|
||||||
|
self.layer3 = original_model.layer3
|
||||||
|
self.layer4 = original_model.layer4
|
||||||
|
|
||||||
|
self.avgpool = original_model.avgpool
|
||||||
|
self.fc = original_model.fc
|
||||||
|
|
||||||
|
# Target layer for filtering: layer4 block 1 conv2
|
||||||
|
# We extract its static tensor data out of the autograd parameter pool
|
||||||
|
self.target_conv = self.layer4[1].conv2
|
||||||
|
self.original_w = nn.Parameter(self.target_conv.weight.data.clone().detach(), requires_grad=False)
|
||||||
|
|
||||||
|
# Require: Alpha gating matrix. Shape: (num_classes, out_channels)
|
||||||
|
# Initialized to 1.5 as per Poppi et al.'s verbatim specification
|
||||||
|
out_channels = self.original_w.shape[0]
|
||||||
|
#self.alpha = nn.Parameter(torch.ones(num_classes, out_channels) * 1.5)
|
||||||
|
self.alpha = nn.Parameter(torch.ones(num_classes, out_channels))
|
||||||
|
|
||||||
|
def forward(self, x: torch.Tensor, target_class_indices: torch.Tensor) -> torch.Tensor:
|
||||||
|
# 1. Run through early sequence of layers undisturbed
|
||||||
|
x = self.maxpool(self.relu(self.bn1(self.conv1(x))))
|
||||||
|
x = self.layer1(x)
|
||||||
|
x = self.layer2(x)
|
||||||
|
x = self.layer3(x)
|
||||||
|
|
||||||
|
# Run layer4 block 0 normally
|
||||||
|
x = self.layer4[0](x)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# HERE IT IS: Save the structural skip connection (identity)
|
||||||
|
# BEFORE modifying features via block 1's convolutions
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
identity = x
|
||||||
|
|
||||||
|
# Now enter layer4 block 1
|
||||||
|
x = self.layer4[1].conv1(x)
|
||||||
|
x = self.layer4[1].bn1(x)
|
||||||
|
x = self.layer4[1].relu(x)
|
||||||
|
|
||||||
|
# [Your Step 1 Masking Math happens right here...]
|
||||||
|
batch_alpha = self.alpha[target_class_indices]
|
||||||
|
mask = torch.sigmoid(batch_alpha).view(x.size(0), -1, 1, 1)
|
||||||
|
|
||||||
|
# Run the functional convolution
|
||||||
|
x = F.conv2d(
|
||||||
|
x,
|
||||||
|
weight=self.original_w,
|
||||||
|
bias=self.target_conv.bias,
|
||||||
|
stride=self.target_conv.stride,
|
||||||
|
padding=self.target_conv.padding
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply your WF-Net channel mask
|
||||||
|
x = x * mask
|
||||||
|
x = self.layer4[1].bn2(x)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# HERE IT IS USED: Add the pristine identity back to the gated output
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
x = self.layer4[1].relu(x + identity)
|
||||||
|
|
||||||
|
# Final Classification Head Sequence
|
||||||
|
x = self.avgpool(x)
|
||||||
|
x = torch.flatten(x, 1)
|
||||||
|
y_out = self.fc(x)
|
||||||
|
|
||||||
|
return y_out
|
||||||
Reference in New Issue
Block a user