Interceptor
In this example, you gonna learn how to use Interceptor to capture intermediate values in the execution of a PyTorch module.
[1]:
import torch # PyTorch
from pytorch_probing import Interceptor # Intercepts intermediate values.
We gonna start creating a example a module:
[2]:
class ExampleModel(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_hidden=0):
super().__init__()
self.linear1 = torch.nn.Linear(input_size, hidden_size)
self.relu = torch.nn.ReLU()
if n_hidden > 0:
layers = []
for _ in range(n_hidden):
layers.append(torch.nn.Linear(hidden_size, hidden_size))
layers.append(torch.nn.ReLU())
self.hidden_layers = torch.nn.Sequential(*layers)
self._n_hidden = n_hidden
self.linear2 = torch.nn.Linear(hidden_size, output_size)
def forward(self, x):
x = self.linear1(x)
x = self.relu(x)
if self._n_hidden > 0:
x = self.hidden_layers(x)
x = self.linear2(x)
return x
In this case, we gonna use 2 hidden layers between the first and last layer:
[3]:
input_size = 2
hidden_size = 3
output_size = 1
n_hidden = 2
model = ExampleModel(input_size, hidden_size, output_size, n_hidden)
model.eval()
[3]:
ExampleModel(
(linear1): Linear(in_features=2, out_features=3, bias=True)
(relu): ReLU()
(hidden_layers): Sequential(
(0): Linear(in_features=3, out_features=3, bias=True)
(1): ReLU()
(2): Linear(in_features=3, out_features=3, bias=True)
(3): ReLU()
)
(linear2): Linear(in_features=3, out_features=1, bias=True)
)
Than, we gonna pass our created module to a Interceptor, with the paths of the submodules we wanna get its outputs. Notices that we can use “.” to get inner submodules:
[4]:
paths = ["linear1", "hidden_layers.2", "linear2"]
intercepted_model = Interceptor(model, paths, detach=False)
intercepted_model.eval()
[4]:
Interceptor(
(_module): ExampleModel(
(linear1): InterceptorLayer(
(_module): Linear(in_features=2, out_features=3, bias=True)
)
(relu): ReLU()
(hidden_layers): Sequential(
(0): Linear(in_features=3, out_features=3, bias=True)
(1): ReLU()
(2): InterceptorLayer(
(_module): Linear(in_features=3, out_features=3, bias=True)
)
(3): ReLU()
)
(linear2): InterceptorLayer(
(_module): Linear(in_features=3, out_features=1, bias=True)
)
)
)
The Interceptor modifies in-place the original module:
[5]:
model
[5]:
ExampleModel(
(linear1): InterceptorLayer(
(_module): Linear(in_features=2, out_features=3, bias=True)
)
(relu): ReLU()
(hidden_layers): Sequential(
(0): Linear(in_features=3, out_features=3, bias=True)
(1): ReLU()
(2): InterceptorLayer(
(_module): Linear(in_features=3, out_features=3, bias=True)
)
(3): ReLU()
)
(linear2): InterceptorLayer(
(_module): Linear(in_features=3, out_features=1, bias=True)
)
)
We pass a example input throught the model:
[6]:
inputs = torch.randn([10, 2])
with torch.no_grad():
outputs = intercepted_model(inputs)
[7]:
outputs
[7]:
tensor([[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029]])
And the interceptor captures the required outputs and stores then in the “outputs” attribute:
[8]:
intercepted_model.outputs
[8]:
{'linear1': tensor([[ 0.1654, 0.0663, -0.7493],
[ 0.3264, -0.9112, -0.8976],
[ 0.1156, 0.0056, -0.8358],
[ 0.7862, -1.3303, -0.4560],
[ 0.3589, -1.0462, -0.9049],
[ 0.0942, -0.3027, -0.9759],
[ 0.7300, -1.1132, -0.4494],
[ 0.5927, -0.4919, -0.4003],
[ 0.3150, -0.3468, -0.7065],
[-0.5145, 0.6613, -1.4115]]),
'hidden_layers.2': tensor([[-0.5792, -0.1493, -0.1676],
[-0.5853, -0.1682, -0.1807],
[-0.5907, -0.1497, -0.1603],
[-0.6053, -0.2082, -0.2035],
[-0.5843, -0.1710, -0.1838],
[-0.5923, -0.1483, -0.1580],
[-0.6003, -0.2033, -0.2024],
[-0.5879, -0.1913, -0.1997],
[-0.5856, -0.1673, -0.1795],
[-0.4808, -0.0937, -0.1802]]),
'linear2': tensor([[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029],
[-0.0029]])}
We can clean this outputs with the interceptor_clear method:
[9]:
intercepted_model.interceptor_clear()
intercepted_model.outputs
[9]:
{'linear1': None, 'hidden_layers.2': None, 'linear2': None}
And return the model to its original state with the reduce method:
[10]:
intercepted_model.reduce()
model
[10]:
ExampleModel(
(linear1): Linear(in_features=2, out_features=3, bias=True)
(relu): ReLU()
(hidden_layers): Sequential(
(0): Linear(in_features=3, out_features=3, bias=True)
(1): ReLU()
(2): Linear(in_features=3, out_features=3, bias=True)
(3): ReLU()
)
(linear2): Linear(in_features=3, out_features=1, bias=True)
)