-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
48adf9b
commit 759511e
Showing
6 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) |