From da9757edd9f3ea6b5657152ccf261b4840f8fb83 Mon Sep 17 00:00:00 2001
From: Ketan Kotwal <ketan.kotwal@idiap.ch>
Date: Wed, 7 Oct 2020 13:51:16 +0200
Subject: [PATCH] local file for lightcnn; configs for dataset and expt

---
 .../config/patch_pooling_lr.py                |  4 +-
 bob/paper/nir_patch_pooling/config/run.sh     |  2 +-
 .../nir_patch_pooling/extractor/__init__.py   |  2 +-
 .../nir_patch_pooling/extractor/lightcnn9.py  | 78 +++++++++++++++++++
 .../extractor/patch_pooling_cnn.py            |  2 +-
 .../script/annotate_database.py               | 31 ++++----
 .../script/convert_mlfp_database.py           | 26 +++----
 buildout.cfg                                  |  3 +-
 setup.py                                      |  7 +-
 9 files changed, 117 insertions(+), 38 deletions(-)
 create mode 100644 bob/paper/nir_patch_pooling/extractor/lightcnn9.py

diff --git a/bob/paper/nir_patch_pooling/config/patch_pooling_lr.py b/bob/paper/nir_patch_pooling/config/patch_pooling_lr.py
index eba3995..d8f89b8 100644
--- a/bob/paper/nir_patch_pooling/config/patch_pooling_lr.py
+++ b/bob/paper/nir_patch_pooling/config/patch_pooling_lr.py
@@ -22,15 +22,13 @@ FACE_SIZE = 128
 RGB_OUTPUT_FLAG = False
 USE_FACE_ALIGNMENT = True
 ALIGNMENT_TYPE = "lightcnn"
-MIN_FACE_SIZE = 50
 NORMALIZATION_FUNCTION = _norm_func
-NORMALIZATION_FUNCTION_KWARGS = {'n_sigma':3.0, 'norm_method':'MAD'}
+NORMALIZATION_FUNCTION_KWARGS = {'n_sigma':4.0, 'norm_method':'MAD'}
 
 _image_preprocessor = FaceCropAlign(face_size=FACE_SIZE,
         rgb_output_flag=RGB_OUTPUT_FLAG,
         use_face_alignment=USE_FACE_ALIGNMENT,
         alignment_type=ALIGNMENT_TYPE,
-        min_face_size=MIN_FACE_SIZE,
         normalization_function = NORMALIZATION_FUNCTION,
         normalization_function_kwargs = NORMALIZATION_FUNCTION_KWARGS)
 
diff --git a/bob/paper/nir_patch_pooling/config/run.sh b/bob/paper/nir_patch_pooling/config/run.sh
index 38606a4..9659f6c 100755
--- a/bob/paper/nir_patch_pooling/config/run.sh
+++ b/bob/paper/nir_patch_pooling/config/run.sh
@@ -7,7 +7,7 @@ echo "-----------------------------------"
 
 expt="wmca"
 
-base_directory="/idiap/temp/kkotwal/icip20/expt"
+base_directory="/idiap/temp/kkotwal/test_icip/expt"
 
 # expt: WMCA
 if [[ "${expt}" == "wmca" ]]; then
diff --git a/bob/paper/nir_patch_pooling/extractor/__init__.py b/bob/paper/nir_patch_pooling/extractor/__init__.py
index bb19ad5..c4fb95e 100644
--- a/bob/paper/nir_patch_pooling/extractor/__init__.py
+++ b/bob/paper/nir_patch_pooling/extractor/__init__.py
@@ -1,2 +1,2 @@
+from .lightcnn9 import LightCNN9
 from .patch_pooling_cnn import PatchPoolingCNN
-
diff --git a/bob/paper/nir_patch_pooling/extractor/lightcnn9.py b/bob/paper/nir_patch_pooling/extractor/lightcnn9.py
new file mode 100644
index 0000000..4038727
--- /dev/null
+++ b/bob/paper/nir_patch_pooling/extractor/lightcnn9.py
@@ -0,0 +1,78 @@
+'''
+    implement Light CNN
+    @author: Alfred Xiang Wu
+    @date: 2017.07.04
+'''
+
+import math
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+#------------------------------------------------------------------------------
+
+class mfm(nn.Module):
+    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, type=1):
+        super(mfm, self).__init__()
+        self.out_channels = out_channels
+        if type == 1:
+            self.filter = nn.Conv2d(in_channels, 2*out_channels, kernel_size=kernel_size, stride=stride, padding=padding)
+        else:
+            self.filter = nn.Linear(in_channels, 2*out_channels)
+
+    def forward(self, x):
+        x = self.filter(x)
+        out = torch.split(x, self.out_channels, 1)
+        return torch.max(out[0], out[1])
+
+#------------------------------------------------------------------------------
+
+class group(nn.Module):
+    def __init__(self, in_channels, out_channels, kernel_size, stride, padding):
+        super(group, self).__init__()
+        self.conv_a = mfm(in_channels, in_channels, 1, 1, 0)
+        self.conv   = mfm(in_channels, out_channels, kernel_size, stride, padding)
+
+    def forward(self, x):
+        x = self.conv_a(x)
+        x = self.conv(x)
+        return x
+
+#------------------------------------------------------------------------------
+
+class LightCNN9(nn.Module):
+
+    def __init__(self, num_classes=79077):
+
+        super(LightCNN9, self).__init__()
+        self.features = nn.Sequential(
+            mfm(1, 48, 5, 1, 2), 
+            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), 
+            group(48, 96, 3, 1, 1), 
+            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True),
+            group(96, 192, 3, 1, 1),
+            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), 
+            group(192, 128, 3, 1, 1),
+            group(128, 128, 3, 1, 1),
+            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True),
+            )
+        self.fc1 = mfm(8*8*128, 256, type=0)
+        self.fc2 = nn.Linear(256, num_classes)
+        self.sigmoid = nn.Sigmoid()
+
+    def forward(self, x):
+
+        x = self.features(x)
+        x = x.view(x.size(0), -1)
+
+        x = self.fc1(x)
+        x = F.dropout(x, p=0.5, training=self.training)
+        scores = self.fc2(x)
+        scores = self.sigmoid(scores)
+
+        # scores, features
+        return scores, x
+
+#------------------------------------------------------------------------------
+
+
diff --git a/bob/paper/nir_patch_pooling/extractor/patch_pooling_cnn.py b/bob/paper/nir_patch_pooling/extractor/patch_pooling_cnn.py
index 0cc37dd..33e807d 100644
--- a/bob/paper/nir_patch_pooling/extractor/patch_pooling_cnn.py
+++ b/bob/paper/nir_patch_pooling/extractor/patch_pooling_cnn.py
@@ -12,7 +12,7 @@ from PIL import Image
 import torch.nn.functional as F
 from torch.autograd import Variable
 import torchvision.transforms as transforms
-from bob.learn.pytorch.architectures import LightCNN9
+from bob.paper.nir_patch_pooling.extractor import LightCNN9
 from bob.bio.base.extractor import Extractor
 
 import logging
diff --git a/bob/paper/nir_patch_pooling/script/annotate_database.py b/bob/paper/nir_patch_pooling/script/annotate_database.py
index 5ab7800..013d3be 100755
--- a/bob/paper/nir_patch_pooling/script/annotate_database.py
+++ b/bob/paper/nir_patch_pooling/script/annotate_database.py
@@ -12,7 +12,7 @@ from bob.io.base import create_directories_safe
 import numpy as np
 import json
 import os, sys
-
+from bob.paper.nir_patch_pooling.config.wmca_mask import database as d1
 #------------------------------------------------------------------------------
 
 class Annotator:
@@ -32,18 +32,18 @@ class Annotator:
         # find annotations using MTCNN
         frame_annotations = detect_face_landmarks_in_image(image, method="mtcnn")
         if frame_annotations:
-            logger.debug(" --> Found using MTCNN")
+            #print(" --> Found using MTCNN")
             return frame_annotations
 
         # else, find annotations using dlib
         frame_annotations = detect_face_landmarks_in_image(image, method="dlib")
         if frame_annotations:
-            logger.debug(" --> Found using dlib")
+            print(" --> Found using dlib")
             return frame_annotations
 
         # else, return empty dictionary with warning
-        logger.warning(" --> Could not find annotations")
-        return {}
+        print(" --> Could not find annotations")
+        return None
 
 #------------------------------------------------------------------------------
 
@@ -85,21 +85,22 @@ class Annotator:
                 frame_annotations = self.find_annotations(image)
 
             except Exception as e:
-                logger.error("\tException: {}".format(e))
+                print("\tException: {}".format(e))
 
                 # copy annotations of previous frame
                 if (prev_valid_index is not None):
                
                     frame_annotations = annotations[prev_valid_index]
-                    logger.warning("\tCopying annotations of valid previous frame")
+                    print("\tCopying annotations of valid previous frame")
                 
                 else:
                 
-                    frame_annotations = {}
-                    logger.warning("\tSetting empty annotations")
+                    frame_annotations = None
+                    print("\tSetting empty annotations")
 
-            annotations[str(index)] = frame_annotations
-            prev_valid_index = str(index)
+            if frame_annotations is not None:
+                annotations[str(index)] = frame_annotations
+                prev_valid_index = str(index)
         
         return annotations
 
@@ -117,7 +118,7 @@ class AnnotationGenerator:
 
         if not os.path.exists(self.annotation_directory):
             os.makedirs(self.annotation_directory)
-            logger.warning("Annotation directory created at: {}"\
+            print("Annotation directory created at: {}"\
                 .format(self.annotation_directory))
 
         self.annotator = Annotator()
@@ -166,14 +167,14 @@ class AnnotationGenerator:
         # process each video in the given range
         for idx, f in enumerate(self.filelist[start_index:end_index]):
 
-            logger.info("[{:03d}/{:03d}] Sample: {}".format(idx+1, total, f.path))
+            print("[{:03d}/{:03d}] Sample: {}".format(idx+1, total, f.path))
             json_filepath = os.path.join(self.annotation_directory, f.path + ".json")
             
             if not os.path.exists(json_filepath):
                 self.process_video(f)
             
             else:
-                logger.info("Annotations exist: {}. Skipping".format(f.path))
+                print("Annotations exist: {}. Skipping".format(f.path))
 
         return
 
@@ -187,7 +188,7 @@ def main():
             .format(__name__))
         exit(0)
 
-    database = sys.argv[1]
+    database = d1 # sys.argv[1]
     annotation_directory = sys.argv[2]
     print("Database: {}. Annotation directory: {}".format(database,\
         annotation_directory))
diff --git a/bob/paper/nir_patch_pooling/script/convert_mlfp_database.py b/bob/paper/nir_patch_pooling/script/convert_mlfp_database.py
index c6d4f80..d451f5f 100755
--- a/bob/paper/nir_patch_pooling/script/convert_mlfp_database.py
+++ b/bob/paper/nir_patch_pooling/script/convert_mlfp_database.py
@@ -13,10 +13,6 @@ import numpy as np
 from bob.pad.face.preprocessor.FaceCropAlign import detect_face_landmarks_in_image
 import json
 
-import logging
-logger = logging.getLogger(__name__)
-logger.setLevel(logging.INFO)
-
 frames_per_video = 20
 
 #------------------------------------------------------------------------------
@@ -99,20 +95,20 @@ class MLFPConvertor:
                 frame_annotations = self.find_annotations(image)
 
             except Exception as e:
-                logger.error("\tException: {}".format(e))
+                print(" --> Exception: {}".format(e))
 
                 # copy annotations of previous frame
                 if (prev_index is not None):
                     frame_annotations = annotations[prev_index]
-                    logger.warning("\tCopying annotations of previous frame")
-                    print("\tCopying annotations of previous frame")
+                    print(" --> Copying annotations of previous frame")
                 
                 else:
-                    frame_annotations = {}
-                    logger.warning("\tSetting empty annotations")
+                    frame_annotations = None
+                    print(" --> No annotations")
 
-            annotations[str(index)] = frame_annotations
-            prev_index = str(index)
+            if frame_annotations is not None:
+                annotations[str(index)] = frame_annotations
+                prev_index = str(index)
         
         return annotations
 
@@ -128,18 +124,18 @@ class MLFPConvertor:
         # find annotations using MTCNN
         frame_annotations = detect_face_landmarks_in_image(image, method="mtcnn")
         if frame_annotations:
-            logger.debug(" --> Found using MTCNN")
+            #print(" --> Found using MTCNN")
             return frame_annotations
 
         # else, find annotations using dlib
         frame_annotations = detect_face_landmarks_in_image(image, method="dlib")
         if frame_annotations:
-            logger.debug(" --> Found using dlib")
+            #print(" --> Found using dlib")
             return frame_annotations
 
         # else, return empty dictionary with warning
-        logger.warning(" --> Could not find annotations")
-        return {}
+        print(" --> Could not find annotations")
+        return None
 
 #------------------------------------------------------------------------------
 
diff --git a/buildout.cfg b/buildout.cfg
index 5f27ead..b0fb596 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -13,8 +13,9 @@ verbose = true
 
 develop = .
 
-eggs = bob.paper.nir_patch_pooling
+eggs = bob.pad.base
     bob.db.batl
+    bob.paper.nir_patch_pooling
 
 [sources]
 bob.db.batl = git git@gitlab.idiap.ch:bob/bob.db.batl rev=5fecee9158832516c560d000a71ae7272d640506
diff --git a/setup.py b/setup.py
index 28f823c..f2b9b4f 100644
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,12 @@ setup(
     install_requires=install_requires,
 
     entry_points={
-      # mlfp, wmca-mask, expt-patch-pooling 
+        'bob.bio.config': [
+            'wmca-mask = bob.paper.nir_patch_pooling.config.wmca_mask',
+            'mlfp = bob.paper.nir_patch_pooling.config.mlfp',
+            'patch-pooling-lr = bob.paper.nir_patch_pooling.config.patch_pooling_lr',
+        ],
+
       },
 
     # check classifiers, add and remove as you see fit
-- 
GitLab