This is a Siamese Neural Network that compares the similarity between two unenhanced fingerpints. This model is similair to Fingerprint Siamese Neural Network for Unenhanced Fingerprint Images (2/27/2023), which achieved a test accuracy of 93% on images of unenhanced fingerprints. The main difference with Fingerprint Siamese Neural Network 2.0 is that its network architecture modified to include more channels per layer. This was done in an attempt to help increase its performance and avoid overfitting. This would not only help the Siamese Neural Network compare the similarity between two fingerprints, but it would give the Fingerprint GAN more starting information about the fingerprint's structure if it was used to produce the initial latent vector.
This Siamese Neural Network was adapted from https://github.com/kevinzakka/one-shot-siamese/blob/master/model.py for comparing images of characters. This model will be trained on a dataset of synthetically generated fringerprints using the Anguli software.
This model was run from 3/07/2023 through 3/08/2023.
!pip install Augmentor
!pip install pillow
!pip install seaborn
%reload_ext autoreload
%autoreload
Collecting Augmentor Downloading Augmentor-0.2.10-py2.py3-none-any.whl (38 kB) Requirement already satisfied: future>=0.16.0 in /usr/lib/python3/dist-packages (from Augmentor) (0.18.2) Requirement already satisfied: tqdm>=4.9.0 in /usr/local/lib/python3.9/dist-packages (from Augmentor) (4.64.0) Requirement already satisfied: numpy>=1.11.0 in /usr/local/lib/python3.9/dist-packages (from Augmentor) (1.23.1) Requirement already satisfied: Pillow>=5.2.0 in /usr/local/lib/python3.9/dist-packages (from Augmentor) (9.2.0) Installing collected packages: Augmentor Successfully installed Augmentor-0.2.10 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv Requirement already satisfied: pillow in /usr/local/lib/python3.9/dist-packages (9.2.0) WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv Requirement already satisfied: seaborn in /usr/local/lib/python3.9/dist-packages (0.11.2) Requirement already satisfied: numpy>=1.15 in /usr/local/lib/python3.9/dist-packages (from seaborn) (1.23.1) Requirement already satisfied: pandas>=0.23 in /usr/local/lib/python3.9/dist-packages (from seaborn) (1.4.3) Requirement already satisfied: matplotlib>=2.2 in /usr/local/lib/python3.9/dist-packages (from seaborn) (3.5.2) Requirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.9/dist-packages (from seaborn) (1.8.1) Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (1.4.3) Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (2.8.2) Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (4.34.4) Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (0.11.0) Requirement already satisfied: pyparsing>=2.2.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (3.0.9) Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (21.3) Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.2->seaborn) (9.2.0) Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/dist-packages (from pandas>=0.23->seaborn) (2022.1) Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7->matplotlib>=2.2->seaborn) (1.14.0) WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import transforms
from torch.utils.data import DataLoader
from torch.utils.data.dataset import Dataset
import torchvision.utils as vutils
import torchvision.datasets as dset
import torchvision.transforms.functional as Fv
import os
import time
import math
import random
import Augmentor
import numpy as np
import random
from numpy import unravel_index
import matplotlib.pyplot as plt
from PIL import Image
from tqdm import tqdm
from random import Random
from skimage.util import random_noise
from IPython.display import HTML
import matplotlib.animation as animation
model_results_file = "checkpoint/SSNN_results.pt"
model_ckpt_filename = "checkpoint/SSNN/SSNN_checkpoint"
im_size = (300, 206)
var_max = 0.5
num_train = 10000
num_valid = 4000
num_workers = 4
shuffle = True
augment = True
sim_label = 1.0
diff_label = 0.0
# Number of channels in the training images. For color images this is 3
nc = 1
# Size of feature maps in Siamese Neural Network
ndf = 256
# Learning rate for optimizers
slr = 0.0002
# Beta1 hyperparam for Adam optimizers
beta1 = 0.5
# Number of GPUs available. Use 0 for CPU mode.
ngpu = 2
# Decide which device we want to run on
device = torch.device("cuda:0" if (torch.cuda.is_available()) else "cpu")
S_losses = []
iters = 0
num_epochs = 250
def loadModel(filepath, netS, optimizerS, S_losses):
# Load checkpoint
if os.path.isfile(filepath):
checkpoint = torch.load(filepath)
netS.load_state_dict(checkpoint['netS_state_dict'])
optimizerS.load_state_dict(checkpoint['optimizerS_state_dict'])
S_losses = checkpoint['S_losses']
iters = checkpoint['iters']
start_epoch = checkpoint['epoch']
return netS, optimizerS, S_losses, iters, start_epoch
return None
def saveCkpt(filepath, epoch, netS, optimizerS, S_losses, iters):
if os.path.isfile(filepath):
os.remove(filepath)
torch.save({
'epoch' : epoch,
'netS_state_dict' : netS.state_dict(),
'optimizerS_state_dict' : optimizerS.state_dict(),
'S_losses' : S_losses,
'iters' : iters,
}, filepath)
def showSampleFingerprintPairs(test_loader):
# Get a Batch of Sample Images
batch = next(iter(test_loader))
labels = batch[2][:8]
# Display the Sample Images
plt.figure(figsize=(20,6))
plt.subplot(2,1,1)
plt.axis("off")
plt.imshow(np.transpose(vutils.make_grid(batch[0].to(device)[:8], padding=5, normalize=True).cpu(),(1,2,0)))
plt.subplot(2,1,2)
plt.axis("off")
plt.imshow(np.transpose(vutils.make_grid(batch[1].to(device)[:8], padding=5, normalize=True).cpu(),(1,2,0)))
plt.show()
c = 0
if labels is not None:
for l in labels:
if l == 1:
print(" same ", end="")
else:
print(" diff ", end="")
if c % 4 == 0:
print(" ", end="")
c += 1
def validate(epoch):
# switch to evaluate mode
netD.eval()
correct = 0
total = 0
for i, (val_Im1, val_Im2, val_y) in enumerate(valid_loader):
with torch.no_grad():
variation = random.uniform(0,var_max)
val_Im1 = torch.tensor(random_noise(val_Im1, mode='gaussian', mean=0, var=variation, clip=True), dtype=torch.float32)
val_Im1, val_Im2, val_y = val_Im1.to(device), val_Im2.to(device), val_y.to(device)
batch_size = val_Im1.shape[0]
# compute log probabilities
pred = torch.round(netD(val_Im1, val_Im2))
correct += (pred == val_y).sum().item()
total += batch_size
if total > num_valid:
break
# compute acc and log
valid_acc = (100. * correct) / total
return valid_acc
class AverageMeter(object):
"""
Computes and stores the average and
current value.
"""
def __init__(self):
self.reset()
def reset(self):
self.val = 0
self.avg = 0
self.sum = 0
self.count = 0
def update(self, val, n=1):
self.val = val
self.sum += val * n
self.count += n
self.avg = self.sum / self.count
class MovingAvg(object):
"""
Computes the moving average of values
"""
def __init__(self, length=10):
self.length = length
self.movingAvg = np.array([], dtype='f')
def average(self):
return np.average(self.movingAvg)
def pop(self):
if len(self.movingAvg > 0):
self.movingAvg = np.delete(self.movingAvg, 0, axis = 0)
def push(self, val):
self.movingAvg = np.append(self.movingAvg, [val])
if len(self.movingAvg) > self.length:
self.movingAvg = np.delete(self.movingAvg, 0, axis = 0)
def get_train_loader(target_dir, template_dir,
batch_size,
num_train,
num_valid,
shuffle=False,
num_workers=2,
pin_memory=False):
"""
Utility function for loading and returning train
iterator over the dataset.
If using CUDA, num_workers should be set to `1` and pin_memory to `True`.
Args
----
- target_dir: path directory to the target dataset.
- template_dir: path directory to the template dataset.
- batch_size: how many samples per batch to load.
- augment: whether to load the augmented version of the train dataset.
- num_workers: number of subprocesses to use when loading the dataset. Set
to `1` if using GPU.
- pin_memory: whether to copy tensors into CUDA pinned memory. Set it to
`True` if using GPU.
"""
fingerprints = [str(finger) for finger in range(1,10000+1)]
random.shuffle(fingerprints)
training_prints = fingerprints[:10000]
# Get the Training Dataloader
train_dataset = FingerprintLoader(target_dir, template_dir, num_train, training_prints, batch_size)
train_loader = DataLoader(
train_dataset, batch_size=batch_size, shuffle=shuffle,
num_workers=num_workers, pin_memory=pin_memory,
)
return (train_loader)
def get_train_valid_test_loaders(target_dir, template_dir,
batch_size,
num_train,
num_valid,
shuffle=False,
num_workers=2,
pin_memory=False):
"""
Utility function for loading and returning train and valid
iterators over the dataset.
If using CUDA, num_workers should be set to `1` and pin_memory to `True`.
Args
----
- target_dir: path directory to the target dataset.
- template_dir: path directory to the template dataset.
- batch_size: how many samples per batch to load.
- augment: whether to load the augmented version of the train dataset.
- num_workers: number of subprocesses to use when loading the dataset. Set
to `1` if using GPU.
- pin_memory: whether to copy tensors into CUDA pinned memory. Set it to
`True` if using GPU.
"""
# Each unique Fingerprint is named as a number from 1 to 10,000 (10000 unique fingerprints)
fingerprints = [str(finger) for finger in range(1,10000+1)]
random.shuffle(fingerprints)
training_prints = fingerprints[:7000]
validation_prints = fingerprints[7000:9500]
test_prints = fingerprints[9500:]
# Get the Training Dataloader
train_dataset = FingerprintLoader(target_dir, template_dir, num_train, training_prints, batch_size)
train_loader = DataLoader(
train_dataset, batch_size=batch_size, shuffle=shuffle,
num_workers=num_workers, pin_memory=pin_memory,
)
# Get the Validation Dataloader
valid_dataset = FingerprintLoader(target_dir, template_dir, num_valid, validation_prints, batch_size)
valid_loader = DataLoader(
valid_dataset, batch_size=batch_size, shuffle=shuffle,
num_workers=num_workers, pin_memory=pin_memory,
)
# Get the Test Dataloader
test_dataset = FingerprintLoader(target_dir, template_dir, num_valid, test_prints, batch_size)
test_loader = DataLoader(
test_dataset, batch_size=batch_size, shuffle=shuffle,
num_workers=num_workers, pin_memory=pin_memory,
)
return (train_loader, valid_loader, test_loader)
class FingerprintLoader(Dataset):
"""
This class is used to help load the fingerpint dataset.
"""
def __init__(self, target_dataset, template_dataset, num_train, dataset, batch_size):
"""
Initializes an instance for the FingerprintLoader class.
:param self: instance of the FingerprintLoader class
:param template_dataset: The template fingerprint dataset
:param target_dataset: The second fingerprint dataset to match against
the template dataset
:param num_train: The number of images to load
:param dataset: List of fingerprints to include in the set
"""
super(FingerprintLoader, self).__init__()
self.target_dataset = target_dataset
self.template_dataset = template_dataset
self.fingerprints_dataset = dataset
self.num_train = num_train
self.augment = augment
self.batch_size = batch_size
def __len__(self):
"""
Helper function to return the length of the dataset
:param self: instance of the FingerprintLoader class
:return: the length of the dataset as an int
"""
return self.num_train
def __getitem__(self, index):
"""
Getter function for accessing images from the dataset. This function will choose a
fingerprint image from the dataset and its corresponding enhanced fingerprint image.
It will then preprocess the images before returning them.
:param self: instance of the FingerprintLoader class
:param index: index for data image in set to return
:return: Image from dataset as a tensor
"""
target_im_filepath, template_im_filepath, y = self.chooseFingerprintPair()
targ_im = self.preprocessImage(target_im_filepath)
temp_img = self.preprocessImage(template_im_filepath)
y = torch.from_numpy(np.array([y], dtype=np.float32))
return targ_im, temp_img, y
def chooseFingerprintPair(self):
"""
Returns the filepath of the target fingerprint image and the enhanced template fingerprint.
:param self: instance of the FingerprintLoader class
:return: The filepaths for the
"""
target_im_filepath = "targetim.jpg"
enhanced_target_im_filepath = "targetim.jpg"
y = float(random.randint(0,1))
# Chose image
while not os.path.isfile(target_im_filepath) or not os.path.isfile(template_im_filepath):
target_im_filepath = self.target_dataset + random.choice(os.listdir(self.target_dataset))
target_im_filepath += "/Impression_1/"
target_im_name = random.choice(self.fingerprints_dataset)
target_im_filepath = target_im_filepath + target_im_name + '.jpg'
template_im_name = target_im_name
if y < 0.9:
while template_im_name == target_im_name:
template_im_name = random.choice(self.fingerprints_dataset)
template_im_filepath = self.template_dataset + random.choice(os.listdir(self.template_dataset)) \
+ "/Impression_1/" + template_im_name + '.jpg'
return target_im_filepath, template_im_filepath, y
def preprocessImage(self, im_filepath):
"""
Preprocesses the image. This function will open the image, convert
it to grayscale, pad the image in order to make is square,
normalize the image, and then finally convert it to a tensor.
:param im: Filepath of the image to preprocess
:return: The preprocessed image
"""
im = Image.open(im_filepath)
# Convert to Grayscale
trans = transforms.Compose([#p.torch_transform(),
transforms.Resize(im_size),
transforms.Grayscale(1),
transforms.ToTensor(),
transforms.Normalize((0.5, ), (0.5, )),
])
# Apply the transformations to the images and labels
preprocessedImage = trans(im)
return preprocessedImage
# custom weights initialization called on netG and netD
def weights_init(m):
classname = m.__class__.__name__
if classname.find('Conv') != -1:
nn.init.normal_(m.weight.data, 0.0, 0.02)
elif classname.find('BatchNorm') != -1:
nn.init.normal_(m.weight.data, 1.0, 0.02)
nn.init.constant_(m.bias.data, 0)
class SiameseNet(nn.Module):
"""
A Convolutional Siamese Network for One-Shot Learning [1].
Siamese networts learn image representations via a supervised metric-based
approach. Once tuned, their learned features can be leveraged for one-shot
learning without any retraining.
References
----------
https://github.com/kevinzakka/one-shot-siamese/blob/master/model.py
- Koch et al., https://www.cs.cmu.edu/~rsalakhu/papers/oneshot1.pdf
"""
def __init__(self):
super(SiameseNet, self).__init__()
# Device
self.ngpu = ngpu
# Convolutional Layers
self.conv1 = nn.Conv2d(nc, ndf, 4, 2, 1, bias=False)
self.conv2 = nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False)
self.conv3 = nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False)
self.conv4 = nn.Conv2d(ndf * 4, ndf * 8, 4, 1, 1, bias=False)
self.conv5 = nn.Conv2d(ndf * 8, 1, 4, 1, 1, bias=False)
# Batch Norm Layers
self.bn1 = nn.BatchNorm2d(ndf * 2)
self.bn2 = nn.BatchNorm2d(ndf * 4)
self.bn3 = nn.BatchNorm2d(ndf * 8)
self.bn4 = nn.BatchNorm2d(ndf * 16)
# Fully Connected Layers
self.fc1 = nn.Linear(1225, 512)
self.fc2 = nn.Linear(805, 1)
def sub_forward(self, x):
"""
Forward pass the input image through 1 subnetwork.
Args
----
- x: Contains either the first or second image pair across the input batch.
Returns
-------
- out: The hidden vector representation of the input vector x.
"""
out = F.leaky_relu_(self.conv1(x), 0.2)
out = F.leaky_relu_(self.bn1(self.conv2(out)), 0.2)
out = F.leaky_relu_(self.bn2(self.conv3(out)), 0.2)
out = F.leaky_relu_(self.bn3(self.conv4(out)), 0.2)
out = self.conv5(out).view(out.shape[0], -1)
return out
def forward(self, x1, x2):
"""
Forward pass the input image pairs through both subtwins. An image
pair is composed of a left tensor x1 and a right tensor x2.
Concretely, we compute the component-wise L1 distance of the hidden
representations generated by each subnetwork, and feed the difference
to a final fc-layer followed by a sigmoid activation function to
generate a similarity score in the range [0, 1] for both embeddings.
Args
----
- x1: a Variable of size (B, C, H, W). The left image pairs along the
batch dimension.
- x2: a Variable of size (B, C, H, W). The right image pairs along the
batch dimension.
Returns
-------
- probas: a Variable of size (B, 1). A probability scalar indicating
whether the left and right input pairs, along the batch dimension,
correspond to the same class. We expect the network to spit out
values near 1 when they belong to the same class, and 0 otherwise.
"""
# encode image pairs
h1 = self.sub_forward(x1)
h2 = self.sub_forward(x2)
# compute l1 distance
diff = torch.abs(h1 - h2)
# score the similarity between the 2 encodings
scores = torch.sigmoid(self.fc2(diff))
return scores
# Create the Siamese Neural Network
netS = SiameseNet().to(device)
# Handle multi-gpu if desired
if (device.type == 'cuda') and (ngpu > 1):
netS = nn.DataParallel(netS, list(range(ngpu)))
# Apply the weights_init function to randomly initialize all weights
# to mean=0, stdev=0.2.
netS.apply(weights_init)
# Print the model
print(netS)
DataParallel(
(module): SiameseNet(
(conv1): Conv2d(1, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(conv2): Conv2d(256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(conv3): Conv2d(512, 1024, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(conv4): Conv2d(1024, 2048, kernel_size=(4, 4), stride=(1, 1), padding=(1, 1), bias=False)
(conv5): Conv2d(2048, 1, kernel_size=(4, 4), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(bn2): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(bn4): BatchNorm2d(4096, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(fc1): Linear(in_features=1225, out_features=512, bias=True)
(fc2): Linear(in_features=805, out_features=1, bias=True)
)
)
The model will first be trained to match the enhanced fingerprint pair versions just as before. This will allow the subnetwork to learn how to extract the features from good quality fingerprints.
# create data loaders
torch.manual_seed(1)
batch_size = 256
kwargs = {}
if device.type == 'cuda':
torch.cuda.manual_seed(1)
kwargs = {'num_workers': ngpu, 'pin_memory': True}
target_dir = "/storage/Prepped_Fingerprints_206x300/Enhanced_Good/"
template_dir = "/storage/Prepped_Fingerprints_206x300/Enhanced_Good/"
# Create the dataloader
num_train = 100000
num_valid = 4000
data_loader = get_train_valid_test_loaders(target_dir, template_dir, batch_size, num_train, num_valid, shuffle, **kwargs)
train_loader = data_loader[0]
valid_loader = data_loader[1]
test_loader = data_loader[2]
criterion = nn.BCELoss()
slr = 0.0002
# Setup Adam optimizers for S
optimizerS = optim.Adam(netS.parameters(), lr=slr, betas=(beta1, 0.999))
It was difficult to get access to large enough fingerprint datasets for training. This is because fingerprints are considered personal information, so this data is not commonly avaiable to everyone. Because of this, I ended up having to synthetically generate my own dataset using the Anguli software. This generated dataset contains close to one million fingerprint images of varying qualities, which includes around 10,000 unique fingerprints.
Below are some sample images that the Fingerprint Siamese Neural Network will be trained on, which is a subset of the dataset containing around 100,000 enhanced images of the good quality synthetic fingerprints in the datase.
showSampleFingerprintPairs(test_loader)
same diff diff same diff same diff diff
# Train
def train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=[], num_epochs=10, start_epoch=1, end_epoch=num_epochs, iters=1):
# Lists to keep track of progress
iters = 0
print("\n[*] Train on {} sample pairs, validate on {} sample pairs".format(
num_train, num_valid)
)
gLossMvAvg = MovingAvg()
for epoch in range(start_epoch, end_epoch+1):
print('\nEpoch: {}/{}'.format(epoch, num_epochs))
# switch to train mode
netS.train()
train_batch_time = AverageMeter()
train_losses = AverageMeter()
tic = time.time()
training_accuracy = 0.0
num_correct = 0
total = 0
with tqdm(total=num_train) as pbar:
for i, (x1, x2, y) in enumerate(train_loader):
x1, x2, y = x1.to(device), x2.to(device), y.to(device)
output = netS(x1, x2).view(-1)
y = y.view(-1)
errS = criterion(output, y)
# Calculate the gradients for this batch
errS.backward()
# Update S
optimizerS.step()
for i in range(len(output)):
label = 0.0
if output[i] > 0.5:
label = 1.0
if label == y[i]:
num_correct += 1
total += 1
training_accuracy = num_correct / total * 100
# store batch statistics
toc = time.time()
train_batch_time.update(toc-tic)
tic = time.time()
pbar.set_description(
(
"loss_S: {:.3f} training accuracy: {:.6f}".format(errS.item(), training_accuracy)
)
)
pbar.update(batch_size)
# Save Losses for plotting later
S_losses.append(errS.item())
iters +=1
# Validate
netS.eval()
validation_accuracy = 0.0
num_valid_correct = 0
total_valid = 0
for i, (x1, x2, y) in enumerate(valid_loader):
x1, x2, y = x1.to(device), x2.to(device), y.to(device)
output = netS(x1, x2).view(-1)
y = y.view(-1)
for i in range(len(output)):
label = 0.0
if output[i] > 0.5:
label = 1.0
if label == y[i]:
num_valid_correct += 1
total_valid += 1
validation_accuracy = num_valid_correct / total_valid * 100
print("Validataion Accuracy: {:.6f}".format(validation_accuracy))
filename = model_ckpt_filename + "_epochs_" + str(start_epoch) + "-" + str(end_epoch) + ".pt"
saveCkpt(filename, 1, netS, optimizerS, S_losses, iters)
return S_losses, iters
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=1, end_epoch=1, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 1/250
loss_S: 0.189 training accuracy: 89.576000: : 100096it [07:45, 215.13it/s]
Validataion Accuracy: 99.475000
Next the model will be trained to match unenhanced good fingerprints to enhance fingerprint images. The hope is that this will help the network bridge the gap between matching enhanced fingerprint pairs to unenhanced fingerprint pairs.
# create data loaders
torch.manual_seed(1)
batch_size = 256
kwargs = {}
if device.type == 'cuda':
torch.cuda.manual_seed(1)
kwargs = {'num_workers': ngpu, 'pin_memory': True}
target_dir = "/storage/Prepped_Fingerprints_206x300/Good/"
template_dir = "/storage/Prepped_Fingerprints_206x300/Enhanced_Good/"
# Create the dataloader
num_train = 100000
num_valid = 4000
data_loader = get_train_valid_test_loaders(target_dir, template_dir, batch_size, num_train, num_valid, shuffle, **kwargs)
train_loader = data_loader[0]
valid_loader = data_loader[1]
test_loader = data_loader[2]
criterion = nn.BCELoss()
slr = 0.00002
# Setup Adam optimizers for S
optimizerS = optim.Adam(netS.parameters(), lr=slr, betas=(beta1, 0.999))
Below are some sample images that the Fingerprint Siamese Neural Network will be trained on. The top row consists of the unenhanced good quality fingerprints, which is a subset of the dataset consisting of around 100,000 fingerprint images with 10,000 unique fingerprints. The bottom row consists of the enhanaced fingerprint images, which is a different subset of the dataset that also consists of around 100,000 fingerprint images containing the same 10,000 unique fingerprints as the perviously described subset. Please note that the enhanced fingerprint subset was generated from the unenhanced good fingerprint subset using Gabor Filters.
showSampleFingerprintPairs(test_loader)
same diff diff same diff same diff diff
Finally, the model will be trained to match unenhanced fingerprint pairs of varying qualities (from really good to really bad).
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=2, end_epoch=3, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 2/250
loss_S: 1.250 training accuracy: 98.128000: : 100096it [12:32, 132.95it/s]
Validataion Accuracy: 79.525000 Epoch: 3/250
loss_S: 0.625 training accuracy: 99.063000: : 100096it [13:54, 119.96it/s]
Validataion Accuracy: 88.600000
Finally, the model will be trained to match unenhanced fingerprint pairs of varying qualities (from really good to really bad).
# create data loaders
torch.manual_seed(1)
batch_size = 256
kwargs = {}
if device.type == 'cuda':
torch.cuda.manual_seed(1)
kwargs = {'num_workers': ngpu, 'pin_memory': True}
target_dir = "/storage/Prepped_Fingerprints_206x300/Bad/"
template_dir = "/storage/Prepped_Fingerprints_206x300/Bad/"
# Create the dataloader
num_train = 100000
num_valid = 4000
data_loader = get_train_valid_test_loaders(target_dir, template_dir, batch_size, num_train, num_valid, shuffle, **kwargs)
train_loader = data_loader[0]
valid_loader = data_loader[1]
test_loader = data_loader[2]
criterion = nn.BCELoss()
slr = 0.000002
# Setup Adam optimizers for S
optimizerS = optim.Adam(netS.parameters(), lr=slr, betas=(beta1, 0.90))
Below are some sample images that the Fingerprint Siamese Neural Network will be trained on, which is a larger subset containing around 800,000 unenhanced fingerprint images of varying qualityies from really good to really bad.
showSampleFingerprintPairs(test_loader)
same diff diff same diff diff diff same
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=4, end_epoch=10, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 4/250
loss_S: 36.214 training accuracy: 63.182000: : 100096it [20:45, 80.35it/s]
Validataion Accuracy: 63.800000 Epoch: 5/250
loss_S: 36.875 training accuracy: 62.144000: : 100096it [17:43, 94.11it/s]
Validataion Accuracy: 60.975000 Epoch: 6/250
loss_S: 35.643 training accuracy: 59.847000: : 100096it [08:24, 198.53it/s]
Validataion Accuracy: 60.050000 Epoch: 7/250
loss_S: 38.797 training accuracy: 57.197000: : 100096it [15:57, 104.54it/s]
Validataion Accuracy: 55.900000 Epoch: 8/250
loss_S: 47.527 training accuracy: 55.660000: : 100096it [16:42, 99.87it/s]
Validataion Accuracy: 53.575000 Epoch: 9/250
loss_S: 46.256 training accuracy: 54.591000: : 100096it [17:15, 96.67it/s]
Validataion Accuracy: 53.825000 Epoch: 10/250
loss_S: 51.758 training accuracy: 54.492000: : 100096it [17:20, 96.23it/s]
Validataion Accuracy: 54.975000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=11, end_epoch=20, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 11/250
loss_S: 42.047 training accuracy: 55.901000: : 100096it [17:09, 97.18it/s]
Validataion Accuracy: 54.825000 Epoch: 12/250
loss_S: 41.875 training accuracy: 58.552000: : 100096it [16:35, 100.52it/s]
Validataion Accuracy: 60.300000 Epoch: 13/250
loss_S: 34.995 training accuracy: 61.959000: : 100096it [15:51, 105.18it/s]
Validataion Accuracy: 64.700000 Epoch: 14/250
loss_S: 40.045 training accuracy: 65.461000: : 100096it [15:49, 105.40it/s]
Validataion Accuracy: 66.950000 Epoch: 15/250
loss_S: 30.357 training accuracy: 67.476000: : 100096it [17:11, 97.06it/s]
Validataion Accuracy: 66.725000 Epoch: 16/250
loss_S: 35.690 training accuracy: 67.923000: : 100096it [20:37, 80.88it/s]
Validataion Accuracy: 68.700000 Epoch: 17/250
loss_S: 30.235 training accuracy: 68.256000: : 100096it [22:41, 73.53it/s]
Validataion Accuracy: 67.500000 Epoch: 18/250
loss_S: 28.061 training accuracy: 69.271000: : 100096it [19:50, 84.09it/s]
Validataion Accuracy: 69.025000 Epoch: 19/250
loss_S: 34.892 training accuracy: 69.457000: : 100096it [22:33, 73.93it/s]
Validataion Accuracy: 69.400000 Epoch: 20/250
loss_S: 31.453 training accuracy: 69.331000: : 100096it [25:29, 65.45it/s]
Validataion Accuracy: 68.525000
netS, optimizerS, S_losses, iters, start_epoch = loadModel('checkpoint/SSNN/SSNN_checkpoint_epochs_11-20.pt', netS, optimizerS, S_losses)
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=21, end_epoch=30, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 21/250
loss_S: 33.469 training accuracy: 70.438000: : 100096it [20:21, 81.95it/s]
Validataion Accuracy: 71.300000 Epoch: 22/250
loss_S: 32.988 training accuracy: 72.363000: : 100096it [20:41, 80.63it/s]
Validataion Accuracy: 72.250000 Epoch: 23/250
loss_S: 25.074 training accuracy: 71.873000: : 100096it [19:02, 87.63it/s]
Validataion Accuracy: 71.600000 Epoch: 24/250
loss_S: 28.897 training accuracy: 72.415000: : 100096it [18:11, 91.72it/s]
Validataion Accuracy: 73.100000 Epoch: 25/250
loss_S: 20.230 training accuracy: 74.574000: : 100096it [16:00, 104.21it/s]
Validataion Accuracy: 76.850000 Epoch: 26/250
loss_S: 19.942 training accuracy: 75.730000: : 100096it [06:01, 276.90it/s]
Validataion Accuracy: 75.825000 Epoch: 27/250
loss_S: 20.148 training accuracy: 76.836000: : 100096it [05:46, 289.02it/s]
Validataion Accuracy: 77.100000 Epoch: 28/250
loss_S: 23.430 training accuracy: 77.084000: : 100096it [05:26, 306.15it/s]
Validataion Accuracy: 78.375000 Epoch: 29/250
loss_S: 19.011 training accuracy: 77.989000: : 100096it [05:32, 301.20it/s]
Validataion Accuracy: 78.600000 Epoch: 30/250
loss_S: 19.189 training accuracy: 78.899000: : 100096it [05:35, 298.40it/s]
Validataion Accuracy: 79.125000
netS, optimizerS, S_losses, iters, start_epoch = loadModel('checkpoint/SSNN/SSNN_checkpoint_epochs_21-30.pt', netS, optimizerS, S_losses)
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=31, end_epoch=40, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 31/250
loss_S: 20.466 training accuracy: 79.977000: : 100096it [05:23, 309.86it/s]
Validataion Accuracy: 80.575000 Epoch: 32/250
loss_S: 16.385 training accuracy: 80.738000: : 100096it [05:26, 306.27it/s]
Validataion Accuracy: 81.025000 Epoch: 33/250
loss_S: 18.797 training accuracy: 81.552000: : 100096it [05:32, 300.89it/s]
Validataion Accuracy: 81.925000 Epoch: 34/250
loss_S: 14.595 training accuracy: 82.427000: : 100096it [05:22, 310.15it/s]
Validataion Accuracy: 81.900000 Epoch: 35/250
loss_S: 15.000 training accuracy: 82.986000: : 100096it [05:22, 310.72it/s]
Validataion Accuracy: 82.350000 Epoch: 36/250
loss_S: 13.506 training accuracy: 83.511000: : 100096it [05:24, 308.73it/s]
Validataion Accuracy: 83.350000 Epoch: 37/250
loss_S: 16.333 training accuracy: 83.902000: : 100096it [05:23, 309.29it/s]
Validataion Accuracy: 83.700000 Epoch: 38/250
loss_S: 13.047 training accuracy: 84.794000: : 100096it [05:22, 310.83it/s]
Validataion Accuracy: 85.350000 Epoch: 39/250
loss_S: 14.344 training accuracy: 85.245000: : 100096it [05:21, 311.05it/s]
Validataion Accuracy: 84.875000 Epoch: 40/250
loss_S: 9.889 training accuracy: 85.805000: : 100096it [05:27, 305.34it/s]
Validataion Accuracy: 85.925000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=41, end_epoch=50, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 41/250
loss_S: 8.989 training accuracy: 86.570000: : 100096it [05:22, 310.17it/s]
Validataion Accuracy: 86.800000 Epoch: 42/250
loss_S: 9.176 training accuracy: 87.240000: : 100096it [05:21, 311.17it/s]
Validataion Accuracy: 87.475000 Epoch: 43/250
loss_S: 10.386 training accuracy: 87.891000: : 100096it [05:21, 310.95it/s]
Validataion Accuracy: 87.625000 Epoch: 44/250
loss_S: 13.173 training accuracy: 88.159000: : 100096it [05:21, 310.86it/s]
Validataion Accuracy: 87.925000 Epoch: 45/250
loss_S: 8.357 training accuracy: 88.391000: : 100096it [05:21, 310.96it/s]
Validataion Accuracy: 87.550000 Epoch: 46/250
loss_S: 9.389 training accuracy: 88.733000: : 100096it [05:23, 309.63it/s]
Validataion Accuracy: 88.950000 Epoch: 47/250
loss_S: 7.717 training accuracy: 88.800000: : 100096it [05:21, 311.07it/s]
Validataion Accuracy: 89.100000 Epoch: 48/250
loss_S: 9.920 training accuracy: 89.258000: : 100096it [06:22, 261.76it/s]
Validataion Accuracy: 89.275000 Epoch: 49/250
loss_S: 7.864 training accuracy: 89.398000: : 100096it [05:24, 308.63it/s]
Validataion Accuracy: 89.775000 Epoch: 50/250
loss_S: 7.658 training accuracy: 89.873000: : 100096it [05:47, 287.80it/s]
Validataion Accuracy: 89.600000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=51, end_epoch=60, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 51/250
loss_S: 11.211 training accuracy: 90.049000: : 100096it [06:50, 244.04it/s]
Validataion Accuracy: 89.475000 Epoch: 52/250
loss_S: 8.369 training accuracy: 90.210000: : 100096it [06:07, 272.62it/s]
Validataion Accuracy: 89.725000 Epoch: 53/250
loss_S: 6.077 training accuracy: 90.503000: : 100096it [05:22, 310.85it/s]
Validataion Accuracy: 89.875000 Epoch: 54/250
loss_S: 7.406 training accuracy: 90.932000: : 100096it [05:24, 308.30it/s]
Validataion Accuracy: 91.600000 Epoch: 55/250
loss_S: 4.744 training accuracy: 91.019000: : 100096it [05:21, 310.91it/s]
Validataion Accuracy: 91.025000 Epoch: 56/250
loss_S: 4.611 training accuracy: 91.048000: : 100096it [05:22, 310.84it/s]
Validataion Accuracy: 91.450000 Epoch: 57/250
loss_S: 4.452 training accuracy: 91.135000: : 100096it [05:21, 311.02it/s]
Validataion Accuracy: 91.175000 Epoch: 58/250
loss_S: 7.368 training accuracy: 91.386000: : 100096it [05:21, 311.02it/s]
Validataion Accuracy: 91.775000 Epoch: 59/250
loss_S: 9.203 training accuracy: 91.564000: : 100096it [05:22, 310.84it/s]
Validataion Accuracy: 91.125000 Epoch: 60/250
loss_S: 6.125 training accuracy: 91.706000: : 100096it [05:23, 309.82it/s]
Validataion Accuracy: 91.925000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=61, end_epoch=70, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 61/250
loss_S: 4.448 training accuracy: 91.628000: : 100096it [05:21, 311.15it/s]
Validataion Accuracy: 91.800000 Epoch: 62/250
loss_S: 5.502 training accuracy: 91.802000: : 100096it [05:21, 311.02it/s]
Validataion Accuracy: 91.600000 Epoch: 63/250
loss_S: 2.770 training accuracy: 92.108000: : 100096it [05:21, 311.14it/s]
Validataion Accuracy: 92.250000 Epoch: 64/250
loss_S: 7.341 training accuracy: 92.367000: : 100096it [05:21, 311.05it/s]
Validataion Accuracy: 92.650000 Epoch: 65/250
loss_S: 4.255 training accuracy: 92.300000: : 100096it [05:21, 310.90it/s]
Validataion Accuracy: 91.950000 Epoch: 66/250
loss_S: 6.474 training accuracy: 92.281000: : 100096it [05:25, 307.69it/s]
Validataion Accuracy: 92.775000 Epoch: 67/250
loss_S: 4.006 training accuracy: 92.253000: : 100096it [05:33, 300.22it/s]
Validataion Accuracy: 92.550000 Epoch: 68/250
loss_S: 6.019 training accuracy: 92.309000: : 100096it [05:23, 309.52it/s]
Validataion Accuracy: 92.025000 Epoch: 69/250
loss_S: 3.988 training accuracy: 92.626000: : 100096it [05:25, 307.33it/s]
Validataion Accuracy: 93.100000 Epoch: 70/250
loss_S: 6.644 training accuracy: 92.541000: : 100096it [05:22, 310.75it/s]
Validataion Accuracy: 91.875000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=71, end_epoch=80, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 71/250
loss_S: 7.824 training accuracy: 92.673000: : 100096it [05:22, 310.69it/s]
Validataion Accuracy: 92.325000 Epoch: 72/250
loss_S: 6.976 training accuracy: 92.817000: : 100096it [05:24, 308.85it/s]
Validataion Accuracy: 93.450000 Epoch: 73/250
loss_S: 1.931 training accuracy: 93.108000: : 100096it [05:22, 310.14it/s]
Validataion Accuracy: 92.900000 Epoch: 74/250
loss_S: 5.358 training accuracy: 93.318000: : 100096it [05:21, 311.07it/s]
Validataion Accuracy: 93.575000 Epoch: 75/250
loss_S: 3.182 training accuracy: 93.234000: : 100096it [05:21, 311.24it/s]
Validataion Accuracy: 93.900000 Epoch: 76/250
loss_S: 4.595 training accuracy: 93.418000: : 100096it [05:26, 306.58it/s]
Validataion Accuracy: 93.950000 Epoch: 77/250
loss_S: 4.234 training accuracy: 93.554000: : 100096it [05:22, 310.76it/s]
Validataion Accuracy: 93.900000 Epoch: 78/250
loss_S: 2.491 training accuracy: 93.640000: : 100096it [05:21, 310.89it/s]
Validataion Accuracy: 93.750000 Epoch: 79/250
loss_S: 6.096 training accuracy: 93.716000: : 100096it [05:21, 310.94it/s]
Validataion Accuracy: 93.075000 Epoch: 80/250
loss_S: 2.570 training accuracy: 93.630000: : 100096it [05:23, 309.05it/s]
Validataion Accuracy: 94.250000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=81, end_epoch=90, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 81/250
loss_S: 2.797 training accuracy: 93.739000: : 100096it [05:23, 309.12it/s]
Validataion Accuracy: 93.700000 Epoch: 82/250
loss_S: 7.786 training accuracy: 93.616000: : 100096it [05:32, 301.42it/s]
Validataion Accuracy: 94.100000 Epoch: 83/250
loss_S: 6.030 training accuracy: 93.718000: : 100096it [05:22, 310.14it/s]
Validataion Accuracy: 93.475000 Epoch: 84/250
loss_S: 3.370 training accuracy: 93.954000: : 100096it [05:21, 311.05it/s]
Validataion Accuracy: 93.700000 Epoch: 85/250
loss_S: 2.720 training accuracy: 94.040000: : 100096it [05:23, 309.84it/s]
Validataion Accuracy: 94.075000 Epoch: 86/250
loss_S: 6.860 training accuracy: 94.284000: : 100096it [05:26, 306.99it/s]
Validataion Accuracy: 94.250000 Epoch: 87/250
loss_S: 5.188 training accuracy: 94.377000: : 100096it [05:21, 310.91it/s]
Validataion Accuracy: 94.500000 Epoch: 88/250
loss_S: 5.750 training accuracy: 94.499000: : 100096it [05:22, 310.12it/s]
Validataion Accuracy: 93.575000 Epoch: 89/250
loss_S: 3.814 training accuracy: 94.409000: : 100096it [05:33, 300.30it/s]
Validataion Accuracy: 94.000000 Epoch: 90/250
loss_S: 7.374 training accuracy: 94.489000: : 100096it [05:47, 288.44it/s]
Validataion Accuracy: 93.850000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=91, end_epoch=100, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 91/250
loss_S: 2.745 training accuracy: 94.632000: : 100096it [05:22, 310.40it/s]
Validataion Accuracy: 93.950000 Epoch: 92/250
loss_S: 4.656 training accuracy: 94.820000: : 100096it [05:22, 310.69it/s]
Validataion Accuracy: 94.750000 Epoch: 93/250
loss_S: 5.718 training accuracy: 94.816000: : 100096it [05:22, 310.63it/s]
Validataion Accuracy: 94.850000 Epoch: 94/250
loss_S: 4.145 training accuracy: 95.007000: : 100096it [05:32, 301.41it/s]
Validataion Accuracy: 94.850000 Epoch: 95/250
loss_S: 4.077 training accuracy: 94.988000: : 100096it [05:25, 307.32it/s]
Validataion Accuracy: 95.300000 Epoch: 96/250
loss_S: 5.456 training accuracy: 95.012000: : 100096it [05:21, 310.93it/s]
Validataion Accuracy: 94.200000 Epoch: 97/250
loss_S: 5.319 training accuracy: 94.933000: : 100096it [05:22, 310.63it/s]
Validataion Accuracy: 95.125000 Epoch: 98/250
loss_S: 4.169 training accuracy: 95.083000: : 100096it [05:21, 310.91it/s]
Validataion Accuracy: 94.975000 Epoch: 99/250
loss_S: 2.486 training accuracy: 95.007000: : 100096it [05:21, 310.89it/s]
Validataion Accuracy: 94.975000 Epoch: 100/250
loss_S: 5.576 training accuracy: 95.168000: : 100096it [05:21, 310.94it/s]
Validataion Accuracy: 95.400000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=101, end_epoch=110, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 101/250
loss_S: 4.328 training accuracy: 95.348000: : 100096it [05:21, 310.89it/s]
Validataion Accuracy: 95.500000 Epoch: 102/250
loss_S: 1.913 training accuracy: 95.422000: : 100096it [05:21, 310.93it/s]
Validataion Accuracy: 95.775000 Epoch: 103/250
loss_S: 1.792 training accuracy: 95.654000: : 100096it [05:25, 307.26it/s]
Validataion Accuracy: 95.525000 Epoch: 104/250
loss_S: 3.846 training accuracy: 95.549000: : 100096it [05:22, 310.76it/s]
Validataion Accuracy: 95.375000 Epoch: 105/250
loss_S: 3.825 training accuracy: 95.359000: : 100096it [05:21, 310.90it/s]
Validataion Accuracy: 94.875000 Epoch: 106/250
loss_S: 5.371 training accuracy: 95.565000: : 100096it [05:21, 311.05it/s]
Validataion Accuracy: 94.800000 Epoch: 107/250
loss_S: 2.231 training accuracy: 95.700000: : 100096it [05:21, 311.02it/s]
Validataion Accuracy: 96.050000 Epoch: 108/250
loss_S: 5.065 training accuracy: 95.709000: : 100096it [05:22, 310.22it/s]
Validataion Accuracy: 95.900000 Epoch: 109/250
loss_S: 2.464 training accuracy: 95.824000: : 100096it [05:23, 309.66it/s]
Validataion Accuracy: 96.075000 Epoch: 110/250
loss_S: 1.250 training accuracy: 95.645000: : 100096it [06:31, 255.46it/s]
Validataion Accuracy: 95.825000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=111, end_epoch=120, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 111/250
loss_S: 0.738 training accuracy: 95.602000: : 100096it [05:21, 310.96it/s]
Validataion Accuracy: 95.375000 Epoch: 112/250
loss_S: 2.276 training accuracy: 95.387000: : 100096it [05:22, 310.29it/s]
Validataion Accuracy: 94.975000 Epoch: 113/250
loss_S: 3.202 training accuracy: 95.449000: : 100096it [05:21, 311.06it/s]
Validataion Accuracy: 95.650000 Epoch: 114/250
loss_S: 6.355 training accuracy: 95.477000: : 100096it [05:21, 310.97it/s]
Validataion Accuracy: 95.225000 Epoch: 115/250
loss_S: 3.618 training accuracy: 95.556000: : 100096it [05:21, 310.92it/s]
Validataion Accuracy: 95.075000 Epoch: 116/250
loss_S: 2.336 training accuracy: 95.769000: : 100096it [05:21, 310.89it/s]
Validataion Accuracy: 96.575000 Epoch: 117/250
loss_S: 2.382 training accuracy: 95.880000: : 100096it [05:22, 310.86it/s]
Validataion Accuracy: 95.725000 Epoch: 118/250
loss_S: 6.046 training accuracy: 95.888000: : 100096it [05:30, 303.08it/s]
Validataion Accuracy: 96.725000 Epoch: 119/250
loss_S: 1.875 training accuracy: 96.095000: : 100096it [05:27, 305.35it/s]
Validataion Accuracy: 95.425000 Epoch: 120/250
loss_S: 3.122 training accuracy: 95.976000: : 100096it [05:28, 304.75it/s]
Validataion Accuracy: 96.250000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=121, end_epoch=130, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 121/250
loss_S: 4.684 training accuracy: 95.948000: : 100096it [05:41, 292.76it/s]
Validataion Accuracy: 95.425000 Epoch: 122/250
loss_S: 2.893 training accuracy: 95.970000: : 100096it [05:29, 304.06it/s]
Validataion Accuracy: 96.125000 Epoch: 123/250
loss_S: 1.786 training accuracy: 96.032000: : 100096it [06:25, 259.62it/s]
Validataion Accuracy: 96.525000 Epoch: 124/250
loss_S: 3.944 training accuracy: 96.021000: : 100096it [05:22, 310.17it/s]
Validataion Accuracy: 95.500000 Epoch: 125/250
loss_S: 4.673 training accuracy: 95.996000: : 100096it [05:21, 310.90it/s]
Validataion Accuracy: 95.725000 Epoch: 126/250
loss_S: 0.707 training accuracy: 96.158000: : 100096it [05:22, 310.82it/s]
Validataion Accuracy: 95.325000 Epoch: 127/250
loss_S: 2.850 training accuracy: 96.115000: : 100096it [05:21, 310.97it/s]
Validataion Accuracy: 96.350000 Epoch: 128/250
loss_S: 2.002 training accuracy: 96.038000: : 100096it [05:22, 310.79it/s]
Validataion Accuracy: 95.575000 Epoch: 129/250
loss_S: 2.544 training accuracy: 96.134000: : 100096it [05:21, 310.97it/s]
Validataion Accuracy: 95.900000 Epoch: 130/250
loss_S: 3.195 training accuracy: 96.098000: : 100096it [05:38, 295.42it/s]
Validataion Accuracy: 95.575000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=131, end_epoch=140, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 131/250
loss_S: 2.217 training accuracy: 95.955000: : 100096it [05:25, 307.15it/s]
Validataion Accuracy: 96.100000 Epoch: 132/250
loss_S: 1.392 training accuracy: 95.998000: : 100096it [05:25, 307.48it/s]
Validataion Accuracy: 96.500000 Epoch: 133/250
loss_S: 3.080 training accuracy: 96.078000: : 100096it [05:36, 297.28it/s]
Validataion Accuracy: 95.600000 Epoch: 134/250
loss_S: 1.985 training accuracy: 95.941000: : 100096it [05:24, 308.88it/s]
Validataion Accuracy: 96.475000 Epoch: 135/250
loss_S: 2.298 training accuracy: 96.180000: : 100096it [05:22, 310.12it/s]
Validataion Accuracy: 95.575000 Epoch: 136/250
loss_S: 4.037 training accuracy: 96.230000: : 100096it [06:06, 272.77it/s]
Validataion Accuracy: 95.925000 Epoch: 137/250
loss_S: 0.788 training accuracy: 96.064000: : 100096it [05:51, 284.47it/s]
Validataion Accuracy: 96.450000 Epoch: 138/250
loss_S: 1.454 training accuracy: 96.198000: : 100096it [05:22, 310.01it/s]
Validataion Accuracy: 96.150000 Epoch: 139/250
loss_S: 4.141 training accuracy: 96.080000: : 100096it [05:27, 306.03it/s]
Validataion Accuracy: 96.200000 Epoch: 140/250
loss_S: 2.433 training accuracy: 96.141000: : 100096it [05:21, 310.91it/s]
Validataion Accuracy: 96.200000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=141, end_epoch=150, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 141/250
loss_S: 2.519 training accuracy: 96.065000: : 100096it [05:23, 309.20it/s]
Validataion Accuracy: 95.500000 Epoch: 142/250
loss_S: 2.500 training accuracy: 95.995000: : 100096it [05:22, 310.82it/s]
Validataion Accuracy: 96.375000 Epoch: 143/250
loss_S: 3.032 training accuracy: 96.001000: : 100096it [05:23, 309.49it/s]
Validataion Accuracy: 95.550000 Epoch: 144/250
loss_S: 3.890 training accuracy: 96.013000: : 100096it [05:22, 310.80it/s]
Validataion Accuracy: 95.700000 Epoch: 145/250
loss_S: 3.750 training accuracy: 96.060000: : 100096it [05:22, 310.79it/s]
Validataion Accuracy: 95.950000 Epoch: 146/250
loss_S: 4.160 training accuracy: 95.989000: : 100096it [05:24, 308.90it/s]
Validataion Accuracy: 95.475000 Epoch: 147/250
loss_S: 3.376 training accuracy: 96.003000: : 100096it [05:22, 310.56it/s]
Validataion Accuracy: 96.075000 Epoch: 148/250
loss_S: 2.500 training accuracy: 96.038000: : 100096it [05:21, 310.93it/s]
Validataion Accuracy: 96.025000 Epoch: 149/250
loss_S: 2.462 training accuracy: 96.059000: : 100096it [05:21, 310.93it/s]
Validataion Accuracy: 96.275000 Epoch: 150/250
loss_S: 2.330 training accuracy: 96.052000: : 100096it [05:32, 300.80it/s]
Validataion Accuracy: 95.200000
# Reduce the Learning Rate
slr = 0.0000002
# Setup Adam optimizers for S
optimizerS = optim.Adam(netS.parameters(), lr=slr, betas=(beta1, 0.999))
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=151, end_epoch=160, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 151/250
loss_S: 3.623 training accuracy: 96.081000: : 100096it [05:21, 310.88it/s]
Validataion Accuracy: 96.300000 Epoch: 152/250
loss_S: 2.179 training accuracy: 96.096000: : 100096it [05:23, 308.95it/s]
Validataion Accuracy: 95.975000 Epoch: 153/250
loss_S: 1.652 training accuracy: 96.088000: : 100096it [05:26, 306.29it/s]
Validataion Accuracy: 96.000000 Epoch: 154/250
loss_S: 1.875 training accuracy: 96.103000: : 100096it [06:10, 270.26it/s]
Validataion Accuracy: 96.575000 Epoch: 155/250
loss_S: 6.045 training accuracy: 96.041000: : 100096it [05:26, 306.67it/s]
Validataion Accuracy: 95.750000 Epoch: 156/250
loss_S: 4.152 training accuracy: 96.095000: : 100096it [05:22, 310.51it/s]
Validataion Accuracy: 96.300000 Epoch: 157/250
loss_S: 2.683 training accuracy: 96.237000: : 100096it [05:22, 310.75it/s]
Validataion Accuracy: 96.425000 Epoch: 158/250
loss_S: 0.625 training accuracy: 96.229000: : 100096it [05:23, 309.50it/s]
Validataion Accuracy: 95.975000 Epoch: 159/250
loss_S: 4.601 training accuracy: 96.231000: : 100096it [05:22, 310.61it/s]
Validataion Accuracy: 96.100000 Epoch: 160/250
loss_S: 1.405 training accuracy: 96.233000: : 100096it [05:22, 310.57it/s]
Validataion Accuracy: 96.050000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=161, end_epoch=170, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 161/250
loss_S: 3.125 training accuracy: 96.210000: : 100096it [05:23, 309.12it/s]
Validataion Accuracy: 96.350000 Epoch: 162/250
loss_S: 5.084 training accuracy: 96.204000: : 100096it [05:23, 309.26it/s]
Validataion Accuracy: 95.875000 Epoch: 163/250
loss_S: 2.636 training accuracy: 96.256000: : 100096it [05:23, 309.74it/s]
Validataion Accuracy: 95.925000 Epoch: 164/250
loss_S: 3.753 training accuracy: 96.386000: : 100096it [05:24, 308.73it/s]
Validataion Accuracy: 95.925000 Epoch: 165/250
loss_S: 5.040 training accuracy: 96.223000: : 100096it [05:22, 310.49it/s]
Validataion Accuracy: 96.200000 Epoch: 166/250
loss_S: 3.477 training accuracy: 96.385000: : 100096it [05:22, 310.61it/s]
Validataion Accuracy: 96.350000 Epoch: 167/250
loss_S: 2.853 training accuracy: 96.388000: : 100096it [05:22, 310.43it/s]
Validataion Accuracy: 96.425000 Epoch: 168/250
loss_S: 1.262 training accuracy: 96.353000: : 100096it [05:21, 310.96it/s]
Validataion Accuracy: 96.550000 Epoch: 169/250
loss_S: 2.786 training accuracy: 96.428000: : 100096it [05:24, 308.40it/s]
Validataion Accuracy: 96.775000 Epoch: 170/250
loss_S: 3.062 training accuracy: 96.354000: : 100096it [05:24, 308.21it/s]
Validataion Accuracy: 96.000000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=171, end_epoch=180, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 171/250
loss_S: 2.176 training accuracy: 96.476000: : 100096it [07:19, 227.52it/s]
Validataion Accuracy: 96.700000 Epoch: 172/250
loss_S: 4.499 training accuracy: 96.357000: : 100096it [05:22, 310.57it/s]
Validataion Accuracy: 96.750000 Epoch: 173/250
loss_S: 3.176 training accuracy: 96.542000: : 100096it [05:22, 310.32it/s]
Validataion Accuracy: 96.000000 Epoch: 174/250
loss_S: 1.932 training accuracy: 96.430000: : 100096it [05:22, 310.54it/s]
Validataion Accuracy: 96.375000 Epoch: 175/250
loss_S: 1.855 training accuracy: 96.511000: : 100096it [05:22, 310.71it/s]
Validataion Accuracy: 96.400000 Epoch: 176/250
loss_S: 2.302 training accuracy: 96.469000: : 100096it [05:30, 302.86it/s]
Validataion Accuracy: 96.675000 Epoch: 177/250
loss_S: 3.609 training accuracy: 96.447000: : 100096it [05:22, 310.65it/s]
Validataion Accuracy: 96.500000 Epoch: 178/250
loss_S: 2.708 training accuracy: 96.484000: : 100096it [05:22, 310.43it/s]
Validataion Accuracy: 96.575000 Epoch: 179/250
loss_S: 2.037 training accuracy: 96.599000: : 100096it [05:22, 310.65it/s]
Validataion Accuracy: 96.350000 Epoch: 180/250
loss_S: 3.557 training accuracy: 96.413000: : 100096it [05:22, 310.81it/s]
Validataion Accuracy: 96.700000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=181, end_epoch=190, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 181/250
loss_S: 0.891 training accuracy: 96.557000: : 100096it [05:21, 310.88it/s]
Validataion Accuracy: 96.250000 Epoch: 182/250
loss_S: 4.375 training accuracy: 96.504000: : 100096it [05:21, 310.88it/s]
Validataion Accuracy: 97.075000 Epoch: 183/250
loss_S: 0.820 training accuracy: 96.518000: : 100096it [05:21, 310.99it/s]
Validataion Accuracy: 96.725000 Epoch: 184/250
loss_S: 2.291 training accuracy: 96.545000: : 100096it [05:22, 310.51it/s]
Validataion Accuracy: 96.075000 Epoch: 185/250
loss_S: 0.688 training accuracy: 96.528000: : 100096it [05:23, 309.57it/s]
Validataion Accuracy: 96.625000 Epoch: 186/250
loss_S: 1.848 training accuracy: 96.662000: : 100096it [05:22, 310.63it/s]
Validataion Accuracy: 96.325000 Epoch: 187/250
loss_S: 2.229 training accuracy: 96.610000: : 100096it [05:23, 309.01it/s]
Validataion Accuracy: 96.525000 Epoch: 188/250
loss_S: 3.017 training accuracy: 96.489000: : 100096it [05:22, 310.74it/s]
Validataion Accuracy: 96.575000 Epoch: 189/250
loss_S: 4.445 training accuracy: 96.540000: : 100096it [05:22, 310.86it/s]
Validataion Accuracy: 96.525000 Epoch: 190/250
loss_S: 2.832 training accuracy: 96.513000: : 100096it [05:22, 310.75it/s]
Validataion Accuracy: 96.300000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=191, end_epoch=200, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 191/250
loss_S: 1.302 training accuracy: 96.585000: : 100096it [05:22, 310.75it/s]
Validataion Accuracy: 97.200000 Epoch: 192/250
loss_S: 1.986 training accuracy: 96.670000: : 100096it [05:28, 304.66it/s]
Validataion Accuracy: 96.600000 Epoch: 193/250
loss_S: 4.395 training accuracy: 96.578000: : 100096it [05:22, 310.85it/s]
Validataion Accuracy: 96.450000 Epoch: 194/250
loss_S: 2.502 training accuracy: 96.588000: : 100096it [05:25, 307.60it/s]
Validataion Accuracy: 97.225000 Epoch: 195/250
loss_S: 3.510 training accuracy: 96.605000: : 100096it [05:27, 305.18it/s]
Validataion Accuracy: 96.475000 Epoch: 196/250
loss_S: 4.307 training accuracy: 96.482000: : 100096it [05:21, 310.89it/s]
Validataion Accuracy: 96.000000 Epoch: 197/250
loss_S: 1.981 training accuracy: 96.596000: : 100096it [05:21, 311.04it/s]
Validataion Accuracy: 96.800000 Epoch: 198/250
loss_S: 1.430 training accuracy: 96.674000: : 100096it [05:23, 309.72it/s]
Validataion Accuracy: 97.150000 Epoch: 199/250
loss_S: 0.970 training accuracy: 96.563000: : 100096it [05:22, 310.85it/s]
Validataion Accuracy: 96.700000 Epoch: 200/250
loss_S: 1.902 training accuracy: 96.638000: : 100096it [05:24, 308.09it/s]
Validataion Accuracy: 96.325000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=201, end_epoch=210, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 201/250
loss_S: 2.540 training accuracy: 96.707000: : 100096it [05:30, 303.11it/s]
Validataion Accuracy: 97.025000 Epoch: 202/250
loss_S: 1.892 training accuracy: 96.589000: : 100096it [05:38, 295.97it/s]
Validataion Accuracy: 96.800000 Epoch: 203/250
loss_S: 3.864 training accuracy: 96.712000: : 100096it [05:21, 310.99it/s]
Validataion Accuracy: 96.650000 Epoch: 204/250
loss_S: 2.564 training accuracy: 96.657000: : 100096it [05:29, 304.15it/s]
Validataion Accuracy: 96.500000 Epoch: 205/250
loss_S: 2.465 training accuracy: 96.730000: : 100096it [05:30, 303.13it/s]
Validataion Accuracy: 96.275000 Epoch: 206/250
loss_S: 0.616 training accuracy: 96.739000: : 100096it [05:23, 309.08it/s]
Validataion Accuracy: 96.800000 Epoch: 207/250
loss_S: 3.771 training accuracy: 96.564000: : 100096it [05:23, 309.42it/s]
Validataion Accuracy: 96.525000 Epoch: 208/250
loss_S: 6.250 training accuracy: 96.736000: : 100096it [06:34, 253.58it/s]
Validataion Accuracy: 96.475000 Epoch: 209/250
loss_S: 2.413 training accuracy: 96.548000: : 100096it [06:10, 270.41it/s]
Validataion Accuracy: 95.925000 Epoch: 210/250
loss_S: 3.142 training accuracy: 96.732000: : 100096it [05:25, 307.92it/s]
Validataion Accuracy: 96.250000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=211, end_epoch=220, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 211/250
loss_S: 0.650 training accuracy: 96.663000: : 100096it [05:22, 310.81it/s]
Validataion Accuracy: 96.775000 Epoch: 212/250
loss_S: 3.137 training accuracy: 96.823000: : 100096it [05:22, 310.81it/s]
Validataion Accuracy: 96.500000 Epoch: 213/250
loss_S: 1.610 training accuracy: 96.681000: : 100096it [05:26, 306.28it/s]
Validataion Accuracy: 96.425000 Epoch: 214/250
loss_S: 3.127 training accuracy: 96.657000: : 100096it [05:22, 310.73it/s]
Validataion Accuracy: 96.950000 Epoch: 215/250
loss_S: 3.303 training accuracy: 96.755000: : 100096it [05:41, 292.77it/s]
Validataion Accuracy: 96.625000 Epoch: 216/250
loss_S: 0.213 training accuracy: 96.723000: : 100096it [05:34, 299.01it/s]
Validataion Accuracy: 96.850000 Epoch: 217/250
loss_S: 2.888 training accuracy: 96.754000: : 100096it [05:28, 305.17it/s]
Validataion Accuracy: 95.975000 Epoch: 218/250
loss_S: 2.355 training accuracy: 96.785000: : 100096it [05:31, 302.33it/s]
Validataion Accuracy: 96.425000 Epoch: 219/250
loss_S: 2.489 training accuracy: 96.756000: : 100096it [05:40, 293.74it/s]
Validataion Accuracy: 96.175000 Epoch: 220/250
loss_S: 2.498 training accuracy: 96.664000: : 100096it [05:23, 309.60it/s]
Validataion Accuracy: 96.275000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=221, end_epoch=230, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 221/250
loss_S: 1.440 training accuracy: 96.703000: : 100096it [05:28, 304.94it/s]
Validataion Accuracy: 96.600000 Epoch: 222/250
loss_S: 0.245 training accuracy: 96.721000: : 100096it [06:09, 271.16it/s]
Validataion Accuracy: 96.575000 Epoch: 223/250
loss_S: 2.164 training accuracy: 96.814000: : 100096it [05:22, 310.24it/s]
Validataion Accuracy: 97.025000 Epoch: 224/250
loss_S: 1.608 training accuracy: 96.743000: : 100096it [05:30, 302.46it/s]
Validataion Accuracy: 96.725000 Epoch: 225/250
loss_S: 0.709 training accuracy: 96.796000: : 100096it [05:32, 300.67it/s]
Validataion Accuracy: 96.600000 Epoch: 226/250
loss_S: 2.949 training accuracy: 96.867000: : 100096it [05:22, 310.76it/s]
Validataion Accuracy: 96.500000 Epoch: 227/250
loss_S: 2.381 training accuracy: 96.748000: : 100096it [05:30, 303.08it/s]
Validataion Accuracy: 96.950000 Epoch: 228/250
loss_S: 1.991 training accuracy: 96.764000: : 100096it [05:26, 306.50it/s]
Validataion Accuracy: 96.850000 Epoch: 229/250
loss_S: 2.421 training accuracy: 96.802000: : 100096it [05:27, 305.79it/s]
Validataion Accuracy: 96.850000 Epoch: 230/250
loss_S: 2.679 training accuracy: 96.734000: : 100096it [05:30, 302.91it/s]
Validataion Accuracy: 96.325000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=231, end_epoch=240, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 231/250
loss_S: 3.614 training accuracy: 96.764000: : 100096it [05:28, 305.16it/s]
Validataion Accuracy: 96.350000 Epoch: 232/250
loss_S: 3.228 training accuracy: 96.793000: : 100096it [05:29, 303.37it/s]
Validataion Accuracy: 96.600000 Epoch: 233/250
loss_S: 0.843 training accuracy: 96.768000: : 100096it [06:02, 275.81it/s]
Validataion Accuracy: 96.675000 Epoch: 234/250
loss_S: 2.556 training accuracy: 96.827000: : 100096it [05:33, 300.09it/s]
Validataion Accuracy: 96.900000 Epoch: 235/250
loss_S: 3.384 training accuracy: 96.885000: : 100096it [07:07, 234.26it/s]
Validataion Accuracy: 96.575000 Epoch: 236/250
loss_S: 5.000 training accuracy: 96.838000: : 100096it [05:37, 296.28it/s]
Validataion Accuracy: 96.675000 Epoch: 237/250
loss_S: 2.636 training accuracy: 96.861000: : 100096it [07:41, 216.91it/s]
Validataion Accuracy: 96.450000 Epoch: 238/250
loss_S: 5.229 training accuracy: 96.836000: : 100096it [05:35, 298.78it/s]
Validataion Accuracy: 96.725000 Epoch: 239/250
loss_S: 2.117 training accuracy: 96.851000: : 100096it [05:26, 306.40it/s]
Validataion Accuracy: 97.375000 Epoch: 240/250
loss_S: 2.186 training accuracy: 96.934000: : 100096it [05:24, 308.39it/s]
Validataion Accuracy: 96.875000
S_losses, iters = train(netS, num_train, num_valid, train_loader, valid_loader, device, S_losses=S_losses, num_epochs=num_epochs, start_epoch=241, end_epoch=250, iters=iters)
[*] Train on 100000 sample pairs, validate on 4000 sample pairs Epoch: 241/250
loss_S: 1.502 training accuracy: 96.817000: : 100096it [05:42, 292.28it/s]
Validataion Accuracy: 97.200000 Epoch: 242/250
loss_S: 3.145 training accuracy: 96.901000: : 100096it [05:31, 301.54it/s]
Validataion Accuracy: 96.900000 Epoch: 243/250
loss_S: 2.276 training accuracy: 96.874000: : 100096it [05:23, 308.94it/s]
Validataion Accuracy: 96.750000 Epoch: 244/250
loss_S: 1.991 training accuracy: 96.900000: : 100096it [05:36, 297.87it/s]
Validataion Accuracy: 96.775000 Epoch: 245/250
loss_S: 3.543 training accuracy: 96.825000: : 100096it [05:36, 297.79it/s]
Validataion Accuracy: 96.575000 Epoch: 246/250
loss_S: 1.417 training accuracy: 96.902000: : 100096it [05:23, 309.05it/s]
Validataion Accuracy: 96.725000 Epoch: 247/250
loss_S: 2.974 training accuracy: 96.822000: : 100096it [05:25, 307.07it/s]
Validataion Accuracy: 97.000000 Epoch: 248/250
loss_S: 1.468 training accuracy: 96.938000: : 100096it [05:23, 309.47it/s]
Validataion Accuracy: 96.575000 Epoch: 249/250
loss_S: 0.928 training accuracy: 97.001000: : 100096it [05:22, 310.63it/s]
Validataion Accuracy: 96.775000 Epoch: 250/250
loss_S: 2.449 training accuracy: 96.893000: : 100096it [05:36, 297.09it/s]
Validataion Accuracy: 96.900000
saveCkpt(model_results_file, num_epochs, netS, optimizerS, S_losses, iters)
def plotTrainingLoss(S_losses):
plt.figure(figsize=(10,5))
plt.title("Siamese Neural Network Training Loss")
plt.plot(S_losses,label="Siamese NN Loss")
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()
plotTrainingLoss(S_losses)
Below is plotted 8 pairs of fingerprints. Below each pair of fingerprints, the model will gives its prediction of whether each pair are of the same fingerprint or not. Below that is listed the ground truth.
def printLabels(labels):
c = 0
for l in labels:
if l == 1:
print(" same ", end="")
else:
print(" diff ", end="")
if c % 4 == 0:
print(" ", end="")
c += 1
print("\n")
def test(netS, loader, device):
# Validate
netS.eval()
validation_accuracy = 0.0
num_valid_correct = 0
total_valid = 0
for i, (x1, x2, y) in enumerate(loader):
x1, x2, y = x1.to(device), x2.to(device), y.to(device)
output = netS(x1, x2).view(-1)
y = y.view(-1)
for i in range(len(output)):
label = 0.0
if output[i] > 0.5:
label = 1.0
if label == y[i]:
num_valid_correct += 1
total_valid += 1
validation_accuracy = num_valid_correct / total_valid * 100
print("Matching Accuracy over Test Dataset: {:.2f}%".format(validation_accuracy))
def showTestPerformance(netS, test_loader, device):
batch = next(iter(test_loader))
labels = batch[2][:8]
# Let model make predictions
netS.eval()
output = netS(batch[0].to(device)[:8], batch[1].to(device)[:8]).view(-1)
# Display the Sample Images
plt.figure(figsize=(20,6))
plt.subplot(2,1,1)
plt.axis("off")
plt.imshow(np.transpose(vutils.make_grid(batch[0].to(device)[:8], padding=5, normalize=True).cpu(),(1,2,0)))
plt.subplot(2,1,2)
plt.axis("off")
plt.imshow(np.transpose(vutils.make_grid(batch[1].to(device)[:8], padding=5, normalize=True).cpu(),(1,2,0)))
plt.show()
# Display Model Performance
preds = [0 if x < 0.5 else 1 for x in output]
print("Pred: ")
printLabels(preds)
print("Truth:")
printLabels(labels)
test(netS, test_loader, device)
showTestPerformance(netS, test_loader, device)
Pred:
diff diff diff diff diff same diff same
Truth:
diff diff diff diff diff same diff same
Matching Accuracy over Test Dataset: 97.08%
Better performance of the Fingerprint Siamese Neural Network was achieved by increasing the number of channels per layer. It was able to achieve a Testing Accuracy of 97%, and it was able to consistenly achieve a validateion accuracy of over 96% for the last 80 epochs of training. Although the model had to be trained for much longer than the previous version, the increased size of the network seemed to help avoid overfitting since the validation accuracy was consistenly similar to that of the training accuracy. In addition, the model achieved a testing accuracy that was higher than the training accuracy from the previous epoch, so it was able to generalize the information it learned from training.
One limitation of this model is that it may have been able to exploit some artifact found in the synthetically generated fingerprints. Only testing this model on a dataset of real fingerprints would tell for sure though.