Use this skill when working with convolutional neural feature ansatz (CNFA), deep convolutional recursive feature machines (Deep ConvRFM), or tasks involving kernel-based feature learning with convolutional architectures, VGG networks, patch-based Jacobian computation, and EGOP (expected gradient outer product) analysis on image datasets such as ImageNet and CIFAR.
Instrucciones de origen · Vista previa de solo lectura
name
convrfm
description
Use this skill when working with convolutional neural feature ansatz (CNFA), deep convolutional recursive feature machines (Deep ConvRFM), or tasks involving kernel-based feature learning with convolutional architectures, VGG networks, patch-based Jacobian computation, and EGOP (expected gradient outer product) analysis on image datasets such as ImageNet and CIFAR.
Convrfm skill
When to use
Activate this skill when:
Implementing or experimenting with the convolutional neural feature ansatz (CNFA)
Training or evaluating deep convolutional recursive feature machines (Deep ConvRFM)
Computing expected gradient outer products (EGOP) for patch-based convolutional layers
Verifying neural feature ansatz properties in pretrained or VGG-style networks
Extracting feature embeddings from convolutional neural networks for kernel analysis
Running binary or multiclass classification experiments on image datasets using RFM-based methods
Generating toy datasets for testing convolutional feature learning pipelines
Analyzing hyperparameter sensitivity of CNFA-based models
Visualizing VGG kernel eigenvectors or passing eigenvectors through network layers
Keywords that trigger this skill: CNFA, convolutional neural feature ansatz, ConvRFM, deep RFM, recursive feature machine, EGOP, patch Jacobian, VGG features, kernel learning, convolutional kernel, imagenet features, patchify, conv embedding.
Description: Code for convolutional neural feature ansatz and deep ConvRFM
Related paper concepts: Neural Feature Ansatz (NFA), Recursive Feature Machines (RFM), Expected Gradient Outer Product (EGOP), convolutional patch kernels
No official documentation site or demo URL is provided by the repository
Installation/setup
Prerequisites
Python 3.7+
PyTorch (with CUDA support recommended for large-scale experiments)
torchvision
NumPy
SciPy (for kernel/eigenvalue computations)
h5py (for dataset loading)
Install dependencies
pip install torch torchvision numpy scipy h5py
Clone the repository
git clone https://github.com/aradha/convrfm.git
cd convrfm
Dataset setup
ImageNet: Provide a local path to the ImageNet dataset directory. The loader expects the standard ImageNet folder structure.
CIFAR / toy data: Use the provided gen_toy_data.py script to generate synthetic datasets for quick experimentation.
python gen_toy_data.py
Core features
Convolutional neural feature ansatz (CNFA) verification: Verify that the EGOP of a trained convolutional network matches its learned kernel features, using pretrained and VGG-based networks (cnfa_verification/).
Deep ConvRFM training: Iteratively train convolutional recursive feature machines that refine feature representations through gradient-based kernel updates (deep_conv_rfm/).
Convolutional network training: Train standard and binary classification convolutional networks on image datasets with utilities for embedding extraction and model evaluation (conv_nets/).
Patch-based Jacobian computation: Decompose convolutional network outputs into patch-level Jacobians, enabling per-patch feature analysis and EGOP estimation (cnfa_verification/pretrained_conv_nfa.py, cnfa_verification/vgg_conv_nfa.py).
EGOP computation: Compute the expected gradient outer product over a dataset to derive the effective feature matrix for kernel comparisons.
VGG kernel visualization: Compute and visualize eigenvectors of VGG-derived kernels, and pass eigenvectors through network layers for interpretability (vgg_vis/).
Hyperparameter CNFA verification: Study the effect of hyperparameters on CNFA properties, including correlation analysis across training regimes (hyperparam_cnfa_verification/).
Binary classification support: Specialized pipelines for binary classification tasks with filter extraction utilities (conv_nets/binary_main.py, deep_conv_rfm/binary_main.py).
Flexible dataset utilities: Custom dataset classes for ImageNet and other image datasets with configurable batch sizes and preprocessing (cnfa_verification/dataset.py, cnfa_verification/loader.py).
Toy data generation: Generate synthetic datasets to test and validate pipeline components without requiring large real-world datasets (gen_toy_data.py).
Usage examples
Note: The repository README does not contain inline code examples. The following examples are derived directly from analysis of the repository source files.
Generate toy data
python gen_toy_data.py
Train a convolutional network (multiclass)
cd conv_nets
python main.py
Train a convolutional network (binary classification)
cd conv_nets
python binary_main.py
Run deep ConvRFM (multiclass)
cd deep_conv_rfm
python main.py
Run deep ConvRFM (binary classification)
cd deep_conv_rfm
python binary_main.py
Run CNFA verification with a pretrained network
cd cnfa_verification
python pretrained_conv_nfa.py
Run CNFA verification with VGG
cd cnfa_verification
python vgg_conv_nfa.py
Run VGG kernel visualization
cd vgg_vis
python main.py
Run hyperparameter CNFA verification
cd hyperparam_cnfa_verification
python main.py
Key APIs/models
Classes
Class
Module
Description
PatchConvLayer
cnfa_verification/pretrained_conv_nfa.py
Wraps a convolutional layer to operate on patchified inputs for Jacobian/EGOP computation
PatchBasicBlock
cnfa_verification/pretrained_conv_nfa.py
Patch-based wrapper for ResNet BasicBlock layers
PatchBottleneck
cnfa_verification/pretrained_conv_nfa.py
Patch-based wrapper for ResNet Bottleneck layers
PatchConvLayer
cnfa_verification/vgg_conv_nfa.py
Patch-based convolutional layer wrapper for VGG-style networks
ImageNet
cnfa_verification/loader.py
Custom PyTorch Dataset class for loading ImageNet with transforms
MyDataset
conv_nets/binary_main.py
Custom dataset class for binary classification experiments
Key functions
Function
Module
Description
patchify(x, patch_size, stride_size)
cnfa_verification/pretrained_conv_nfa.py
Extracts overlapping patches from input tensor x
get_jacobian(net, data, c_idx)
cnfa_verification/pretrained_conv_nfa.py
Computes the Jacobian of network output w.r.t. input patches for class index c_idx
egop(model, X)
cnfa_verification/pretrained_conv_nfa.py
Computes the expected gradient outer product (EGOP) over dataset X using model
patchify(x, patch_size, stride_size)
cnfa_verification/vgg_conv_nfa.py
Patch extraction for VGG-style feature maps
get_jacobian(net, data, c_idx)
cnfa_verification/vgg_conv_nfa.py
Jacobian computation for VGG-based networks
egop(model, z)
cnfa_verification/vgg_conv_nfa.py
EGOP computation for VGG-based models
get_imagenet(batch_size, path)
cnfa_verification/dataset.py
Returns a DataLoader for ImageNet given batch size and dataset path
get_filter(net, layer)
conv_nets/binary_main.py
Extracts filter weights from a specified layer of network net
get_classes(X_full, y_full, c1)
conv_nets/binary_main.py
Filters dataset to return samples belonging to class c1 for binary tasks
Sub-modules
Module
Purpose
cnfa_verification/
CNFA verification using pretrained ResNet and VGG networks
conv_nets/
Standard CNN training, embedding extraction, and evaluation utilities
deep_conv_rfm/
Deep ConvRFM training loop, gradient computation, and model definitions
hyperparam_cnfa_verification/
Hyperparameter sensitivity analysis for CNFA
vgg_vis/
VGG kernel eigenvector computation and visualization
Common patterns and best practices
Patchify before Jacobian computation: Always apply patchify(x, patch_size, stride_size) to input tensors before passing them to get_jacobian. Patch size and stride should match the receptive field of the target convolutional layer.
EGOP over batches: For large datasets like ImageNet, compute EGOP in mini-batches and accumulate to avoid memory overflow. The egop function takes a model and a data tensor X; ensure X is moved to the appropriate device before calling.
Binary vs multiclass pipelines: Use binary_main.py for two-class problems and main.py for multiclass. The binary pipeline uses get_classes to filter datasets and get_filter to inspect learned filters.
Dataset paths: When using get_imagenet(batch_size, path), ensure path points to the root ImageNet directory containing train/ and val/ subdirectories in the standard ImageNet folder format.
Device management: The codebase is designed for GPU use. Always set tensors and models to .cuda() or the appropriate device before running Jacobian or EGOP computations.
Gradient computation: When calling get_jacobian, ensure the model is in evaluation mode (model.eval()) and that torch.no_grad() is not active, since Jacobian computation requires gradient tracking.
VGG visualization workflow: Use vgg_vis/kernel.py to compute kernels, then vgg_vis/pass_eigvs.py to propagate eigenvectors through the network, and finally vgg_vis/main.py to orchestrate the full visualization pipeline.
Toy data for debugging: Use gen_toy_data.py to generate small synthetic datasets when debugging pipeline components before scaling to ImageNet or CIFAR.
Demo Scripts
scripts/egop_and_patchify_demo.py
#!/usr/bin/env python3"""
Demo: EGOP computation and patch extraction using ConvRFM utilities
This script demonstrates how to use the core components of the convrfm
repository:
- patchify(): extract overlapping patches from image tensors
- get_jacobian(): compute per-patch Jacobians of a network output
- egop(): compute the Expected Gradient Outer Product (EGOP) over a dataset
- get_imagenet(): construct an ImageNet DataLoader
- PatchConvLayer: wrap a convolutional layer for patch-based processing
Requirements:
pip install torch torchvision numpy scipy
NOTE: This script is structured to run standalone with synthetic data
for demonstration. Replace IMAGENET_PATH with your actual ImageNet
root directory to use real data.
"""import sys
import os
import numpy as np
import torch
import torch.nn as nn
import torchvision.models as tv_models
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, TensorDataset
# ---------------------------------------------------------------------------# Path setup: add repository root to sys.path so local modules are importable# when running from inside the cloned convrfm directory.# Adjust REPO_ROOT to point to the cloned convrfm repository on your system.# ---------------------------------------------------------------------------
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, REPO_ROOT)
# ---------------------------------------------------------------------------# Configuration# ---------------------------------------------------------------------------
IMAGENET_PATH = "/path/to/imagenet"# Replace with your ImageNet root path
BATCH_SIZE = 16
PATCH_SIZE = 3
STRIDE_SIZE = 1
NUM_CLASSES =
DEVICE = torch.cuda.is_available()
()
():
( + * )
()
( * )
x = torch.randn(, , , )
()
:
cnfa_verification.pretrained_conv_nfa patchify
patches = patchify(x, patch_size=PATCH_SIZE, stride_size=STRIDE_SIZE)
()
()
()
(
)
ImportError e:
(
)
()
patches = standalone_patchify(x, patch_size=PATCH_SIZE, stride_size=STRIDE_SIZE)
()
patches
() -> torch.Tensor:
N, C, H, W = x.shape
patches = x.unfold(, patch_size, stride_size).unfold(, patch_size, stride_size)
n_h = patches.shape[]
n_w = patches.shape[]
patches = patches.contiguous().view(N, C, n_h * n_w, patch_size * patch_size)
patches = patches.permute(, , , ).contiguous()
patches = patches.view(N, n_h * n_w, C * patch_size * patch_size)
patches
():
( + * )
()
( * )
(nn.Module):
():
().__init__()
.fc = nn.Linear( * PATCH_SIZE * PATCH_SIZE, NUM_CLASSES)
():
N, P, D = x.shape
out = .fc(x.view(N * P, D))
out.view(N, P, NUM_CLASSES)
net = ToyConvNet().to(DEVICE)
net.()
data = torch.randn(, , * PATCH_SIZE * PATCH_SIZE, requires_grad=).to(DEVICE)
c_idx =
:
cnfa_verification.pretrained_conv_nfa get_jacobian
jac = get_jacobian(net, data, c_idx)
()
()
()
ImportError e:
()
()
jac = standalone_get_jacobian(net, data, c_idx)
()
()
()
jac
() -> torch.Tensor:
data = data.detach().requires_grad_()
output = net(data)
scalar = output[:, :, c_idx].()
scalar.backward()
jac = data.grad.clone()
jac
():
( + * )
()
( * )
patch_dim = * PATCH_SIZE * PATCH_SIZE
num_patches =
N =
(nn.Module):
():
().__init__()
.proj = nn.Linear(in_dim, n_classes)
() -> torch.Tensor:
N, P, D = x.shape
.proj(x.view(N * P, D)).view(N, P, -)
model = ToyNet(in_dim=patch_dim, n_classes=NUM_CLASSES).to(DEVICE)
model.()
X = torch.randn(N, num_patches, patch_dim).to(DEVICE)
:
cnfa_verification.pretrained_conv_nfa egop
egop_matrix = egop(model, X)
()
()
()
ImportError e:
()
()
egop_matrix = standalone_egop(model, X)
()
()
egop_matrix
() -> np.ndarray:
N, P, D = X.shape
egop_accum = np.zeros((D, D), dtype=np.float64)
i (N):
x_i = X[i:i+].detach().requires_grad_()
output = model(x_i)
num_classes = output.shape[-]
c (num_classes):
scalar = output[, :, c].()
scalar.backward(retain_graph=(c < num_classes - ))
x_i.grad :
g = x_i.grad[].detach().cpu().numpy()
egop_accum += g.T @ g
x_i.grad.zero_()
egop_accum /= N
egop_accum
():
( + * )
()
( * )
os.path.exists(IMAGENET_PATH):
:
cnfa_verification.dataset get_imagenet
loader = get_imagenet(batch_size=BATCH_SIZE, path=IMAGENET_PATH)
batch = ((loader))
images, labels = batch
()
()
()
loader
ImportError e:
()
:
()
()
fake_images = torch.randn(, , , )
fake_labels = torch.randint(, , (,))
fake_dataset = TensorDataset(fake_images, fake_labels)
fake_loader = DataLoader(fake_dataset, batch_size=BATCH_SIZE, shuffle=)
batch = ((fake_loader))
images, labels = batch
(
)
()
(
)
fake_loader
():
( + * )
()
( * )
(nn.Module):
():
().__init__()
.conv1 = nn.Conv2d(, , kernel_size=, padding=)
.conv2 = nn.Conv2d(, , kernel_size=, padding=)
.fc = nn.Linear( * * , )
() -> torch.Tensor:
x = torch.relu(.conv1(x))
x = torch.relu(.conv2(x))
x = x.view(x.size(), -)
.fc(x)
net = SimpleConvNet()
:
conv_nets.binary_main get_filter
filters = get_filter(net, layer=)
()
ImportError e:
()
()
filters = standalone_get_filter(net, layer=)
()
np.random.seed()
X_full = np.random.randn(, ).astype(np.float32)
y_full = np.random.randint(, , size=)
c1 =
:
conv_nets.binary_main get_classes
X_c1, y_c1 = get_classes(X_full, y_full, c1)
()
()
()
()
ImportError e:
()
()
X_c1, y_c1 = standalone_get_classes(X_full, y_full, c1)
()
()
()
()
() -> torch.Tensor:
(net, layer).weight.data
() -> :
mask = y_full == c1
X_full[mask], y_full[mask]
():
( + * )
()
( * )
N, C, H, W = , , ,
n_classes =
patch_size =
stride =
patch_dim = C * patch_size * patch_size
images = torch.randn(N, C, H, W).to
"""
Demonstrate the patchify function from cnfa_verification/pretrained_conv_nfa.py.
patchify(x, patch_size, stride_size) extracts overlapping spatial patches
from a 4D tensor of shape (N, C, H, W), returning a tensor of shape
(N, num_patches, C * patch_size * patch_size).
"""
x: torch.Tensor, patch_size: int, stride_size: int
"""
Standalone reimplementation of patchify() for demonstration purposes.
Mirrors the logic in cnfa_verification/pretrained_conv_nfa.py.
Args:
x (torch.Tensor): Input tensor of shape (N, C, H, W).
patch_size (int): Height and width of each square patch.
stride_size (int): Stride between consecutive patches.
Returns:
torch.Tensor: Tensor of shape (N, num_patches, C * patch_size * patch_size).
"""
"""
Demonstrate get_jacobian() from cnfa_verification/pretrained_conv_nfa.py.
get_jacobian(net, data, c_idx) computes the Jacobian of the network output
for class index c_idx with respect to the input data (patches).
The Jacobian shape is (num_patches, input_dim) for a single sample or
batched as (N, num_patches, input_dim).
"""
print
"\n"
"="
60
print
"Section 2: get_jacobian() demonstration"
print
"="
60
# Build a minimal network for illustration
# In practice, this would be a pretrained ResNet or VGG layer wrapper
class
ToyConvNet
def
__init__
self
super
self
3
def
forward
self, x
# x: (N, num_patches, patch_dim) -- flatten for demo
"""
Standalone Jacobian computation mirroring the logic in
cnfa_verification/pretrained_conv_nfa.py.
Args:
net (nn.Module): Network to differentiate through.
data (torch.Tensor): Patchified input of shape (N, num_patches, patch_dim).
c_idx (int): Class index to compute gradients for.
Returns:
torch.Tensor: Jacobian of shape (N, num_patches, patch_dim).
"""
"""
Demonstrate egop() from cnfa_verification/pretrained_conv_nfa.py.
egop(model, X) computes the Expected Gradient Outer Product over dataset X.
The EGOP is the average of J^T J over all samples, where J is the Jacobian
of the network output with respect to the input features. This forms the
basis of the Neural Feature Ansatz.
Returns:
np.ndarray: EGOP matrix of shape (patch_dim, patch_dim).
"""
print
"\n"
"="
60
print
"Section 3: egop() demonstration"
print
"="
60
3
16
8
# Small synthetic dataset
class
ToyNet
"""Minimal network for EGOP demonstration."""
def
__init__
self, in_dim: int, n_classes: int
super
self
def
forward
self, x: torch.Tensor
# x: (N, num_patches, patch_dim)
return
self
1
eval
# Synthetic dataset: (N, num_patches, patch_dim)
try
from
import
print
f"Input X shape: {X.shape}"
print
f"EGOP matrix shape: {egop_matrix.shape}"
print
f"EGOP matrix dtype: {egop_matrix.dtype}"
except
as
print
f"[INFO] Could not import from repository: {e}"
print
"[FALLBACK] Running standalone EGOP computation:"
print
f"Input X shape: {X.shape}"
print
f"EGOP matrix shape: {egop_matrix.shape}"
return
def
standalone_egop
model: nn.Module, X: torch.Tensor
"""
Standalone EGOP computation mirroring egop() in
cnfa_verification/pretrained_conv_nfa.py.
Computes E[J^T J] where J is the Jacobian of all class outputs
w.r.t. each patch, averaged over the dataset.
Args:
model (nn.Module): Trained neural network.
X (torch.Tensor): Patchified dataset of shape (N, num_patches, patch_dim).
Returns:
np.ndarray: EGOP matrix of shape (patch_dim, patch_dim).
"""
"""
Demonstrate get_imagenet() from cnfa_verification/dataset.py.
get_imagenet(batch_size, path) returns a PyTorch DataLoader for the
ImageNet validation set. Requires a local copy of ImageNet at `path`.
This demo shows the expected call signature and what the loader returns.
It uses a synthetic TensorDataset as fallback when the real path is absent.
"""
"""
Demonstrate get_filter() and get_classes() from conv_nets/binary_main.py.
get_filter(net, layer): extracts the weight tensor from a named layer
of network `net`.
get_classes(X_full, y_full, c1): filters dataset arrays to return only
samples belonging to class c1, used for binary classification setup.
"""
print
"\n"
"="
60
print
"Section 5: get_filter() and get_classes() demonstration"
print
"="
60
# --- get_filter() ---
class
SimpleConvNet
"""Minimal CNN with named layers for filter extraction demo."""
"""
Standalone implementation of get_filter() from conv_nets/binary_main.py.
Args:
net (nn.Module): Trained convolutional network.
layer (str): Name of the layer to extract filters from.
Returns:
torch.Tensor: Weight tensor of the specified layer.
"""
return
getattr
def
standalone_get_classes
X_full: np.ndarray,
y_full: np.ndarray,
c1: int
tuple
"""
Standalone implementation of get_classes() from conv_nets/binary_main.py.
Args:
X_full (np.ndarray): Full feature matrix of shape (N, D).
y_full (np.ndarray): Full label array of shape (N,).
c1 (int): Target class index to filter.
Returns:
tuple: (X_c1, y_c1) -- filtered features and labels for class c1.
"""