Custom autograd functions in PyTorch allow users to define their own gradients for non-standard or complex operations, enabling the creation of custom neural network architectures and loss functions that can be trained with automatic differentiation. Here is the process of implementing a custom autograd function in PyTorch:
1. Extend ‘torch.autograd.Function‘ and define the forward and backward passes of your custom function. The forward pass computes the output of your function given the inputs, while the backward pass computes the gradients of the output with respect to the inputs.
2. In the forward pass, you can use ‘ctx.save_for_backward‘ to save any tensors that will be needed in the backward pass. These tensors can be accessed later in ‘backward‘ using ‘ctx.saved_tensors‘.
3. In the backward pass, you will receive the gradients of the output tensor with respect to its corresponding tensor in the output tuple, and you can compute the gradients of the input tensors with respect to the loss using these gradients and the saved tensors from ‘ctx.saved_tensors‘.
4. Register your function with ‘torch.autograd.Function.apply‘ so that it can be used in PyTorch’s automatic differentiation.
Here’s an example of how you might implement a custom autograd function to create a loss function that measures the cosine similarity between two tensors:
import torch
class CosineSimilarityLossFunction(torch.autograd.Function):
@staticmethod
def forward(ctx, input1, input2):
cos_sim = torch.nn.functional.cosine_similarity(input1, input2)
ctx.save_for_backward(input1, input2)
return cos_sim
@staticmethod
def backward(ctx, grad_output):
input1, input2 = ctx.saved_tensors
grad_input1 = grad_input2 = None
if ctx.needs_input_grad[0]:
cosine_loss_grad = grad_output.unsqueeze(-1) * input2
cosine_loss_grad = cosine_loss_grad - torch.sum(input1 * cosine_loss_grad, dim=-1, keepdim=True) * input1
grad_input1 = -cosine_loss_grad
if ctx.needs_input_grad[1]:
cosine_loss_grad = grad_output.unsqueeze(-1) * input1
cosine_loss_grad = cosine_loss_grad - torch.sum(input2 * cosine_loss_grad, dim=-1, keepdim=True) * input2
grad_input2 = -cosine_loss_grad
return grad_input1, grad_input2
class CosineSimilarityLoss(torch.nn.Module):
def __init__(self):
super().__init__()
def forward(self, input1, input2):
sim = CosineSimilarityLossFunction.apply(input1, input2)
loss = 1 - sim
return loss.mean()
In this example, ‘CosineSimilarityLossFunction‘ computes the cosine similarity between two inputs in the ‘forward‘ pass, and the gradients of the inputs with respect to the loss in the ‘backward‘ pass. The ‘CosineSimilarityLoss‘ module uses this function to compute a loss between two input tensors.
This implementation can be used as follows:
input1 = torch.randn(10, 20, requires_grad=True)
input2 = torch.randn(10, 20, requires_grad=True)
loss_fn = CosineSimilarityLoss()
loss = loss_fn(input1, input2)
loss.backward()
In this example, ‘input1‘ and ‘input2‘ are 10x20 tensors with requires_grad=True, and the ‘CosineSimilarityLoss‘ function can be used as a custom loss function in PyTorch. The ‘loss.backward()‘ line computes the gradients with respect to ‘input1‘ and ‘input2‘ using the custom autograd function defined in ‘CosineSimilarityLossFunction‘.