Visualizing Convolutional Neural Network Features with 40 Lines of Python Code
This article demonstrates how to visualize convolutional features of a VGG‑16 network using only about 40 lines of Python code, explains the underlying concepts, walks through generating patterns by maximizing filter activations, and provides a complete implementation with hooks, loss functions, and multi‑scale optimization.
Convolutional Neural Networks (CNNs) have revolutionized computer vision, and understanding what each filter detects is an important research problem. This article shows how to visualize the learned features of a VGG‑16 model using a concise Python implementation.
The structure of the article is threefold: first, visualizations of several VGG‑16 layers (Layer 7, 14, 20, 30, and 40) are presented; second, the author interprets selected patterns (e.g., cathedral arches, chicken heads, feathers, chains, cat ears) and demonstrates hypothesis testing by feeding real images through the network; third, the complete code that generates these visualizations is explained.
Feature visualization treats a deep network as a cascade of information‑distilling filters. By maximizing the average activation of a chosen feature map, one can synthesize an image that strongly excites that filter, a technique also known as neural style transfer.
For each displayed layer the article shows example filters (e.g., filters 12, 16, 86, 110 in Layer 7) together with the generated patterns. The author notes how pattern complexity grows with depth and how some visualizations resemble recognizable objects.
To reproduce the results, the workflow starts with a random‑noise image: img = np.uint8(np.random.uniform(150, 180, (sz, sz, 3))) / 255 which is wrapped in a PyTorch variable that requires gradients: img_var = V(img[None], requires_grad=True)
A pretrained VGG‑16 model is loaded in evaluation mode and its parameters are frozen: model = vgg16(pre=True).eval() set_trainable(model, False)
Activations of a target layer are captured with a forward hook. The helper class is defined as:
<code>class SaveFeatures():
def __init__(self, module):
self.hook = module.register_forward_hook(self.hook_fn)
def hook_fn(self, module, input, output):
self.features = torch.tensor(output, requires_grad=True).cuda()
def close(self):
self.hook.remove()</code>The loss to be maximized is the negative mean activation of the selected filter:
loss = -activations.features[0, j].mean()An Adam optimizer updates the pixel values:
optimizer = torch.optim.Adam([img_var], lr=lr, weight_decay=1e-6)The optimization loop runs for a few steps, repeatedly computing the forward pass, back‑propagating the loss, and stepping the optimizer. After each up‑scaling step the image is resized (e.g., using cv2.resize ) and optionally blurred to suppress high‑frequency artifacts.
The full implementation is encapsulated in the FilterVisualizer class, which handles multi‑scale up‑scaling, optional blurring, and saving the final pattern image. Example usage:
<code>layer = 40
filter = 265
FV = FilterVisualizer(size=56, upscaling_steps=12, upscaling_factor=1.2)
FV.visualize(layer, filter, blur=5)</code>The code assumes an NVIDIA GPU; if unavailable it can be run on Google Colab. The article concludes with links to additional Python learning resources.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.