Would a quick sketch of your description look something like this?
class Encoder(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Encoder, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, hidden_size//2),
            nn.ReLU(),
            nn.Linear(hidden_size//2, output_size),
        )
    
    def forward(self, x):
        out = self.layers(x)
        return out


class Classifier(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(Classifier, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, hidden_size//2),
            nn.ReLU(),
            nn.Linear(hidden_size//2, 1),
        )
    
    def forward(self, x):
        out = self.layers(x)
        out = F.sigmoid(out)
        return out

Training loop:
criterion = nn.BCELoss()
encoder_net = Encoder(input_size, hidden_size, output_size)
classifier_net = Classifier(input_size, hidden_size)

for e in num_epochs:
    for idx, (data, target) in enumerate(data_loader):
        data1, data2 = data
        output1 = encoder_net(data1)
        output2 = encoder_net(data2)
        if output1 > output2:
            predicted_label = torch.ones([1,1])
        else:
            predicted_label = torch.zeros([1,1)
        
        loss = criterion(predicted_label, target)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

I am still unsure if the criterion in the above “pseudocode” is structured correctly. That is, is it correct to have criterion(predicted_label, target) where criterion = nn.BCELoss()? Would the gradient back-propagate through this loss? If so, how is this different from the one-model architecture I had in my original post? Also, in this case, would I have two optimizers, one per network, and call optimizer1.zero_grad(), optimizer2.zero_grad(), optimizer1.step(), optimizer2.step()?
Thanks a lot!!