Skip to content

Conversation

ProGamerGov
Copy link
Contributor

@ProGamerGov ProGamerGov commented Nov 13, 2020

I moved all loss objectives from captum.optim._core.objectives to captum.optim._core.loss as per: #500 (comment)

  • I changed the loss functions to classes and made it so that they were building off an abstract loss class. The new classes work with the existing objective optimization code, so no changes to that were needed.

  • The tutorials were also updated to reflect the loss changes.

  • The loss changes should be compatible with / not be in conflict with: Optim-WIP: Preliminary transform unit tests & more #521

  • Added a ton of missing type hints.

  • I added the 3 Direction objectives that we were missing. They've been tested and work with the current objective system.

  • Added Channel Interpolation objective, and made it possible to use without selecting specific channels.

  • Added layer objective.

  • Added alignment objective.

  • Added weight objective (all 3 weight objectives merged into a single objective class).

  • I got LaplacianImage working. It seems to work pretty good for feature visualization!

  • I added an init parameter to FFTImage, LaplacianImage, and NaturalImage.

  • FFTImage, NaturalImage, PixelImage, LaplacianImage, InputOptimization, and ToRGB all support batch sizes now!

  • Added decorrelate_init & squash_func parameters to NaturalImage.

  • Added size property / function to ImageTensor, as size is more PyTorch-like than shape I think.

  • Fixed major bug where errors / interrupts to the InputOptimization class' optimize function resulted in activations being None in subsequent runs.

  • Custom input images now also work correctly!

test_c5

@ProGamerGov
Copy link
Contributor Author

ProGamerGov commented Nov 13, 2020

@NarineK I left the loss objective functionality the exact same, so that @greentfrapp and I can change them as we tackle issues like: #496 (comment), and allowing for non mean & penalty losses.

This PR is ready for review as I will likely not be making any major changes to it for the moment.

ProGamerGov added a commit to ProGamerGov/captum that referenced this pull request Nov 13, 2020
ProGamerGov referenced this pull request in ProGamerGov/captum Nov 15, 2020
@ProGamerGov ProGamerGov reopened this Nov 20, 2020
Copy link
Contributor

@NarineK NarineK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for moving the losses into a separate file and extending from the Loss ABC, @ProGamerGov! It looks like, there are a couple of losses that assume NCHW input shape - we could group them together or leave as is. It's probably fine to leave them as is right now.

In general I think that it would be great if we could document and explain the losses a bit more in detail and point out to the related papers.
I also added a couple inline comments. Let me know what you think.

pass

def get_neuron_pos(
self, H: int, W: int, x: Optional[int] = None, y: Optional[int] = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a specific logic for images ? Perhaps we can keep this function in _utils package ?

Copy link
Contributor Author

@ProGamerGov ProGamerGov Nov 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's specific logic meant to be used along with activations in the form of NCHW, and I've moved it to a new _utils/images.py file.

H_vec, W_vec = self.direction.size(2), self.direction.size(3)
H_activ, W_activ = activations.size(2), activations.size(3)

H = (H_activ - W_vec) // 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: H_vec ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had it as H_vec because of the input variable name vec, but I've changed it to be H_direction now as that seems more readable.


class TensorDirection(Loss):
"""
Visualize a tensor direction.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do you mind adding some description here about this loss w.r.t. cosine similarity, etc. ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a citation and link to the distil paper that the direction objectives come from.

self.direction = vec.reshape((1, -1, 1, 1))

def __call__(self, targets_to_values: ModuleOutputMapping) -> torch.Tensor:
activations = targets_to_values[self.target]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think that it would be good to assert the sizes of self.direction and activations before computing cosine similarity on them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an assert for the channel size of self.direction & activations. @greentfrapp may be able to add more assertion tests in his upcoming PR.

activations = targets_to_values[self.target]
x_diff = activations[..., 1:, :] - activations[..., :-1, :]
y_diff = activations[..., :, 1:] - activations[..., :, :-1]
return torch.sum(torch.abs(x_diff)) + torch.sum(torch.abs(y_diff))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this L1-norm w.r.t. total variation of height and width ?

Copy link
Contributor Author

@ProGamerGov ProGamerGov Nov 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the sum of the absolute differences for neighboring values in the activations or image. TensorFlow's version (that Lucid uses) links to this Wikipedia page: https://en.wikipedia.org/wiki/Total_variation_denoising

My neural-style-pt project uses basically the same algorithm, but it's origins trace back to this research article: https://arxiv.org/abs/1412.0035

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chris also says that TensorFlow's total variation algorithm comes from the Understanding Deep Image Representations by Inverting Them paper: https://arxiv.org/abs/1412.0035


class ActivationInterpolation(Loss):
"""
Interpolate between two different layers & channels
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a paper related to this loss. It would be good to document it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a link and citiation for Activation Interpolation!

(activ_a - activ_b) ** 2
).mean() / self.decay_ratio ** float(d)

return sum_tensor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: because we are optimizing negative loss do we want to return sum_tensor ? I'm asking that because the losses are returning the opposite sign here for other losses as well:
https://github.com/greentfrapp/lucent/blob/master/lucent/optvis/objectives.py

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the InputOptimization class doesn't support losses like Alignment. So, I've left them as they are for @greentfrapp to change, as he's currently working on the optimization system.

@ProGamerGov
Copy link
Contributor Author

@NarineK I'll have to think about the ordering of the objectives, but for the moment we can leave them in their current order.

As for the losses, I'll work on writing more in-depth descriptions with @greentfrapp, but in the meantime we can leave the descriptions as they are so that @greentfrapp can continue his work on the optimization stuff.

@ProGamerGov ProGamerGov requested a review from NarineK November 24, 2020 19:38
Copy link
Contributor

@NarineK NarineK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this PR, @ProGamerGov !

@NarineK NarineK merged commit 3cf1675 into pytorch:optim-wip Nov 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants