Newer
Older
R_phipi / DNN.ipynb
@Davide Lancierini Davide Lancierini on 10 Oct 2018 35 KB bug solving
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "import os\n",
    "import pickle\n",
    "import math\n",
    "\n",
    "trunc_normal= tf.truncated_normal_initializer(stddev=1)\n",
    "normal = tf.random_normal_initializer(stddev=1)\n",
    "\n",
    "from architectures.data_processing import *\n",
    "from architectures.utils.toolbox import *\n",
    "from architectures.DNN import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# IMPORTING THE DATASET"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "l_index=1\n",
    "mag_index=1\n",
    "Ds_mass= 1968"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Signal MC amounts to 47950 while bkg data amounts to 188715\n"
     ]
    }
   ],
   "source": [
    "MC_sig_dict, data_bkg_dict = load_datasets(l_index)\n",
    "m=MC_sig_dict[\"Ds_ConsD_M\"].shape[0]\n",
    "n=data_bkg_dict[\"Ds_ConsD_M\"].shape[0]\n",
    "\n",
    "print('Signal MC amounts to {0} while bkg data amounts to {1}'.format(m,n))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Normalising the Chi2 vertex fits to the NDoF\n",
    "\n",
    "MC_sig_dict[\"Ds_ENDVERTEX_CHI2\"]=MC_sig_dict[\"Ds_ENDVERTEX_CHI2\"]/MC_sig_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "MC_sig_dict[\"Ds_OWNPV_CHI2\"]=MC_sig_dict[\"Ds_OWNPV_CHI2\"]/MC_sig_dict[\"Ds_OWNPV_NDOF\"]\n",
    "MC_sig_dict[\"Ds_IPCHI2_OWNPV\"]=MC_sig_dict[\"Ds_IPCHI2_OWNPV\"]/MC_sig_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "\n",
    "del MC_sig_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "del MC_sig_dict[\"Ds_OWNPV_NDOF\"]\n",
    "\n",
    "data_bkg_dict[\"Ds_ENDVERTEX_CHI2\"]=data_bkg_dict[\"Ds_ENDVERTEX_CHI2\"]/data_bkg_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "data_bkg_dict[\"Ds_OWNPV_CHI2\"]=data_bkg_dict[\"Ds_OWNPV_CHI2\"]/data_bkg_dict[\"Ds_OWNPV_NDOF\"]\n",
    "data_bkg_dict[\"Ds_IPCHI2_OWNPV\"]=data_bkg_dict[\"Ds_IPCHI2_OWNPV\"]/data_bkg_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "\n",
    "del data_bkg_dict[\"Ds_ENDVERTEX_NDOF\"]\n",
    "del data_bkg_dict[\"Ds_OWNPV_NDOF\"]\n",
    "\n",
    "data_bkg_dict[\"phi_ENDVERTEX_CHI2\"]=data_bkg_dict[\"phi_ENDVERTEX_CHI2\"]/data_bkg_dict[\"phi_ENDVERTEX_NDOF\"]\n",
    "data_bkg_dict[\"phi_OWNPV_CHI2\"]=data_bkg_dict[\"phi_OWNPV_CHI2\"]/data_bkg_dict[\"phi_OWNPV_NDOF\"]\n",
    "data_bkg_dict[\"phi_IPCHI2_OWNPV\"]=data_bkg_dict[\"phi_IPCHI2_OWNPV\"]/data_bkg_dict[\"phi_ENDVERTEX_NDOF\"]\n",
    "\n",
    "del data_bkg_dict[\"phi_ENDVERTEX_NDOF\"]\n",
    "del data_bkg_dict[\"phi_OWNPV_NDOF\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "branches_needed = [\n",
    "                    \"Ds_ENDVERTEX_CHI2\",\n",
    "                    #\"Ds_ENDVERTEX_NDOF\",\n",
    "                    \"Ds_OWNPV_CHI2\",\n",
    "                    #\"Ds_OWNPV_NDOF\",\n",
    "                    \"Ds_IPCHI2_OWNPV\",\n",
    "                    \"Ds_IP_OWNPV\",\n",
    "                    \"Ds_DIRA_OWNPV\",\n",
    "                    #l_flv[l_index]+\"_plus_MC15TuneV1_ProbNN\"+l_flv[l_index],\n",
    "                    #\"Ds_Hlt1TrackMVADecision_TOS\",\n",
    "                    #\"Ds_Hlt2RareCharmD2Pi\"+l_flv[l_index].capitalize()+l_flv[l_index].capitalize()+\"OSDecision_TOS\",\n",
    "                    #\"Ds_Hlt2Phys_TOS\",\n",
    "                    \"phi_ENDVERTEX_CHI2\",\n",
    "                    #\"phi_ENDVERTEX_NDOF\",\n",
    "                    \"phi_OWNPV_CHI2\",\n",
    "                    #\"phi_OWNPV_NDOF\",\n",
    "                    \"phi_IPCHI2_OWNPV\",\n",
    "                    \"phi_IP_OWNPV\",\n",
    "                    \"phi_DIRA_OWNPV\",\n",
    "                    \"Ds_ConsD_M\",\n",
    "                  ] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Number of input features\n",
    "\n",
    "dim=len(branches_needed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Convert data dictionaries to arrays for NN\n",
    "\n",
    "MC_sig = extract_array(MC_sig_dict, branches_needed, dim, m)\n",
    "data_bkg = extract_array(data_bkg_dict, branches_needed, dim, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Add 0/1 label for bkg/sig\n",
    "\n",
    "MC_sig_labelled=add_labels(MC_sig,signal=True)\n",
    "data_bkg_labelled=add_labels(data_bkg,signal=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#SOME CROSS CHECKS\n",
    "#MC_sig.shape==data_bkg.shape\n",
    "#MC_sig_labelled.shape[1]==dim+1==data_bkg_labelled.shape[1]\n",
    "#data_bkg_labelled[:,dim].sum()==0\n",
    "#(MC_sig_labelled[:,dim].sum()/m)==1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(135665, 1000, 100000)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Establish train/val/test sizes\n",
    "\n",
    "val_size=1000\n",
    "test_size=100000\n",
    "\n",
    "train_size=MC_sig.shape[0]+data_bkg.shape[0]-val_size-test_size\n",
    "(train_size, val_size, test_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Merge MC sig and data bkg, shuffle it\n",
    "\n",
    "data=np.concatenate((MC_sig_labelled,data_bkg_labelled), axis =0)\n",
    "np.random.seed(1)\n",
    "np.random.shuffle(data)\n",
    "\n",
    "#Check that nothing is missing\n",
    "\n",
    "data.shape[0]==train_size+val_size+test_size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Strip away the label column and convert it to a one-hot encoding\n",
    "\n",
    "X=data[:,0:dim]\n",
    "Y_labels=data[:,dim].astype(int)\n",
    "Y_labels=Y_labels.reshape(train_size+val_size+test_size,1)\n",
    "Y_labels_hot = to_one_hot(Y_labels)\n",
    "Y_labels=Y_labels_hot\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Divide the dataset in train/val/test sets \n",
    "\n",
    "X_train_0 = X[0:train_size]\n",
    "Y_train = Y_labels[0:train_size]\n",
    "\n",
    "X_val_0 = X[train_size:train_size+val_size]\n",
    "Y_val = Y_labels[train_size:train_size+val_size]\n",
    "\n",
    "X_test_0 = X[train_size+val_size:train_size+val_size+test_size]\n",
    "Y_test = Y_labels[train_size+val_size:train_size+val_size+test_size]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Ds_ENDVERTEX_CHI2',\n",
       " 'Ds_OWNPV_CHI2',\n",
       " 'Ds_IPCHI2_OWNPV',\n",
       " 'Ds_IP_OWNPV',\n",
       " 'Ds_DIRA_OWNPV',\n",
       " 'phi_ENDVERTEX_CHI2',\n",
       " 'phi_OWNPV_CHI2',\n",
       " 'phi_IPCHI2_OWNPV',\n",
       " 'phi_IP_OWNPV',\n",
       " 'phi_DIRA_OWNPV',\n",
       " 'Ds_ConsD_M']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "branches_needed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Strip out the reconstructed Ds mass\n",
    "\n",
    "X_train = X_train_0[:,0:dim-1]\n",
    "X_val = X_val_0[:,0:dim-1]\n",
    "X_test = X_test_0[:,0:dim-1]\n",
    "dim=X_train.shape[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SETTING UP THE NETWORK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "#task='TRAIN'\n",
    "task='TEST'\n",
    "\n",
    "PATH=l_flv[l_index]+'_Mag'+mag_status[mag_index]+'_test_4'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "if task =='TRAIN' and os.path.exists(PATH+'/hyper_parameters.pkl'):\n",
    "    with open(PATH+'/hyper_parameters.pkl', 'rb') as f:  \n",
    "        hyper_dict = pickle.load(f)\n",
    "        \n",
    "    m=hyper_dict[\"m\"]\n",
    "    test_size=hyper_dict[\"test_size\"]\n",
    "    val_size=hyper_dict[\"val_size\"]\n",
    "    LEARNING_RATE=hyper_dict[\"LEARNING_RATE\"]\n",
    "    BETA1=hyper_dict[\"BETA1\"]\n",
    "    BATCH_SIZE=hyper_dict[\"BATCH_SIZE\"]\n",
    "    EPOCHS=hyper_dict[\"EPOCHS\"]\n",
    "    VAL_PERIOD=hyper_dict[\"VAL_PERIOD\"]\n",
    "    SEED=hyper_dict[\"SEED\"]\n",
    "    sizes=hyper_dict[\"sizes\"]\n",
    "    LAMBD=hyper_dict[\"LAMBD\"]\n",
    "    PATH=hyper_dict[\"PATH\"]\n",
    "\n",
    "elif task=='TRAIN' and not os.path.exists(PATH+'/hyper_parameters.pkl'):\n",
    "    \n",
    "    \n",
    "    LEARNING_RATE = 0.001\n",
    "    BETA1 = 0.5\n",
    "    BATCH_SIZE = 64\n",
    "    EPOCHS = 20\n",
    "    VAL_PERIOD = 5\n",
    "    SEED=1\n",
    "    LAMBD=1.\n",
    "    \n",
    "    sizes = {\n",
    "    'dense_layers': [\n",
    "                        #(16, 'bn', 0.8, lrelu, tf.glorot_uniform_initializer()),\n",
    "                        #(8, 'bn', 0.5, lrelu, tf.glorot_uniform_initializer()),\n",
    "                        #(16, 'bn',0.8, lrelu, tf.glorot_uniform_initializer()),\n",
    "                        (32, 'bn', 0.8, lrelu, tf.glorot_uniform_initializer()),\n",
    "                        (16, 'bn', 0.8, lrelu, tf.glorot_uniform_initializer()),\n",
    "                        (8, 'bn', 0.8, lrelu, tf.glorot_uniform_initializer()),\n",
    "                    ],\n",
    "    'n_classes':2,\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "if task == 'TEST' and os.path.exists(PATH+'/hyper_parameters.pkl'):\n",
    "    with open(PATH+'/hyper_parameters.pkl', 'rb') as f:  \n",
    "        hyper_dict = pickle.load(f)\n",
    "        #for key, item in hyper_dict.items():\n",
    "        #    print(key+':'+str(item))\n",
    "            \n",
    "    m=hyper_dict[\"m\"]\n",
    "    test_size=hyper_dict[\"test_size\"]\n",
    "    val_size=hyper_dict[\"val_size\"]\n",
    "    LEARNING_RATE=hyper_dict[\"LEARNING_RATE\"]\n",
    "    BETA1=hyper_dict[\"BETA1\"]\n",
    "    BATCH_SIZE=hyper_dict[\"BATCH_SIZE\"]\n",
    "    EPOCHS=hyper_dict[\"EPOCHS\"]\n",
    "    VAL_PERIOD=hyper_dict[\"VAL_PERIOD\"]\n",
    "    SEED=hyper_dict[\"SEED\"]\n",
    "    sizes=hyper_dict[\"sizes\"]\n",
    "    LAMBD=hyper_dict[\"LAMBD\"]\n",
    "    PATH=hyper_dict[\"PATH\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "def bkg():\n",
    "    \n",
    "    tf.reset_default_graph()\n",
    "    nn = DNN(dim, sizes,\n",
    "              lr=LEARNING_RATE, beta1=BETA1, lambd=LAMBD,\n",
    "              batch_size=BATCH_SIZE, epochs=EPOCHS,\n",
    "              save_sample=VAL_PERIOD, path=PATH, seed=SEED)\n",
    "    \n",
    "    vars_to_train= tf.trainable_variables()\n",
    "    \n",
    "    if task == 'TRAIN':\n",
    "        init_op = tf.global_variables_initializer()\n",
    "        \n",
    "    if task == 'TEST':\n",
    "        vars_all = tf.global_variables()\n",
    "        vars_to_init = list(set(vars_all)-set(vars_to_train))\n",
    "        init_op = tf.variables_initializer(vars_to_init)\n",
    "    \n",
    "    # Add ops to save and restore all the variables.\n",
    "    saver = tf.train.Saver()\n",
    "    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)\n",
    "    \n",
    "    with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:\n",
    "        \n",
    "        sess.run(init_op)\n",
    "\n",
    "        if task=='TRAIN':\n",
    "            print('\\n Training...')\n",
    "            \n",
    "            if os.path.exists(PATH+'/CNN_model.ckpt.index'):\n",
    "                saver.restore(sess,PATH+'/CNN_model.ckpt')\n",
    "                print('Model restored.')\n",
    "            \n",
    "            nn.set_session(sess)\n",
    "            nn.fit(X_train, Y_train, X_val, Y_val)\n",
    "            \n",
    "            save_path = saver.save(sess, PATH+'/CNN_model.ckpt')\n",
    "            print(\"Model saved in path: %s\" % save_path)\n",
    "        \n",
    "        if task=='TEST':\n",
    "            print('\\n Evaluate model on test set...')\n",
    "            saver.restore(sess,PATH+'/CNN_model.ckpt')\n",
    "            print('Model restored.')\n",
    "            \n",
    "            nn.set_session(sess)\n",
    "            #nn.test(X_test, Y_test)\n",
    "            output_dict={}\n",
    "            \n",
    "            batch_size_output=100\n",
    "            n_batches_output = X_test.shape[0]//batch_size_output\n",
    "            \n",
    "            for i in range(n_batches_output):\n",
    "                small_dataset = X_test[i*batch_size_output:(i+1)*batch_size_output]\n",
    "                output_dict[i] = nn.predict(small_dataset)\n",
    "            output=np.concatenate([output_dict[i] for i in range(n_batches_output)])\n",
    "            \n",
    "            return output\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input for propagation (?, 10)\n",
      "Logits shape (?, 2)\n",
      "Input for propagation (?, 10)\n",
      "Logits shape (?, 2)\n",
      "\n",
      " Evaluate model on test set...\n",
      "INFO:tensorflow:Restoring parameters from mu_MagDown_test_4/CNN_model.ckpt\n",
      "Model restored.\n"
     ]
    }
   ],
   "source": [
    "if __name__=='__main__':\n",
    "\n",
    "    if task == 'TRAIN':\n",
    "        if not os.path.exists(PATH):\n",
    "            os.mkdir(PATH)\n",
    "    \n",
    "        elif os.path.exists(PATH):\n",
    "            if os.path.exists(PATH+'/checkpoint'):\n",
    "                ans = input('A previous checkpoint already exists, choose the action to perform \\n \\n 1) Overwrite the current model saved at '+PATH+'/checkpoint \\n 2) Start training a new model \\n 3) Restore and continue training the previous model \\n ')\n",
    "                \n",
    "                if ans == '1':\n",
    "                    print('Overwriting existing model in '+PATH)\n",
    "                    for file in os.listdir(PATH):\n",
    "                        file_path = os.path.join(PATH, file)\n",
    "                        try:\n",
    "                            if os.path.isfile(file_path):\n",
    "                                os.unlink(file_path)\n",
    "                            #elif os.path.isdir(file_path): shutil.rmtree(file_path)\n",
    "                        except Exception as e:\n",
    "                            print(e)\n",
    "                            \n",
    "                elif ans == '2':\n",
    "                    PATH = input('Specify the name of the model, a new directory will be created.\\n')\n",
    "                    os.mkdir(PATH)         \n",
    "        bkg()\n",
    "\n",
    "    elif task == 'TEST': \n",
    "        if not os.path.exists(PATH+'/checkpoint'):\n",
    "            print('No checkpoint to test')\n",
    "        else:\n",
    "            output = bkg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(100000, 2)"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1440x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if task=='TEST':\n",
    "\n",
    "    Ds_mass_MC =[MC_sig_dict[\"Ds_ConsD_M\"][i][0] for i in range(m)]\n",
    "    NN_selected = X_test_0[np.argmax(output, axis=1).astype(np.bool)]\n",
    "    Ds_mass_sel_NN = [NN_selected[i][dim] for i in range(NN_selected.shape[0])]\n",
    "    Ds_mass_train_NN =[X_train_0[i][dim] for i in range(X_train_0.shape[0])]\n",
    "\n",
    "    plt.subplot(1,2,1)\n",
    "    plt.hist(Ds_mass_MC,bins=70);\n",
    "    plt.subplot(1,2,2)\n",
    "    plt.hist(Ds_mass_sel_NN,alpha=0.8,bins=70);\n",
    "    plt.hist(Ds_mass_train_NN,alpha=0.2,bins=70);\n",
    "\n",
    "    fig=plt.gcf();\n",
    "    fig.set_size_inches(20,8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "if task=='TRAIN':\n",
    "    hyper_dict={\n",
    "        'm':m,\n",
    "        'test_size':test_size,\n",
    "        'val_size':val_size,\n",
    "        'LEARNING_RATE':LEARNING_RATE,\n",
    "        'BETA1':BETA1,\n",
    "        'BATCH_SIZE':BATCH_SIZE,\n",
    "        'EPOCHS':EPOCHS,\n",
    "        'VAL_PERIOD':VAL_PERIOD,\n",
    "        'SEED':SEED,\n",
    "        'sizes':sizes,\n",
    "        'LAMBD':LAMBD,\n",
    "        'PATH':PATH,\n",
    "    }\n",
    "    with open(PATH+'/hyper_parameters.pkl', 'wb') as f:  \n",
    "        pickle.dump(hyper_dict, f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}