Skip to content

Commit

Permalink
Commit vanilla saliency
Browse files Browse the repository at this point in the history
  • Loading branch information
HwangJaeYoung committed Oct 10, 2021
1 parent 48adf9b commit 759511e
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ __pycache__/
# C extensions
*.so

# IntelliJ project files
.idea

# Distribution / packaging
.Python
build/
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions Interpretable_AI/Vanilla_gradient/Vanilla_backprop_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
### Source from
### https://towardsdatascience.com/saliency-map-using-pytorch-68270fe45e80

import torch
import torch.nn as nn
import torchvision
from torchvision import models
import matplotlib.pyplot as plt

# Initialize the model
#model = torch.load('<PATH_FILE_NAME>.pth')
model = torchvision.models.resnet18(pretrained=False)


# Set the model to run on the GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = model.to(device)

# Set the model on Eval Mode
model.eval()

from torchvision import transforms
from PIL import Image

# Open the image file
image = Image.open('Vanilla_backprop_1.jpg')

# Set up the transformations
transform_ = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),transforms.ToTensor(),
transforms.Normalize(mean=[0., 0., 0.], std=[1., 1., 1.])
])

# Transforms the image
image = transform_(image)

image = image.reshape(1, 3, 224, 224)

image = image.to(device)

image.requires_grad_()

# Retrieve output from the image
output = model(image)
print(output.shape)

# Catch the output
output_idx = output.argmax()
print(output_idx)

output_max = output[0, output_idx]
print(output_max)

# Do backpropagation to get the derivative of the output based on the image
output_max.backward()

# Retireve the saliency map and also pick the maximum value from channels on each pixel.
# In this case, we look at dim=1. Recall the shape (batch_size, channel, width, height)

saliency, _ = torch.max(image.grad.abs(), dim=1)
print(saliency.shape)

saliency = saliency.reshape(224, 224)

# Reshape the image
image = image.reshape(-1, 224, 224)

# Visualize the image and the saliency map
fig, ax = plt.subplots(1, 2)
ax[0].imshow(image.cpu().detach().numpy().transpose(1, 2, 0))
ax[0].axis('off')
ax[1].imshow(saliency.cpu(), cmap='hot')
ax[1].axis('off')
plt.tight_layout()
fig.suptitle('The Image and Its Saliency Map')
plt.show()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions Interpretable_AI/Vanilla_gradient/Vanilla_backprop_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
### Source from
### https://medium.datadriveninvestor.com/visualizing-neural-networks-using-saliency-maps-in-pytorch-289d8e244ab4

import torch
import torchvision
import torchvision.transforms as T
import matplotlib.pyplot as plt
import requests
from PIL import Image

#Using VGG# -19 pretrained model for image classification
model = torchvision.models.vgg19(pretrained=True)
for param in model.parameters():
param.requires_grad = False

def download(url, fname):
response = requests.get(url)
with open(fname, "wb") as f:
f.write(response.content)

# Downloading the image
download("https://specials-images.forbesimg.com/imageserve/5db4c7b464b49a0007e9dfac/960x0.jpg?fit=scale", "Vanilla_backprop_2.jpg")

# Opening the image
img = Image.open('Vanilla_backprop_2.jpg')

# Preprocess the image
def preprocess(image, size=224):
transform = T.Compose([
T.Resize((size, size)),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
T.Lambda(lambda x: x[None]),
])
return transform(image)

# preprocess the image
X = preprocess(img)

# we would run the model in evaluation mode
model.eval()

# we need to find the gradient with respect to the input image, so we need to call requires_grad_on it
X.requires_grad_()

'''
forward pass through the model to get the scores, note that VGG-19 model doesn't perform softmax at the end
and we also don't need softmax, we need scores, so that's perfect for us.
'''

scores = model(X)

# Get the index corresponding to the maximum score and the maximum score itself.
score_max_index = scores.argmax()
score_max = scores[0, score_max_index]

'''
backward function on score_max performs the backward pass in the computation graph and calculates the gradient of
score_max with respect to nodes in the computation graph
'''
score_max.backward()

'''
Saliency would be the gradient with respect to the input image now. But note that the input image has 3 channels,
R, G and B. To derive a single class saliency value for each pixel (i, j), we take the maximum magnitude
across all colour channels.
'''
saliency, _ = torch.max(X.grad.data.abs(), dim=1)
print(saliency[0].shape)

# code to plot the saliency map as a heatmap
plt.imshow(saliency[0], cmap=plt.cm.hot)
plt.axis('off')
plt.show()
79 changes: 79 additions & 0 deletions Interpretable_AI/pytorch_test/pytorch_cnn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import torch
from functools import partial
from sklearn.datasets import make_classification
from torch.utils.data import Dataset
from torch.utils.data import DataLoader

X, y = make_classification(n_samples=100, n_features=5, random_state=42)

class CustomDataset(Dataset):
def __init__(self, X, y, transform=None):
self.X = X
self.y = y
self.transform = transform

def __len__(self):
return len(self.X)

def __getitem__(self, idx):
x = X[idx]
label = y[idx]

if self.transform:
x = self.transform(x)
label = self.transform(label)

return x, label

torch_tensor_float32 = partial(torch.tensor, dtype=torch.float32)
transformed_dataset = CustomDataset(X, y, transform=torch_tensor_float32)

dataloader = DataLoader(transformed_dataset, batch_size=4, shuffle=True)

num_features = 5
num_outputs = 1
layer_dims = [num_features, 5, 3, num_outputs]

# Model Definition
model = torch.nn.Sequential(
torch.nn.Linear(5, 5),
torch.nn.ReLU(),
torch.nn.Linear(5, 3),
torch.nn.ReLU(),
torch.nn.Linear(3, 1),
torch.nn.Sigmoid()
)

class BinaryClassifier(torch.nn.Sequential):
def __init__(self, layer_dims):
super(BinaryClassifier, self).__init__()

for idx, dim in enumerate(layer_dims):
if idx < len(layer_dims) - 1:
module = torch.nn.Linear(dim, layer_dims[idx + 1])
self.add_module(f"linear{idx}", module)
if idx < len(layer_dims) - 2:
activation = torch.nn.ReLU()
self.add_module(f"relu{idx}", activation)
elif idx == len(layer_dims) - 2:
activation = torch.nn.Sigmoid()
self.add_module(f"sigmoid{idx}", activation)

bc_model = BinaryClassifier(layer_dims)

criterion = torch.nn.BCELoss()
optimizer = torch.optim.Adam(bc_model.parameters())

num_epochs = 10

for epoch in range(num_epochs):
for idx, (X_batch, labels) in enumerate(dataloader):
optimizer.zero_grad()
outputs = bc_model(X_batch)
outputs = torch.flatten(outputs)
loss = criterion(outputs, labels.float())
loss.backward()
optimizer.step()

pred_var = bc_model(transformed_dataset[0][0])
print(pred_var.detach().numpy()[0])

0 comments on commit 759511e

Please sign in to comment.