diff --git a/part3/part3.ipynb b/part3/part3.ipynb index e0227b859ee1c7216596037ff9dddd800dfe51bf..d4ac8ae0ae914d825eb97e6f63ca53abb47602f4 100644 --- a/part3/part3.ipynb +++ b/part3/part3.ipynb @@ -120,7 +120,9 @@ "import uproot\n", "import awkward as ak\n", "import matplotlib.pyplot as plt\n", - "import mplhep" + "import mplhep\n", + "import os\n", + "d = os.environ['MLATL1T_DIR']" ] }, { @@ -139,8 +141,8 @@ "metadata": {}, "outputs": [], "source": [ - "f_sig = uproot.open('part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_signal.root')\n", - "f_bkg = uproot.open('part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_background.root')\n", + "f_sig = uproot.open(d + '/part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_signal.root')\n", + "f_bkg = uproot.open(d + '/part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_background.root')\n", "y_sig_cmssw = ak.flatten(f_sig['Events/L1TMLDemo_y'].array()).to_numpy()\n", "y_bkg_cmssw = ak.flatten(f_bkg['Events/L1TMLDemo_y'].array()).to_numpy()" ] diff --git a/solutions/part3.ipynb b/solutions/part3.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..23b9f976243a7ecc676df1bd2e2a04599d39baf6 --- /dev/null +++ b/solutions/part3.ipynb @@ -0,0 +1,260 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3e175280", + "metadata": {}, + "source": [ + "# CMSSW Emulator\n", + "\n", + "In this exercise you will be guided through the steps to create, compile, and run the emulator of the hls4ml model you trained in part 2. The code in these steps should be executed from the command line on `lxplus` after doing `source setup.sh` from this `cms_mlatl1t_tutorial`.\n", + "\n", + "When developing your own hls4ml NN emulators, you should compile and run your model emulator locally before delivering it to `cms-hls4ml`.\n", + "\n", + "**Note** you need to run the steps described below in the terminal before going through the cells in this notebook!\n", + "\n", + "## Prerequisite\n", + "\n", + "You will need the HLS for the model of part 2.\n", + "\n", + "## 1.\n", + "\n", + "Copy the NN-specific part of the hls4ml project to the `cms-hls4ml` repo. We _don't_ copy `ap_types` since we'll reference them from the externals.\n", + "\n", + "```shell\n", + "[ ! -d $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo/L1TMLDemo_v1/NN ] && mkdir $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo/L1TMLDemo_v1/NN\n", + "cp -r $MLATL1T_DIR/part2/L1TMLDemo_v1/firmware/{*.h,*.cpp,weights,nnet_utils} $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo/L1TMLDemo_v1/NN\n", + "```\n", + "\n", + "## 2.\n", + "\n", + "As of `hls4ml` `0.8.1`, when run outside of Vivado HLS, the C++ code loads the weights from txt files. We need to force compilation of the weights from the header file instead. \n", + "\n", + "This one liner will replace the `#define` that would cause the weights to be loaded from txt files with one that will load them from the header files when we compile instead.\n", + "\n", + "If you don't do this, when you `cmsRun` you will see a runtime error like `ERROR: file w2.txt does not exist`\n", + "\n", + "```shell\n", + "find $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo/L1TMLDemo_v1/NN \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i 's/#ifndef __SYNTHESIS__/#ifdef __HLS4ML_LOAD_TXT_WEIGHTS__/'\n", + "```\n", + "\n", + "## 3.\n", + "\n", + "`make` the hls4ml emulator interface shared object\n", + "\n", + "```shell\n", + "cd $MLATL1T_DIR/part3/cms-hls4ml/hls4mlEmulatorExtras\n", + "make\n", + "mkdir lib64\n", + "mv libemulator_interface.so lib64\n", + "```\n", + "\n", + "## 4.\n", + "\n", + "`make` the `L1TMLDemo` model shared object\n", + "\n", + "```shell\n", + "cd $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo\n", + "make\n", + "```\n", + "\n", + "*Note* you might benefit from adding `-g` to `CXXFLAGS` to compile with debugging while developing.\n", + "The Makefile line would change to `CXXFLAGS := -O3 -fPIC -std=$(CPP_STANDARD) -g`.\n", + "\n", + "\n", + "## 5.\n", + "\n", + "`scram build` compile the CMSSW code\n", + "\n", + "```shell\n", + "cd $CMSSW_BASE/src\n", + "scram b -j8\n", + "```\n", + "\n", + "## 6.\n", + "\n", + "Copy the `L1TMLDemo` model shared object to the CMSSW area.\n", + "\n", + "```shell\n", + "mkdir $CMSSW_BASE/src/L1Trigger/L1TMLDemo/data\n", + "cp $MLATL1T_DIR/part3/cms-hls4ml/L1TMLDemo/L1TMLDemo_v1.so $CMSSW_BASE/src/L1Trigger/L1TMLDemo/data\n", + "```\n", + "\n", + "## 7.\n", + "\n", + "Run the test config over signal and background!\n", + "\n", + "```shell\n", + "cd $CMSSW_BASE/src/L1Trigger/L1TMLDemo/test\n", + "cmsRun demoL1TMLNtuple.py signal=True\n", + "cmsRun demoL1TMLNtuple.py signal=False\n", + "```\n", + "\n", + "We run over the same datasets as part 1:\n", + "- Signal: `/GluGlutoHHto2B2Tau_kl-1p00_kt-1p00_c2-0p00_TuneCP5_13p6TeV_powheg-pythia8/Run3Summer22MiniAODv4-130X_mcRun3_2022_realistic_v5-v2/MINIAODSIM`\n", + "- Background: `/SingleNeutrino_E-10-gun/Run3Summer23BPixMiniAODv4-130X_mcRun3_2023_realistic_postBPix_v2-v2/MINIAODSIM`\n", + "\n", + "This will produce the files\n", + "- `L1TMLDemo_NanoAOD_signal.root`\n", + "- `L1TMLDemo_NanoAOD_background.root`\n", + "\n", + "*Note* when developing your own models, you may unfortunately run into segmentation violations while developing. The most common reason is that the input and output data type set in the producer mismatch the types used by the model emulator. In this emulator workflow, this causes a runtime error rather than a compile time error.\n", + "\n", + "## 8.\n", + "\n", + "Run the notebook part3.ipynb\n", + "\n", + "# Notebook\n", + "\n", + "Now we can read the predictions from our Nano AOD ntuple and check they make sense compared to part 1 and part 2." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8d652e36", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import uproot\n", + "import awkward as ak\n", + "import matplotlib.pyplot as plt\n", + "import mplhep\n", + "import os\n", + "d = os.environ['MLATL1T_DIR']" + ] + }, + { + "cell_type": "markdown", + "id": "f40b86af", + "metadata": {}, + "source": [ + "## Load data\n", + "Load our signal and background data with `uproot`" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e8fc68f0", + "metadata": {}, + "outputs": [], + "source": [ + "f_sig = uproot.open(d + '/part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_signal.root')\n", + "f_bkg = uproot.open(d + '/part3/cmssw/src/L1Trigger/L1TMLDemo/test/L1TMLDemo_NanoAOD_background.root')\n", + "y_sig_cmssw = ak.flatten(f_sig['Events/L1TMLDemo_y'].array()).to_numpy()\n", + "y_bkg_cmssw = ak.flatten(f_bkg['Events/L1TMLDemo_y'].array()).to_numpy()" + ] + }, + { + "cell_type": "markdown", + "id": "2069399f", + "metadata": {}, + "source": [ + "## Histogram\n", + "\n", + "Plot the score distribution for signal and background" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d55f97b8", + "metadata": {}, + "outputs": [], + "source": [ + "bins=np.linspace(0, 1, 100)\n", + "w = bins[1]\n", + "h_sig, _ = np.histogram(y_sig_cmssw, bins=bins)\n", + "h_bkg, _ = np.histogram(y_bkg_cmssw, bins=bins)\n", + "h_sig = h_sig.astype('float') / np.sum(h_sig)\n", + "h_bkg = h_bkg.astype('float') / np.sum(h_bkg)" + ] + }, + { + "cell_type": "markdown", + "id": "08e81144", + "metadata": {}, + "source": [ + "## Plot" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eda30259", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/afs/cern.ch/user/s/ssummers/.local/lib/python3.9/site-packages/numpy/core/getlimits.py:500: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n", + " setattr(self, word, getattr(machar, word).flat[0])\n", + "/afs/cern.ch/user/s/ssummers/.local/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n", + " return self._float_to_str(self.smallest_subnormal)\n" + ] + }, + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'Frequency')" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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CQmxeI4kVVRUOFROAIB/IzTZYM/ac/7GZDKpQYMGunDhgrZu3apWrVpp2rRp6t27t9q3b69jx45Z7N+9e3dzp25bkpOT9eGHH+qFF17Q/PnzzdvbtGmjkJAQi2Vqzp07p6+//rrWcnbq1Elbtmyx2LZlyxZ16NDBXMt09dVX69SpU+bHv/nmGxUVFdnxLlie54svvrDY9vnnn9fpGAAA/0HznA3p6elKT09Xfn6+oqOjPV0clyguLlZeXp50uXnutddeU0FBgYYOHar8/HwdP35cK1asUJ8+fbR27Vq99957Fs/PzMzUzTffrLZt2+q+++5TWVmZ1q1bpylTpljs179/f61bt05DhgxRcHCwJkyYoKioKI0aNUpPPvmkmjZtqubNmyszM1MNGjSotdZs4sSJ6tOnj2bNmqURI0Zo27Zteu211/T666+b9xk8eLBee+019evXT+Xl5ZoyZYpFrZI9fve732nAgAGaP3++hg0bpg0bNtA0BwABjJqmALZ+/XrFx8crPj5effv21Y4dO7Rq1SoNGjRIv/jFL/TEE09o/PjxSkpK0tatW80drysNGjRIq1at0vvvv6+kpCQNHjxY27dvt3quG2+8UWvXrtX06dP16quvSpIWLlyofv366ec//7lSU1M1YMAAderUSeHh4TWWu2fPnnr33Xe1YsUKde3aVTNmzNDMmTMtOoEvWLBALVq00E033aT7779fkyZNUmRkZJ3enxtuuEFvvvmmXn75ZfXo0UMbN2606BwPAAgsJsORCX4CSGVN06mz3ysupqmKSsrM0wrseXqg8v5zQq1bt671gx61Kyws1DXXXKMFCxZo7Nixni6OQy5evKgjR47wMwEArlBS+N/JLSsnsrS2rcrn97lz5ywGMdUHzXPwmD179mj//v1KTk7WuXPnNHPmTEmqNjIOAABvQGiCR82fP18HDhxQaGioevXqpU8//VQxMTGeLhYAANUQmuAx119/vXbt2uXpYgAAYBc6ggMAANiB0AQAAGAHQhMAAIAdCE0AAAB2IDQBAADYgdAEq0wmk9asWeP28yYmJmrRokVuPy8AALUhNAWos2fP6je/+Y1atmypsLAwxcXFKS0tzbwQ7qlTpzRkyBBPFxMAAK/BPE0B6q677lJJSYmWL1+uNm3a6PTp08rOztb3338vSYqLi/N0EQEA8CrUNAWgn376SZ9++qlefPFFpaSkqFWrVkpOTtZTTz2lX/ziF5KV5rmtW7cqKSlJ4eHh6t27t9asWSOTyaScnBxJ0ubNm2UymZSdna3evXsrMjJS/fv314EDB8zHOHTokIYNG6bY2Fg1atRIffr00UcffeSBdwAAgLojNNmQlZWlzp07q0+fPvY/yTAuLRzoiVsd1l1u1KiRGjVqpDVr1qi4uLjW/fPz8zV06FB169ZNu3fv1qxZszRlyhSr+06bNk0LFizQzp07FRwcrDFjxpgfKygo0G233abs7Gzt2bNHt956q4YOHarjx4/bXXYAADyF5jkb0tPTlZ6ebl4l2S6lRf9dadndqqzsXJvg4GAtW7ZM48aN0+LFi9WzZ08NHDhQ9913n7p3715t/7/85S8ymUx68803FR4ers6dO+s///mPxo0bV23f2bNna+DAgZKkqVOn6vbbb9fFixcVHh6uHj16qEePHuZ9Z82apffee0/vv/++xo8fX6+XDwCAq1HTFKDuuusunTx5Uu+//75uvfVWbd68WT179tSyZcuq7XvgwAF1795d4eHh5m3JyclWj1s1dMXHx0uSzpw5I12uaZo0aZI6deqkJk2aqFGjRtq3bx81TQAAn0BNkzOFRF6q8fHUuesoPDxct9xyi2655RY988wz+tWvfqXMzEyNHj3a8WKEhJj/bzKZJEkVFRWSpEmTJukf//iH5s+fr3bt2ikiIkJ33323SkpKHD4fAADuQmhyJpPJ7iYyb9S5c2erczN17NhRf/rTn1RcXKywsDBJ0o4dO+p8/C1btmj06NG64447pMs1T0ePHnVCyQEAcD2a5wLQ999/r8GDB+tPf/qTvvzySx05ckSrVq3SvHnzNGzYsGr733///aqoqNAjjzyiffv2acOGDZo/f75UpTbJHu3bt9fq1auVk5OjvXv3mo8LAIAvoKYpADVq1Eh9+/bV73//ex06dEilpaVq0aKFxo0bp6effrra/o0bN9bf//53/eY3v1FSUpK6deumGTNm6P7777fo51SbhQsXasyYMerfv79iYmI0ZcoU5efnO/nVAQDgGoSmABQWFqY5c+Zozpw5NvcxrpjCoH///tq7d6/5/p///GeFhISoZcuWkqRBgwZVe05SUpLFtsTERP3zn/+02Cc9Pd3iPs11AABvRWiCXd555x21adNG11xzjfbu3aspU6bo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8+eNPXv2GHv27DEkGQsXLjT27NljHDt2zDAMw5g6daoxcuRI8/6VUw48+eSTxr59+4ysrCymHHDUq6++arRs2dIIDQ01kpOTjc8//9z82MCBA41Ro0ZZ7P/uu+8aHTp0MEJDQ40uXboYa9eu9UCp/VNdrkWrVq0MSdVumZmZHiq9f6nr70VVhCbnquu12Lp1q9G3b18jLCzMaNOmjTF79myjrKzMAyX3P3W5FqWlpcazzz5rtG3b1ggPDzdatGhhPPbYY8aPP/7oodL7j02bNln9+1/5/o8aNcoYOHBgteckJSUZoaGhRps2bYylS5fW+bwmgzpCAACAWgV0nyYAAAB7EZoAAADsQGgCAACwA6EJAADADoQmAAAAOxCaAAAA7EBoAgAAsAOhCQAAwA6EJgCoYvPmzTKZTPrpp588XRSPePbZZ5WUlGS+P3r0aA0fPrxex3TGMQBvQGgCnCwvL0+//e1v1aZNG4WFhalFixYaOnSoxWKRiYmJMplMWrFiRbXnd+nSRSaTScuWLTNv27t3r37xi1+oefPmCg8PV2JiokaMGKEzZ86Y93nvvfd0ww03KDo6WlFRUerSpYsmTJggSdq/f79MJpM+//xzi3PdcMMNCg8P18WLF83bLl68qPDwcL399ttWX19lqOjSpYvKy8stHmvSpIlFuStf55XnnTBhggYNGmTzPTx69KhMJpPV25XH8gaDBg0yv9eu8Oyzz5pff3BwsBITE/XEE0+ooKDAZees9PLLL1tc05pUXrecnByHjwF4M0IT4ERHjx5Vr1699M9//lMvvfSSvvrqK61fv14pKSlKT0+32LdFixZaunSpxbbPP/9ceXl5atiwoXnb2bNndfPNN6tp06basGGD9u3bp6VLlyohIUGFhYWSpOzsbI0YMUJ33XWXtm/frl27dmn27NkqLS2VJF133XWKi4vT5s2bzcc9f/68du/erauvvtoiiGzbtk3FxcUaPHhwja/18OHDeuedd2p9T8LDwzVlypRa97Pmo48+0qlTpyxuvXr1cuhYvqCkpMTmY126dNGpU6d09OhRvfjii/rDH/6giRMn1vk4dRUdHa0mTZp4/BiANyA0AU702GOPyWQyafv27brrrrvUoUMHdenSRRkZGdVqSB544AF9/PHHOnHihHnbkiVL9MADDyg4ONi8bcuWLTp37pzeeustXX/99WrdurVSUlL0+9//Xq1bt5Yk/f3vf9eAAQP05JNPqmPHjurQoYOGDx+urKws83FSUlIsQtNnn32mDh06aOjQoRbbN2/erFatWpmPbctvf/tbZWZmqri4uMb9HnnkEX3++edat26dXe9hVc2aNVNcXJzFLSQkRKrSjLRkyRK1bNlSjRo10mOPPaby8nLNmzdPcXFxat68uWbPnm0+nrWakJ9++kkmk8niPajq+++/1y9/+Utdc801ioyMVLdu3fTXv/7V/Pjo0aP18ccf6+WXXzbXBh09elSS9PHHHys5OVlhYWGKj4/X1KlTVVZWZn7uoEGDNH78eE2YMEExMTFKS0uz+V4EBwcrLi5O1157rUaMGKEHHnhA77//vsV78dZbb6l169YKDw83v7Zf/epXuvrqq9W4cWMNHjxYe/futTju3LlzFRsbq6ioKI0dO9ai1lFWmtYqKio0b948tWvXTmFhYWrZsqX5Pa78mbn++utlMpnMtYlXHqO4uFi/+93vzDWnN954o3bs2GF+vLI2Mzs7W71791ZkZKT69++vAwcO2Hx/AHcgNAFO8sMPP2j9+vVKT0+3qCmqdOU37djYWKWlpWn58uWSpKKiIq1cuVJjxoyx2C8uLk5lZWV67733ZGt97bi4OP373//Wv/71L5vlS0lJ0WeffWb+0N60aZMGDRqkgQMHatOmTeb9Nm3apJSUlFpf74QJE1RWVqZXX321xv1at26tRx99VE899ZQqKipqPW5dHDp0SB9++KHWr1+vv/71r3r77bd1++2369tvv9XHH3+sF198UdOnT9cXX3zh8DkuXryoXr16ae3atfrXv/6lRx55RCNHjtT27duly01P/fr107hx48y1YS1atNB//vMf3XbbberTp4/27t2rN954Q2+//baef/55i+MvX75coaGh2rJlixYvXmx3uSIiIixqlA4ePKi//e1vWr16tTkU3nPPPTpz5ow+/PBD7dq1Sz179tTNN9+sH374QZL07rvv6tlnn9ULL7ygnTt3Kj4+Xq+//nqN533qqac0d+5cPfPMM8rNzdVf/vIXxcbGSpL5PamsIVy9erXVY0yePFl/+9vftHz5cu3evVvt2rVTWlqauVyVpk2bpgULFmjnzp0KDg6u9rsBuJ0BwCm++OILQ5KxevXqWvdt1aqV8fvf/95Ys2aN0bZtW6OiosJY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", + "text/plain": [ + "<Figure size 640x480 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "mplhep.histplot(h_bkg, bins, label='Background')\n", + "mplhep.histplot(h_sig, bins, label='Signal')\n", + "plt.semilogy()\n", + "plt.legend()\n", + "plt.xlim(0,1)\n", + "plt.xlabel('CMSSW NN Emulator Prediction')\n", + "plt.ylabel('Frequency')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc0de85f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}