From bddc2ac0d9861dd09b7b2f99101bd63ea165ecb0 Mon Sep 17 00:00:00 2001
From: Jean-Luc Parouty <Jean-Luc.Parouty@grenoble-inp.fr>
Date: Wed, 6 Jan 2021 19:01:44 +0100
Subject: [PATCH] Add new beautifull overriding system :-)

---
 VAE/08-VAE-with-CelebA.ipynb |  88 +++++++++++--------------
 VAE/batch_slurm.sh           |  54 ++++++++-------
 VAE/modules/callbacks.py     |   2 +-
 fidle/log/finished.json      |  10 ++-
 fidle/pwk.py                 | 124 ++++++++++++++++++++++++++---------
 5 files changed, 168 insertions(+), 110 deletions(-)

diff --git a/VAE/08-VAE-with-CelebA.ipynb b/VAE/08-VAE-with-CelebA.ipynb
index 01abdcd..ad89e9b 100644
--- a/VAE/08-VAE-with-CelebA.ipynb
+++ b/VAE/08-VAE-with-CelebA.ipynb
@@ -37,7 +37,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [
     {
@@ -117,15 +117,14 @@
      "text": [
       "Version              : 0.6.1 DEV\n",
       "Notebook id          : VAE8\n",
-      "Run time             : Tuesday 5 January 2021, 14:49:56\n",
-      "TensorFlow version   : 2.4.0\n",
-      "Keras version        : 2.4.0\n",
-      "Datasets dir         : /gpfswork/rech/mlh/uja62cb/datasets\n",
-      "Run dir              : ./run/CelebA-s.001\n",
-      "CI running mode      : none\n",
+      "Run time             : Wednesday 6 January 2021, 18:46:14\n",
+      "TensorFlow version   : 2.2.0\n",
+      "Keras version        : 2.3.0-tf\n",
+      "Datasets dir         : /home/pjluc/datasets/fidle\n",
+      "Run dir              : ./run/CelebA.001\n",
       "Update keras cache   : False\n",
       "Save figs            : True\n",
-      "Path figs            : ./run/CelebA-s.001/figs\n"
+      "Path figs            : ./run/CelebA.001/figs\n"
      ]
     },
     {
@@ -145,8 +144,8 @@
      "output_type": "stream",
      "text": [
       "Version              : 1.2\n",
-      "TensorFlow version   : 2.4.0\n",
-      "Keras version        : 2.4.0\n"
+      "TensorFlow version   : 2.2.0\n",
+      "Keras version        : 2.3.0-tf\n"
      ]
     },
     {
@@ -166,8 +165,8 @@
      "output_type": "stream",
      "text": [
       "Version              : 0.4.1\n",
-      "TensorFlow version   : 2.4.0\n",
-      "Keras version        : 2.4.0\n"
+      "TensorFlow version   : 2.2.0\n",
+      "Keras version        : 2.3.0-tf\n"
      ]
     }
    ],
@@ -190,7 +189,7 @@
     "sys.path.append('..')\n",
     "import fidle.pwk as pwk\n",
     "\n",
-    "run_dir = './run/CelebA-s.001'                  # Output directory\n",
+    "run_dir = './run/CelebA.001'                  # Output directory\n",
     "datasets_dir = pwk.init('VAE8', run_dir)\n",
     "\n",
     "VAE.about()\n",
@@ -199,17 +198,9 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 3,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "rm: cannot remove './run/CelebA-s.001/logs': No such file or directory\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# To clean run_dir, uncomment and run this next line\n",
     "# ! rm -r \"$run_dir\"/images-* \"$run_dir\"/logs \"$run_dir\"/figs \"$run_dir\"/models ; rmdir \"$run_dir\""
@@ -233,24 +224,30 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
     "# ---- For tests\n",
-    "# scale        = 0.3\n",
-    "# image_size   = (128,128)\n",
-    "# enhanced_dir = './data'\n",
+    "scale         = 0.3\n",
+    "image_size    = (128,128)\n",
+    "enhanced_dir  = './data'\n",
+    "latent_dim    = 300\n",
+    "r_loss_factor = 0.6\n",
     "\n",
     "# ---- Training with a full dataset\n",
-    "scale        = 1.\n",
-    "image_size   = (128,128)\n",
-    "enhanced_dir = f'{datasets_dir}/celeba/enhanced'\n",
+    "# scale         = 1.\n",
+    "# image_size    = (128,128)\n",
+    "# enhanced_dir  = f'{datasets_dir}/celeba/enhanced'\n",
+    "# latent_dim    = 300\n",
+    "# r_loss_factor = 0.6\n",
     "\n",
     "# ---- Training with a full dataset of large images\n",
-    "# scale        = 1.\n",
-    "# image_size   = (192,160)\n",
-    "# enhanced_dir = f'{datasets_dir}/celeba/enhanced'"
+    "# scale         = 1.\n",
+    "# image_size    = (192,160)\n",
+    "# enhanced_dir  = f'{datasets_dir}/celeba/enhanced'\n",
+    "# latent_dim    = 300\n",
+    "# r_loss_factor = 0.6\n"
    ]
   },
   {
@@ -262,23 +259,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Train directory is : /gpfswork/rech/mlh/uja62cb/datasets/celeba/enhanced/clusters-128x128\n"
+      "Train directory is : ./data/clusters-128x128\n"
      ]
     }
    ],
    "source": [
-    "# ---- Used for continous integration or batch mode - Just forget this 2 lines\n",
+    "# ---- Override parameters (batch mode) - Just forget this line\n",
     "#\n",
-    "scale        = pwk.override('scale',        scale)\n",
-    "image_size   = pwk.override('image_size',   image_size)\n",
-    "enhanced_dir = pwk.override('enhanced_dir', enhanced_dir)\n",
+    "pwk.override()\n",
     "\n",
     "# ---- the place of the clusters files\n",
     "#\n",
@@ -296,14 +291,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Data generator is ready with : 6331 batchs of 32 images, or 202599 images\n"
+      "Data generator is ready with : 379 batchs of 32 images, or 12155 images\n"
      ]
     }
    ],
@@ -320,15 +315,6 @@
     "## Step 3 - Build model"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "latent_dim = 300"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -422,7 +408,7 @@
     }
    ],
    "source": [
-    "vae = VAE(encoder, decoder, r_loss_factor=0.6)\n",
+    "vae = VAE(encoder, decoder, r_loss_factor)\n",
     "\n",
     "vae.compile(optimizer=keras.optimizers.Adam())"
    ]
diff --git a/VAE/batch_slurm.sh b/VAE/batch_slurm.sh
index 8a66cdd..35535d3 100755
--- a/VAE/batch_slurm.sh
+++ b/VAE/batch_slurm.sh
@@ -1,16 +1,4 @@
 #!/bin/bash
-
-#SBATCH --job-name="VAE"                               # nom du job
-#SBATCH --ntasks=1                                     # nombre de tâche (un unique processus ici)
-#SBATCH --gres=gpu:1                                   # nombre de GPU à réserver (un unique GPU ici)
-#SBATCH --cpus-per-task=10                             # nombre de coeurs à réserver (un quart du noeud)
-#SBATCH --hint=nomultithread                           # on réserve des coeurs physiques et non logiques
-#SBATCH --time=01:00:00                                # temps exécution maximum demande (HH:MM:SS)
-#SBATCH --output="VAE_%j.out"                          # nom du fichier de sortie
-#SBATCH --error="VAE_%j.err"                           # nom du fichier d'erreur (ici commun avec la sortie)
-#SBATCH --mail-user=Jean-Luc.Parouty@grenoble-inp.fr
-#SBATCH --mail-type=ALL
-
 # -----------------------------------------------
 #         _           _       _
 #        | |__   __ _| |_ ___| |__
@@ -27,25 +15,44 @@
 # Soumission :  sbatch  /(...)/fidle/VAE/batch_slurm.sh
 # Suivi      :  squeue -u $USER
 
-# ---- Parameters -------------------------------
+# ==== Job parameters ==============================================
+
+#SBATCH --job-name="VAE"                               # nom du job
+#SBATCH --ntasks=1                                     # nombre de tâche (un unique processus ici)
+#SBATCH --gres=gpu:1                                   # nombre de GPU à réserver (un unique GPU ici)
+#SBATCH --cpus-per-task=10                             # nombre de coeurs à réserver (un quart du noeud)
+#SBATCH --hint=nomultithread                           # on réserve des coeurs physiques et non logiques
+#SBATCH --time=01:00:00                                # temps exécution maximum demande (HH:MM:SS)
+#SBATCH --output="VAE_%j.out"                          # nom du fichier de sortie
+#SBATCH --error="VAE_%j.err"                           # nom du fichier d'erreur (ici commun avec la sortie)
+#SBATCH --mail-user=Jean-Luc.Parouty@grenoble-inp.fr
+#SBATCH --mail-type=ALL
+
+# ==== Notebook parameters =========================================
 
 MODULE_ENV="tensorflow-gpu/py3/2.4.0"
 NOTEBOOK_DIR="$WORK/fidle/VAE"
 
+# ---- VAE MNIST
+#
 # NOTEBOOK_SRC="01-VAE-with-MNIST.ipynb"
-# FIDLE_RUN_DIR="./run/MNIST.$SLURM_JOB_ID"
-
+# FIDLE_OVERRIDE_VAE8_run_dir="./run/MNIST.$SLURM_JOB_ID"
 
+# ---- VAE CelebA
+#
 NOTEBOOK_SRC="08-VAE-with-CelebA.ipynb"
+#
+export FIDLE_OVERRIDE_VAE8_run_dir="./run/CelebA.$SLURM_JOB_ID"
+export FIDLE_OVERRIDE_VAE8_scale="0.05"
+export FIDLE_OVERRIDE_VAE8_image_size="(128,128)"
+export FIDLE_OVERRIDE_VAE8_enhanced_dir='{datasets_dir}/celeba/enhanced'
+export FIDLE_OVERRIDE_VAZ8_r_loss_factor="0.5"
 
-FIDLE_OVERRIDE_VAE8_run_dir="./run/CelebA.$SLURM_JOB_ID"
-FIDLE_OVERRIDE_VAE8_scale="0.05"
-FIDLE_OVERRIDE_VAE8_image_size="(128,128)"
-FIDLE_OVERRIDE_VAE8_enhanced_dir='{datasets_dir}/celeba/enhanced'
-
+# ---- By default (no need to modify)
+#
 NOTEBOOK_OUT="${NOTEBOOK_SRC%.*}==${SLURM_JOB_ID}==.ipynb"
 
-# ------------------------------------------------
+# ==================================================================
 
 echo '------------------------------------------------------------'
 echo "Start : $0"
@@ -57,10 +64,10 @@ echo '------------------------------------------------------------'
 echo "Notebook dir  : $NOTEBOOK_DIR"
 echo "Notebook src  : $NOTEBOOK_SRC"
 echo "Notebook out  : $NOTEBOOK_OUT"
-echo "Run dir       : $FIDLE_OVERRIDE_VAE8_run_dir"
 echo "Environment   : $MODULE_ENV"
 echo '------------------------------------------------------------'
-
+env | grep FIDLE_OVERRIDE | awk 'BEGIN { FS = "=" } ; { printf("%-35s : %s\n",$1,$2) }'
+echo '------------------------------------------------------------'
 
 # ---- Module
 
@@ -70,7 +77,6 @@ module load "$MODULE_ENV"
 # ---- Run it...
 
 cd $NOTEBOOK_DIR
-export FIDLE_RUN_DIR
 
 jupyter nbconvert --ExecutePreprocessor.timeout=-1 --to notebook --output "$NOTEBOOK_OUT" --execute "$NOTEBOOK_SRC"
 
diff --git a/VAE/modules/callbacks.py b/VAE/modules/callbacks.py
index 25d12d3..2248251 100644
--- a/VAE/modules/callbacks.py
+++ b/VAE/modules/callbacks.py
@@ -76,4 +76,4 @@ class BestModelCallback(Callback):
         if current < self.loss:
             self.loss = current
             self.model.save(self.filename)
-            print('Saved - loss=',current)
+            print(f'Saved - loss={current:.6f}')
diff --git a/fidle/log/finished.json b/fidle/log/finished.json
index 06288e3..0acd1f6 100644
--- a/fidle/log/finished.json
+++ b/fidle/log/finished.json
@@ -150,8 +150,8 @@
         "duration": "00:00:08 736ms"
     },
     "VAE8": {
-        "path": "/gpfsdswork/projects/rech/mlh/uja62cb/fidle/VAE",
-        "start": "Wednesday 6 January 2021, 12:17:53",
+        "path": "/home/pjluc/dev/fidle/VAE",
+        "start": "Wednesday 6 January 2021, 18:46:14",
         "end": "",
         "duration": "Unfinished..."
     },
@@ -160,5 +160,11 @@
         "start": "Tuesday 5 January 2021, 15:22:23",
         "end": "Tuesday 5 January 2021, 15:23:32",
         "duration": "00:01:10 597ms"
+    },
+    "VAE12": {
+        "path": "/home/pjluc/dev/fidle/VAE",
+        "start": "Wednesday 6 January 2021, 18:29:53",
+        "end": "",
+        "duration": "Unfinished..."
     }
 }
\ No newline at end of file
diff --git a/fidle/pwk.py b/fidle/pwk.py
index fea2934..27d2bbf 100644
--- a/fidle/pwk.py
+++ b/fidle/pwk.py
@@ -10,7 +10,7 @@
 # A simple module to host some common functions for practical work
 # Jean-Luc Parouty 2020
 
-import os
+import os,sys
 import glob
 import shutil
 from datetime import datetime
@@ -80,7 +80,7 @@ def init(name=None, run_dir='./run'):
         
     # ---- run_dir
     #
-    run_dir = override('run_dir',run_dir)
+    override('run_dir')
     mkdir(run_dir)
     
     # ---- Update Keras cache
@@ -152,46 +152,106 @@ def error_datasets_not_found():
     display_md('----')
     assert False, 'datasets folder not found, please set FIDLE_DATASETS_DIR env var.'
 
-
-# -------------------------------------------------------------
-# param_override
-# -------------------------------------------------------------
-# Try to override a given parameter 'param'.
-#
-def override(name, value):
+    
+    
+def override(*names):
     '''
-    Try to override a given parameter (name,value) with an environment variable.
-    Env variable name is : FIDLE_OVERRIDE_<NOTEBOOK-ID>_<NAME>
-    If no env variable is available, return the given value.
-    If type is str, substitution is done with notebook_id and datasets_dir
+    Try to override attributes given par name with environment variables.
+    Environment variables name must be : FIDLE_OVERRIDE_<NOTEBOOK-ID>_<NAME>
+    If no env variable is available for a given name, nothing is change.
+    If type is str, substitution is done with 'notebook_id' and 'datasets_dir'
+    Example : override('image_size','nb_epochs')
     params:
-       name : parameter name
-       value: parameter value
+       names : list of attributes names as a str list
+               if empty, all attributes can be override
     return :
-       eval(env variable), if it env variable exist, or given value
+       nothing
     '''
-    # ---- Environment variable name
+    # ---- Where to override
     #
-    env_name  = f'FIDLE_OVERRIDE_{notebook_id}_{name}'
-    env_value = os.environ.get(env_name) 
+    main=sys.modules['__main__']
     
-    # ---- Doesn't exist ?
+    # ---- No names : mean all
     #
-    if env_value is None:
-        return value
-    
-    # ---- Exist
+    if len(names)==0:
+        names=[]
+        for name in dir(main):
+            if name.startswith('_'): continue
+            v=getattr(main,name)
+            if type(v) not in [str, int, float, bool, tuple, list, dict]: continue
+            names.append(name)
+            
+    # ---- Search for names
     #
-    if isinstance(value, str) : 
-        new_value = env_value.format(datasets_dir=datasets_dir, notebook_id=notebook_id)
+    for name in names:
+        
+        # ---- Environment variable name
+        #
+        env_name  = f'FIDLE_OVERRIDE_{notebook_id}_{name}'
+        env_value = os.environ.get(env_name) 
+
+        # ---- Environment variable : Doesn't exist
+        #
+        if env_value is None: continue
+
+        # ---- Environment variable : Exist
+        #
+        value_old  = getattr(main,name)
+        value_type = type(value_old)
+        
+        if value_type in [ str ] : 
+            new_value = env_value.format(datasets_dir=datasets_dir, notebook_id=notebook_id)
+
+        if value_type in [ int, float, bool, tuple, list, dict]:
+            new_value = eval(env_value)
+    
+        # ---- Override value
+        #
+        setattr(main,name,new_value)
+        print(f'Override : Attribute [{name}={value_old}] with [{new_value}]')        
+    
+      
+    
+
+# -------------------------------------------------------------
+# param_override
+# -------------------------------------------------------------
+# Try to override a given parameter 'param'.
+#
+# def override(name, value):
+#     '''
+#     Try to override a given parameter (name,value) with an environment variable.
+#     Env variable name is : FIDLE_OVERRIDE_<NOTEBOOK-ID>_<NAME>
+#     If no env variable is available, return the given value.
+#     If type is str, substitution is done with notebook_id and datasets_dir
+#     params:
+#        name : parameter name
+#        value: parameter value
+#     return :
+#        eval(env variable), if it env variable exist, or given value
+#     '''
+#     # ---- Environment variable name
+#     #
+#     env_name  = f'FIDLE_OVERRIDE_{notebook_id}_{name}'
+#     env_value = os.environ.get(env_name) 
+    
+#     # ---- Doesn't exist ?
+#     #
+#     if env_value is None:
+#         return value
+    
+#     # ---- Exist
+#     #
+#     if isinstance(value, str) : 
+#         new_value = env_value.format(datasets_dir=datasets_dir, notebook_id=notebook_id)
         
-    if type(value) in [ tuple, int, float]:
-        new_value = eval(env_value)
+#     if type(value) in [ tuple, int, float]:
+#         new_value = eval(env_value)
     
-    # ---- Return 
-    #
-    print(f'Override : Parameter [{name}={value}] set to [{new_value}]')
-    return new_value
+#     # ---- Return 
+#     #
+#     print(f'Override : Parameter [{name}={value}] set to [{new_value}]')
+#     return new_value
     
     
 # -------------------------------------------------------------
-- 
GitLab