mv_machine_learning: change feature vector manager for face recognition
authorInki Dae <inki.dae@samsung.com>
Mon, 18 Dec 2023 07:58:42 +0000 (16:58 +0900)
committerKwanghoon Son <k.son@samsung.com>
Wed, 27 Dec 2023 03:22:49 +0000 (12:22 +0900)
[Issue type] : code enhancement

Change feature vector manager including some code cleanups for face recognition
task group.

With this patch, the header data of the feature vector is now stored at the
beginning of the feature vector file, while the feature vector data is stored
at the end of the file. This change makes it easier to manage feature vectors
without having to worry about moving the file pointer.
In the previous version, the header data was stored at the end of the file,
and the feature vector data was stored at the beginning of the file.

Additionally, this patch skips an unnecessary process in the deleteLabel
function and cleans up the existing code.

Change-Id: I9ef2c0f5603788ea1907002bacf25d9f4fba68ed
Signed-off-by: Inki Dae <inki.dae@samsung.com>
mv_machine_learning/face_recognition/include/face_recognition_dsm.h
mv_machine_learning/face_recognition/include/face_recognition_fvm.h
mv_machine_learning/face_recognition/src/face_recognition.cpp
mv_machine_learning/face_recognition/src/face_recognition_dsm.cpp
mv_machine_learning/face_recognition/src/face_recognition_fvm.cpp
mv_machine_learning/training/include/feature_vector_manager.h

index 844d1c3..3aaca9c 100644 (file)
@@ -26,7 +26,7 @@ class FaceRecognitionDSM : public DataSetManager
 {
 private:
        void printHeader(FeaVecHeader &fvh);
-       bool isHeaderValid(const FeaVecHeader &fvh, size_t max_size);
+       bool isHeaderValid(const FeaVecHeader &fvh);
 
 public:
        FaceRecognitionDSM();
index a46b9b1..1b4cfdc 100644 (file)
@@ -29,7 +29,7 @@ public:
        FaceRecognitionFVM(const std::string feature_vector_file = "feature_vector_file.dat");
        ~FaceRecognitionFVM() = default;
 
-       void writeHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt) override;
+       void updateHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt) override;
        void storeData(std::vector<std::vector<float> > &features_vec, std::vector<unsigned int> &label_index) override;
        void remove() override;
 };
index ab59014..19ac61a 100644 (file)
@@ -75,15 +75,15 @@ void FaceRecognition::storeDataSet(unique_ptr<DataSetManager> &data_set, unsigne
                // Make sure feature vector file.
                checkFeatureVectorFile(fvm->getFileName(), fvm_new->getFileName());
 
-               // 1. Write feature vector and it's label index.
-               fvm_new->storeData(data_set->getData(), data_set->getLabelIdx());
+               // Write feature vector header.
+               fvm_new->updateHeader(data_set->getFeaVecSize(), label_cnt, data_set->getData().size());
 
-               // 2. Write feature vector header.
-               fvm_new->writeHeader(data_set->getFeaVecSize(), label_cnt, data_set->getData().size());
+               // Write feature vector and it's label index.
+               fvm_new->storeData(data_set->getData(), data_set->getLabelIdx());
 
                int ret = 0;
 
-               // 3. Change new data file to existing one.
+               // Change new data file to existing one.
                if (FaceRecogUtil::isFileExist(fvm->getFileName())) {
                        ret = ::remove(fvm->getFileName().c_str());
                        if (ret)
@@ -130,7 +130,7 @@ int FaceRecognition::registerNewFace(std::vector<float> &input_vec, string label
 
        // TODO. consider data augmentation.
        try {
-               // 1. Store a new label name to label file if the given label doesn't exist.
+               // Store a new label name to label file if the given label doesn't exist.
                if (!_label_manager->isExist(label_name))
                        _label_manager->addLabelToFile(label_name);
 
@@ -336,26 +336,16 @@ int FaceRecognition::deleteLabel(string label_name)
 
                LOGD("Current label count is %zu after removing the label(%s)", label_cnt, label_name.c_str());
 
-               unique_ptr<FeatureVectorManager> fvm = make_unique<FaceRecognitionFVM>(_config.feature_vector_file_path);
-               unique_ptr<FeatureVectorManager> fvm_new =
-                               make_unique<FaceRecognitionFVM>(_config.feature_vector_file_path + ".new");
-
-               // Make sure feature vector file.
-               checkFeatureVectorFile(fvm->getFileName(), fvm_new->getFileName());
-
                unique_ptr<DataSetManager> data_set = make_unique<FaceRecognitionDSM>();
+               unique_ptr<DataSetManager> data_set_new = make_unique<FaceRecognitionDSM>();
 
                // feature vectors corresponding to given label aren't removed yet from feature vector file.
                // So label_cnt_ori is needed.
                LOGD("Load the original feature vector data from the feature vector file.");
-               data_set->loadDataSet(fvm->getFileName(), label_cnt_ori);
+               data_set->loadDataSet(_config.feature_vector_file_path, label_cnt_ori);
 
                vector<vector<float> > feature_vectors_old = data_set->getData();
                vector<unsigned int> label_idx_vectors_old = data_set->getLabelIdx();
-               vector<vector<float> > feature_vectors_new;
-               vector<unsigned int> label_idx_vectors_new;
-
-               size_t data_set_cnt = 0;
 
                // Write existing feature vectors and its one-hot encoding table with updated label.
                for (unsigned int idx = 0; idx < feature_vectors_old.size(); ++idx) {
@@ -381,38 +371,17 @@ int FaceRecognition::deleteLabel(string label_name)
                        if (label_idx_vectors_old[idx] > target_label_idx)
                                label_idx_vectors_old[idx]--;
 
-                       feature_vectors_new.push_back(feature_vectors_old[idx]);
-                       label_idx_vectors_new.push_back(label_idx_vectors_old[idx]);
-                       data_set_cnt++;
+                       data_set_new->addDataSet(feature_vectors_old[idx], label_idx_vectors_old[idx], label_cnt);
                }
 
                // Retrain only in case that feature vectors exist.
-               if (data_set_cnt > 0) {
-                       fvm_new->storeData(feature_vectors_new, label_idx_vectors_new);
-                       fvm_new->writeHeader(feature_vectors_new[0].size(), label_cnt, data_set_cnt);
-
-                       int ret = 0;
-
-                       if (FaceRecogUtil::isFileExist(fvm->getFileName())) {
-                               // Change new data file to existing one.
-                               ret = ::remove(fvm->getFileName().c_str());
-                               if (ret)
-                                       throw InvalidOperation("Fail to remove feature vector file.");
-                       }
-
-                       ret = ::rename(fvm_new->getFileName().c_str(), fvm->getFileName().c_str());
-                       if (ret)
-                               throw InvalidOperation("Fail to rename new feature vector file to original one.");
-
+               if (data_set_new->getData().size() > 0) {
+                       storeDataSet(data_set_new, label_cnt);
                        _training_model->configureModel(label_cnt);
-                       unique_ptr<DataSetManager> new_data_set = make_unique<FaceRecognitionDSM>();
-                       new_data_set->clear();
 
                        // TODO. Remove existing internal model file.
 
-                       LOGD("Load the new feature vector data from the feature vector file.");
-                       new_data_set->loadDataSet(_config.feature_vector_file_path, label_cnt);
-                       _training_model->applyDataSet(new_data_set);
+                       _training_model->applyDataSet(data_set_new);
                        _training_model->compile();
                        _training_model->train();
 
@@ -422,10 +391,9 @@ int FaceRecognition::deleteLabel(string label_name)
 
                        // All data set can be used next time again so make sure to clean up previous dataset
                        // after training.
-                       _training_model->clearDataSet(new_data_set);
+                       _training_model->clearDataSet(data_set_new);
                } else {
                        _training_model->removeModel();
-                       fvm->remove();
                        _label_manager->removeFile();
 
                        LOGD("No training data so removed all relevant files.");
index 559133b..7a197f5 100644 (file)
 
 #include "machine_learning_exception.h"
 #include "face_recognition_dsm.h"
+
 #define MAX_FEATURE_VECTOR_CNT 5
+#define MAX_FEATURE_SIZE 1024
+#define MAX_NUMBER_OF_LABELS 20
+#define MAX_NUMBER_OF_DATA_SETS (MAX_FEATURE_VECTOR_CNT * MAX_NUMBER_OF_LABELS)
 
 using namespace std;
 using namespace mediavision::machine_learning::exception;
@@ -33,10 +37,10 @@ void FaceRecognitionDSM::printHeader(FeaVecHeader &fvh)
        LOGD("data set count = %u", fvh.data_set_cnt);
 }
 
-bool FaceRecognitionDSM::isHeaderValid(const FeaVecHeader &fvh, size_t max_size)
+bool FaceRecognitionDSM::isHeaderValid(const FeaVecHeader &fvh)
 {
-       return !(FeatureVectorManager::feature_vector_signature != fvh.signature || max_size <= fvh.feature_size ||
-                        max_size <= fvh.label_cnt || max_size <= fvh.data_set_cnt);
+       return !(FeatureVectorManager::feature_vector_signature != fvh.signature || MAX_FEATURE_SIZE < fvh.feature_size ||
+                        MAX_NUMBER_OF_LABELS < fvh.label_cnt || MAX_NUMBER_OF_DATA_SETS < fvh.data_set_cnt);
 }
 
 FaceRecognitionDSM::FaceRecognitionDSM() : DataSetManager()
@@ -71,22 +75,15 @@ void FaceRecognitionDSM::loadDataSet(const string file_name, unsigned int new_la
        if (!inFile.is_open())
                throw InvalidOperation("fail to open a file.");
 
-       // Feature vector file header is written at the end of the data file
-       // So read feature vector header from the end of the file.
-       inFile.seekg(static_cast<int>(sizeof(FeaVecHeader)) * -1, ios::end);
-
-       size_t file_size = inFile.tellg();
        FeaVecHeader fvh;
 
        inFile.read((char *) &fvh, sizeof(FeaVecHeader));
        if (inFile.gcount() != sizeof(FeaVecHeader))
                throw InvalidOperation("Invalid feature vector file.");
 
-       inFile.seekg(0, ios::beg);
-
        printHeader(fvh);
 
-       if (!isHeaderValid(fvh, file_size))
+       if (!isHeaderValid(fvh))
                throw InvalidOperation("Wrong feature vector header.");
 
        /*
index 2aa1cb9..87c7548 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <fstream>
+#include <unistd.h>
 
 #include "machine_learning_exception.h"
 #include "face_recognition_fvm.h"
@@ -25,29 +26,37 @@ using namespace mediavision::machine_learning::exception;
 FaceRecognitionFVM::FaceRecognitionFVM(const string feature_vector_file) : FeatureVectorManager(feature_vector_file)
 {}
 
-void FaceRecognitionFVM::writeHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt)
+void FaceRecognitionFVM::updateHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt)
 {
-       ofstream outFile { _feature_vector_file, ios::out | ios::binary | ios::app };
+       fstream headerFile {};
 
-       if (!outFile.is_open())
+       // When trying to write header data for the first time, the feature vector file doesn't exist,
+       // so create a new file with ios::out flag. Otherwise, open the feature vector file with ios::in | ios::out flags
+       // to update existing header data in the feature vector file.
+       if (access(_feature_vector_file.c_str(), F_OK))
+               headerFile.open(_feature_vector_file.c_str(), ios::out | ios::binary);
+       else
+               headerFile.open(_feature_vector_file.c_str(), ios::in | ios::out | ios::binary);
+
+       if (!headerFile.is_open())
                throw InvalidOperation("fail to open a file");
 
-       FeaVecHeader fvHeader { FeatureVectorManager::feature_vector_signature, feature_size, label_cnt, data_set_cnt };
+       FeaVecHeader header { FeatureVectorManager::feature_vector_signature, feature_size, label_cnt, data_set_cnt };
 
-       outFile.write((char *) &fvHeader, sizeof(FeaVecHeader));
+       headerFile.write((const char *) &header, sizeof(FeaVecHeader));
 }
 
 void FaceRecognitionFVM::storeData(vector<vector<float> > &features_vec, vector<unsigned int> &label_index)
 {
-       ofstream outFile { _feature_vector_file, ios::out | ios::binary | ios::app };
+       fstream writeFile { _feature_vector_file, ios::binary | ios::app };
 
-       if (!outFile.is_open())
+       if (!writeFile.is_open())
                throw InvalidOperation("fail to open a file.");
 
        for (size_t idx = 0; idx < features_vec.size(); ++idx) {
-               outFile.write(reinterpret_cast<char *>(features_vec[idx].data()),
-                                         static_cast<streamsize>(features_vec[idx].size() * sizeof(float)));
-               outFile.write(reinterpret_cast<char *>(&label_index[idx]), static_cast<streamsize>(sizeof(unsigned int)));
+               writeFile.write(reinterpret_cast<char *>(features_vec[idx].data()),
+                                               static_cast<streamsize>(features_vec[idx].size() * sizeof(float)));
+               writeFile.write(reinterpret_cast<char *>(&label_index[idx]), static_cast<streamsize>(sizeof(unsigned int)));
        }
 }
 
index 50b9256..5dce36f 100644 (file)
@@ -50,7 +50,7 @@ public:
        static void getVecFromXRGB(unsigned char *in_data, std::vector<float> &vec, unsigned int in_width,
                                                           unsigned int in_height, unsigned int re_width, unsigned int re_height);
 
-       virtual void writeHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt) = 0;
+       virtual void updateHeader(size_t feature_size, size_t label_cnt, unsigned int data_set_cnt) = 0;
        virtual void storeData(std::vector<std::vector<float> > &features_vec, std::vector<unsigned int> &label_index) = 0;
        virtual void remove() = 0;