Hello,
I am working on a face recognition project using DL4J Core 1.0.0-M2.1 Facenetnn4small2. Despite progress, I am facing accuracy challenges, and my knowledge in transfer learning and pretrained models such as Tensorflow facenet.h5 model and weights is limited.
Kindly look at the code I have provided and offer me your guidance on enhancing accuracy, especially given our need to train and verify on limited dataset just like face unlock does with smart phones.
I have provided code for training Facenetnn4small2 model (Part 1) and for running face recognition(Part 2).
Training Model Part 1
package digitalattendance;
import org.deeplearning4j.zoo.ZooModel;
import org.deeplearning4j.zoo.model.FaceNetNN4Small2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.logging.Level;
import org.datavec.api.io.filters.BalancedPathFilter;
import org.datavec.api.io.labels.ParentPathLabelGenerator;
import org.datavec.api.split.FileSplit;
import org.datavec.api.split.InputSplit;
import org.datavec.image.loader.NativeImageLoader;
import org.datavec.image.recordreader.ImageRecordReader;
import org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator;
import org.deeplearning4j.nn.conf.*;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.deeplearning4j.optimize.listeners.ScoreIterationListener;
import org.deeplearning4j.util.ModelSerializer;
import org.nd4j.evaluation.classification.Evaluation;
import org.nd4j.linalg.dataset.api.iterator.DataSetIterator;
import org.nd4j.linalg.dataset.api.preprocessor.DataNormalization;
import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
-
@author AugustineBeilel
*/
public class FaceNetSerialiser {private static final Logger logger = LoggerFactory.getLogger(FaceNetSerialiser.class);
private long seed = 1234;
CacheMode cacheMode = CacheMode.NONE;
static int nEpochs = 10, transformedDataEpochs = 5;
Random randNumGen = new Random(seed);
File mainPath = new File(“D:\2Citt\Parliament\Dataset”);
//File CnnModelPath = new File(“C:\TrackSMART\FaceNetModel” + “.zip”);
File CnnModelPath = new File(“D:\2Citt\Parliament” + “.zip”);int batchSize = 54; // Test batch size ( number of samples that will be propagated through the network in each iteration )54
public void FaceNetNN4Small2() throws IOException {
int height = 96;
int width = 96;FileSplit filesInDir = new FileSplit(mainPath, NativeImageLoader.ALLOWED_FORMATS, randNumGen); int numClasses = filesInDir.getRootDir().listFiles(File::isDirectory).length; //This only works if your root is clean: only label subdirs. //creating Face Labels txt file logger.info("\n\n creating Face Labels.txt file"); File file = new File("C:\\TrackSMART\\Face Labels" + ".txt"); try ( PrintWriter writer = new PrintWriter(file)) { for (int i = 0; i < numClasses; i++) { String folderName = filesInDir.getRootDir().listFiles(File::isDirectory)[i].getName(); writer.println(folderName + "," + i); } } catch (FileNotFoundException e) { e.printStackTrace(); } // vectorization of train data ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator(); BalancedPathFilter pathFilter = new BalancedPathFilter(randNumGen, NativeImageLoader.ALLOWED_FORMATS, labelMaker); //Split the image files into train and test. Specify the train test split as 80%,20% InputSplit[] filesInDirSplit = filesInDir.sample(pathFilter, 80, 20); InputSplit trainData = filesInDirSplit[0]; InputSplit testData = filesInDirSplit[1]; //The testData is never used in the example, commenting out. // vectorization of train data logger.info("\n\n vectorization of train data"); ImageRecordReader trainRR = new ImageRecordReader(height, width, 3, labelMaker); try { trainRR.initialize(trainData); } catch (IOException ex) { java.util.logging.Logger.getLogger(FaceNetSerialiser.class.getName()).log(Level.SEVERE, null, ex); } DataSetIterator trainIter = new RecordReaderDataSetIterator(trainRR, batchSize, 1, numClasses); // pixel values from 0-255 to 0-1 (min-max scaling) logger.info("\n\nTrain Data Normalistion (pixel values from 0-255 to 0-1 (min-max scaling))"); DataNormalization imageScaler = new ImagePreProcessingScaler(0, 1); imageScaler.fit(trainIter); trainIter.setPreProcessor(imageScaler); // vectorization of test data logger.info("\n\n vectorization of test data"); ImageRecordReader testRR = new ImageRecordReader(height, width, 3, labelMaker); try { testRR.initialize(testData); } catch (IOException ex) { java.util.logging.Logger.getLogger(FaceNetSerialiser.class.getName()).log(Level.SEVERE, null, ex); } DataSetIterator testIter = new RecordReaderDataSetIterator(testRR, batchSize, 1, numClasses); logger.info("\n\nTest Data Normalistion (pixel values from 0-255 to 0-1 (min-max scaling))"); testIter.setPreProcessor(imageScaler); // same normalization for better results logger.info("Multi Layer Neural Network configuration and training...");
////Neural Network Architecture
ZooModel zooModel = FaceNetNN4Small2.builder()
.numClasses(numClasses)
// .seed(seed)
.build();
ComputationGraph model = ((FaceNetNN4Small2) zooModel).init();
model.setListeners(new ScoreIterationListener(10));
logger.info(“\n\nTotal num of params: {}” + model.numParams());
// evaluation while training (the score should go down)
logger.info(“Training with original data”);
for (int i = 0; i < nEpochs; i++) {
model.fit(trainIter);
logger.info(“\n\nCompleted epoch {} " + i);
Evaluation eval = model.evaluate(testIter);
logger.info(”\n\n" + eval.stats());
trainIter.reset();
testIter.reset();
try {
ModelSerializer.writeModel(model, CnnModelPath, true);
} catch (IOException ex) {
java.util.logging.Logger.getLogger(FaceNetSerialiser.class.getName()).log(Level.SEVERE, null, ex);
}
logger.info("\n\nMultiLayer Neural Network model has been saved in {} " + CnnModelPath.getPath());
}
}public static void main(String args) throws IOException {
FaceNetSerialiser fc = new FaceNetSerialiser();
fc.FaceNetNN4Small2();
}
}
Running Face recognition Part 2
//Use the nativeImageLoader to convert to numerical matrix // Load the image and convert it to a 4D array
NativeImageLoader loader = new NativeImageLoader(height, width, channels);
INDArray testimage = loader.asMatrix(croppedImage);
DataNormalization scalar = new ImagePreProcessingScaler(0, 1);
//then call that scalar on the image dataset
scalar.transform(testimage);
INDArray embeddings = null;
try {
// Pass the input through the model to get the predictions
embeddings = model.output(testimage);
} catch (RuntimeException e) {
// NotificationManager.getInstance().fireNotification(Notification.Type.INFO, Notification.Location.CENTER, “Stopped Reading from the model”);
}
Map<Integer, String> labelMap = new HashMap<>();
File file = new File("C:\\TrackSMART\\Face Labels.txt");
if (file.exists()) {
try ( BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
if (line.trim().isEmpty()) {
continue; // skip empty lines
}
String[] parts = line.split(",");
if (parts.length >= 2) {
labelMap.put(Integer.parseInt(parts[1].trim()), parts[0].trim());
} else {
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
}
int maxIdx = -1;
double maxVal3 = Double.MIN_VALUE;
double threshold = 0.997;
boolean validPrediction = false;
if (embeddings != null) {
for (int k = 0; k < embeddings[0].size(1); k++) {
double val = embeddings[0].getDouble(0, k);
if (val > threshold) {
validPrediction = true;
if (val > maxVal3) {
maxVal3 = val;
maxIdx = k;
threshold = val;
// System.out.println("Threshold value of the predicted label: " + threshold);
}
}
}
} else {
}
if (validPrediction) {
StudentNumber = labelMap.get(maxIdx);
} else {
// handle case where no valid predictions were found
}