Hybrid CNN + SVM Feature Extraction

Hello everyone,

First time on the PyTorch forum. This is the first time I’m working with a PyTorch project, so bare with me if this is an easy misunderstanding.

I have a CNN that I trained/tested using the PyTorch basic CNN tutorial, and I believe I have a feature extractor working with it. I am trying to add the features into a new dataset that I can pass to a SVM model for training. These features are saved after a FC layer, so with a batch size of 4, each feature is (4, 84). The reason I am trying to create a new dataset from the features is that I have a SVM model that iterates over a trainingloader.

If there is an easier way of grabbing features to pass to another model, I am all open to suggestions. Below I have attached some of the code I am using.

Thanks,
Greg

# CNN Architecture: INPUT - CONV - RELU - MAXPOOL - CONV - RELU - MAXPOOL - FC1 - FC2 - FC3
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
        self.feature_ext = create_feature_extractor(self, return_nodes=[feature_layer])

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = torch.flatten(x, 1) # flatten all dimensions except batch
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    
    def extract_features(self, x):
        x = self.feature_ext(x)
        return x

# Training occurs here in my code.

# Extract features from TRAINING set (as an example)
feat_list = list()
label_list = list()
with torch.no_grad():   
    for data in trainloader:
        images, labels = data
        feat_list.append(net.extract_features(images)[feature_layer])
        label_list.append(labels)

# How to turn features into a dataset from here???

I think I finally figured it out. Is there a more efficient way to pass features apart from this:

# Extract features from TRAINING set
feat_list = list()
label_list = list()
with torch.no_grad():   
    for data in trainloader:
        images, labels = data
        feat_list.append(net.extract_features(images)[feature_layer])
        label_list.append(labels)

# Convert extracted features to a dataset
feat_tensor = torch.cat(feat_list, dim=0)
label_tensor = torch.cat(label_list, dim=0)
svm_dataset = TensorDataset(feat_tensor, label_tensor)
svm_train_size = int(0.8 * len(svm_dataset))  # 80% of the data for training
svm_test_size = len(svm_dataset) - svm_train_size  # Remaining 20% for testing
svm_train_dataset, svm_test_dataset = random_split(dataset, [svm_train_size, svm_test_size])
svm_batch_size = 4
svm_trainloader = DataLoader(svm_train_dataset, batch_size=svm_batch_size, shuffle=True)