├── LICENSE.txt ├── NNtoP4 ├── .gitignore ├── README.md ├── cmd_txt │ ├── cmd_32_32_32_32_bnn.txt │ ├── cmd_32_32_32_bnn.txt │ ├── cmd_32_32_bnn.txt │ ├── cmd_32_8_32_bnn.txt │ ├── cmd_32_8_bnn.txt │ ├── cmd_8_32_8_bnn.txt │ ├── cmd_8_32_bnn.txt │ ├── cmd_8_8_8_bnn.txt │ └── cmd_8_8_bnn.txt ├── gen_p4.py ├── net_setup.sh ├── nn_utils.py ├── run_p4.sh ├── test_bnn.py ├── tmpl_bnn.p4 └── tmpl_ipv4_src.p4 ├── README.md └── dt_rf_bnn ├── README.md ├── datasets ├── UNSW_IOT │ └── .gitignore └── UNSW_NB15 │ └── .gitignore ├── iot_dataset.ipynb ├── models └── .gitignore └── sec_dataset.ipynb /LICENSE.txt: -------------------------------------------------------------------------------- 1 | SOFTWARE LICENSE AGREEMENT 2 | 3 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 4 | 5 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 6 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 7 | DOWNLOAD THE SOFTWARE. 8 | 9 | This is a license agreement ("Agreement") between your academic institution or 10 | non-profit organization or self (called "Licensee" or "You" in this Agreement) 11 | and NEC Laboratories Europe GmbH (called "Licensor" in this Agreement). All 12 | rights not specifically granted to you in this Agreement are reserved for 13 | Licensor. 14 | 15 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 16 | ownership of any copy of the Software (as defined below) licensed under this 17 | Agreement and hereby grants to Licensee a personal, non-exclusive, 18 | non-transferable license to use the Software for noncommercial research 19 | purposes, without the right to sublicense, pursuant to the terms and conditions 20 | of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF LICENSOR'S PATENT 21 | RIGHTS ARE GRANTED BY THIS LICENSE. As used in this Agreement, the term 22 | "Software" means (i) the actual copy of all or any portion of code for program 23 | routines made accessible to Licensee by Licensor pursuant to this Agreement, 24 | inclusive of backups, updates, and/or merged copies permitted hereunder or 25 | subsequently supplied by Licensor, including all or any file structures, 26 | programming instructions, user interfaces and screen formats and sequences as 27 | well as any and all documentation and instructions related to it, and (ii) all 28 | or any derivatives and/or modifications created or made by You to any of the 29 | items specified in (i). 30 | 31 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 32 | proprietary to Licensor, and as such, Licensee agrees to receive all such 33 | materials and to use the Software only in accordance with the terms of this 34 | Agreement. Licensee agrees to use reasonable effort to protect the Software 35 | from unauthorized use, reproduction, distribution, or publication. All 36 | publication materials mentioning features or use of this software must 37 | explicitly include an acknowledgement the software was developed by NEC 38 | Laboratories Europe GmbH. 39 | 40 | COPYRIGHT: The Software is owned by Licensor. 41 | 42 | PERMITTED USES: The Software may be used for your own noncommercial internal 43 | research purposes. You understand and agree that Licensor is not obligated to 44 | implement any suggestions and/or feedback you might provide regarding the 45 | Software, but to the extent Licensor does so, you are not entitled to any 46 | compensation related thereto. 47 | 48 | DERIVATIVES: You may create derivatives of or make modifications to the 49 | Software, however, You agree that all and any such derivatives and 50 | modifications will be owned by Licensor and become a part of the Software 51 | licensed to You under this Agreement. You may only use such derivatives and 52 | modifications for your own noncommercial internal research purposes, and you 53 | may not otherwise use, distribute or copy such derivatives and modifications in 54 | violation of this Agreement. 55 | 56 | BACKUPS: If Licensee is an organization, it may make that number of copies of 57 | the Software necessary for internal noncommercial use at a single site within 58 | its organization provided that all information appearing in or on the original 59 | labels, including the copyright and trademark notices are copied onto the 60 | labels of the copies. 61 | 62 | USES NOT PERMITTED: You may not distribute, copy or use the Software except as 63 | explicitly permitted herein. Licensee has not been granted any trademark 64 | license as part of this Agreement. Neither the name of NEC Laboratories Europe 65 | GmbH nor the names of its contributors may be used to endorse or promote 66 | products derived from this Software without specific prior written permission. 67 | 68 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 69 | whole or in part, or provide third parties access to prior or present versions 70 | (or any parts thereof) of the Software. 71 | 72 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder without 73 | the prior written consent of Licensor. Any attempted assignment without such 74 | consent shall be null and void. 75 | 76 | TERM: The term of the license granted by this Agreement is from Licensee's 77 | acceptance of this Agreement by downloading the Software or by using the 78 | Software until terminated as provided below. 79 | 80 | The Agreement automatically terminates without notice if you fail to comply 81 | with any provision of this Agreement. Licensee may terminate this Agreement by 82 | ceasing using the Software. Upon any termination of this Agreement, Licensee 83 | will delete any and all copies of the Software. You agree that all provisions 84 | which operate to protect the proprietary rights of Licensor shall remain in 85 | force should breach occur and that the obligation of confidentiality described 86 | in this Agreement is binding in perpetuity and, as such, survives the term of 87 | the Agreement. 88 | 89 | FEE: Provided Licensee abides completely by the terms and conditions of this 90 | Agreement, there is no fee due to Licensor for Licensee's use of the Software 91 | in accordance with this Agreement. 92 | 93 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY OF 94 | ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS 95 | FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE BEARS ALL 96 | RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND RELATED MATERIALS. 97 | 98 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 99 | provided as part of this Agreement. 100 | 101 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent permitted 102 | under applicable law, Licensor shall not be liable for direct, indirect, 103 | special, incidental, or consequential damages or lost profits related to 104 | Licensee's use of and/or inability to use the Software, even if Licensor is 105 | advised of the possibility of such damage. 106 | 107 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable export 108 | control laws, regulations, and/or other laws related to embargoes and sanction 109 | programs administered by law. 110 | 111 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 112 | invalid, illegal, or unenforceable by a court or other tribunal of competent 113 | jurisdiction, the validity, legality and enforceability of the remaining 114 | provisions shall not in any way be affected or impaired thereby. 115 | 116 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right or 117 | remedy under this Agreement shall be construed as a waiver of any future or 118 | other exercise of such right or remedy by Licensor. 119 | 120 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 121 | with the laws of Germany without reference to conflict of laws principles. You 122 | consent to the personal jurisdiction of the courts of this country and waive 123 | their rights to venue outside of Germany. 124 | 125 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and entire 126 | agreement between Licensee and Licensor as to the matter set forth herein and 127 | supersedes any previous agreements, understandings, and arrangements between 128 | the parties relating hereto. 129 | 130 | -------------------------------------------------------------------------------- /NNtoP4/.gitignore: -------------------------------------------------------------------------------- 1 | out.p4 2 | out.p4i 3 | out.json 4 | -------------------------------------------------------------------------------- /NNtoP4/README.md: -------------------------------------------------------------------------------- 1 | # Requirements (tested on Ubuntu 20.04.3 LTS) 2 | 3 | ``` 4 | sudo apt update 5 | sudo apt install -y python3-pip curl 6 | pip install scapy 7 | ``` 8 | 9 | Install BMv2 (https://github.com/p4lang/behavioral-model) 10 | ``` 11 | git clone https://github.com/p4lang/behavioral-model.git 12 | cd behavioral-model 13 | ./install_deps.sh 14 | ./autogen.sh 15 | ./configure 16 | make 17 | sudo make install 18 | ``` 19 | 20 | Install P4 compiler (https://github.com/p4lang/p4c) 21 | ``` 22 | . /etc/os-release 23 | echo "deb http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/home:p4lang.list 24 | curl -L "http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_${VERSION_ID}/Release.key" | sudo apt-key add - 25 | sudo apt-get update 26 | sudo apt install -y p4lang-p4c 27 | 28 | ``` 29 | 30 | # gen_p4.py 31 | 32 | This script generates a p4_16 program for the execution of a Binarized Neural 33 | Network (BNN), on a bmv2 target. When the switch receives a packet that contains 34 | a BNN input, it reads the input value from a packet header field, performs the 35 | network execution and writes back to a packet header field the result of the s 36 | computation. The packet is then forwarded according to the switch configuration. 37 | 38 | To combine the BNN processing with regular switch operations, the user of this 39 | script should provide a P4_16 program template, which contains all the 40 | statements for the networking pipeline description and a set of custom 41 | annotations that are interpreted to introduce the handling of BNNs. 42 | 43 | We provide two template examples. 44 | 45 | In a first example, contained in `tmpl_bnn.p4`, a BNN packet is an ethernet 46 | packet with `ETH_TYPE` 0x2323 followed by a 32b custom header. 47 | ``` 48 | xx:xx:xx:xx:xx:xx || xx:xx:xx:xx:xx:xx || 0x2323 || 0xXXXXXXXX 49 | MAC_DST MAC_SRC ETH_TYPE BNN 50 | ``` 51 | The switch executes the network as soon as the packet is received, and provides 52 | the result by forwarding back the packet to the sender. The packet has the 53 | MAC addresses swapped, so that the sender can receive it, and the result of the 54 | network inference written in the BNN field. 55 | 56 | The second example, contained in `tmpl_ipv4_src.p4`, encodes in the IPv4 source 57 | address the BNN input. The reply packet coming out from the switch has both 58 | the MAC and IP addresses swapped, with the IPv4 destination address rewritten 59 | to contain the inference result. I.e., the IPv4 destination address is used 60 | in place of the custom BNN header in this case. 61 | 62 | 63 | The BNN description is provided as a comma-separated list of number of neurons. 64 | The numbers represent the ordered number of neurons of the BNN. 65 | 66 | For example the command 67 | ``` 68 | ./gen_p4.py -n 32,8,32 -t tmpl_bnn.p4 69 | ``` 70 | generates a P4 71 | program that implements a BNN with an input layer of 32 neurons, a hidden layer 72 | of 8 neurons and an output layers of 32 neurons, whose input/output is 73 | read/written from/to the custom BNN header field. 74 | 75 | If not specified otherwise, the script generates the p4 code in the `out.p4` file. 76 | 77 | ``` 78 | usage: gen_p4.py [-h] -n NN_DESC -t TEMPLATE [-o OUT_FILE] 79 | 80 | optional arguments: 81 | -h, --help show this help message and exit 82 | -n NN_DESC, --nn_desc NN_DESC 83 | NN description (comma-separated list of number of 84 | neurons) 85 | -t TEMPLATE, --template TEMPLATE 86 | p4 template file (e.g. tmpl_bnn.p4 or 87 | tmpl_ipv4_src.p4) 88 | -o OUT_FILE, --out_file OUT_FILE 89 | p4 output file 90 | ``` 91 | 92 | # test_bnn.py 93 | 94 | This script generates a packet with the NN input specified by the user, sends it 95 | to the switch and verifies if the NN output read from the reply packet is 96 | correct. 97 | 98 | To verify the output of the NN, the user has to specify the set of weights in 99 | the `weights()` method of `test_bnn.py` and provide the proper txt file to configure 100 | the flow entries (examples can be found in the `cmd_txt` folder). 101 | 102 | ``` 103 | usage: test_bnn.py [-h] -n NN_DESC -f {bnn,ipv4_src} -i NN_INPUT 104 | 105 | optional arguments: 106 | -h, --help show this help message and exit 107 | -n NN_DESC, --nn_desc NN_DESC 108 | NN description 109 | -f {bnn,ipv4_src}, --header_field {bnn,ipv4_src} 110 | packet header field 111 | -i NN_INPUT, --nn_input NN_INPUT 112 | NN input 113 | ``` 114 | 115 | Before running the two examples below, once after each boot, the following command 116 | is required to configure the virtual ethernet interfaces. 117 | ``` 118 | sudo ./net_setup.sh add 119 | ``` 120 | 121 | ## Example 1 122 | 123 | Generate the P4 code 124 | ``` 125 | ./gen_p4.py -n 32,8,32 -t tmpl_bnn.p4 126 | ``` 127 | 128 | Notice: to support the encoding of a BNN input in a header field that is larger 129 | than the actual BNN input, or to encode only a portion of the results in the 130 | output field, the script asks if the size of the input/output header field is 131 | bigger/smaller/equal than the input/output size of the BNN. This generates 132 | the proper slicing when reading/writing from/to the header fields. 133 | The second example provides a clarifying case of this. 134 | 135 | In this first example, you should type `=` twice, since no slicing is needed. 136 | 137 | Further custom pre/post processing can be added by modifying `get_nn_input()` 138 | and `get_nn_output()` actions from the generated `out.p4` file. 139 | The output of the BNN can be written to a different header field, 140 | but the `test_bnn.py` script would not able to verify the results. 141 | 142 | Run the bmv2 switch and load the `out.p4` code with 143 | ``` 144 | sudo ./run_p4.sh out 145 | ``` 146 | 147 | From a second terminal, load the flow entries with the BNN weights 148 | ``` 149 | sudo simple_switch_CLI < cmd_txt/cmd_32_8_32_bnn.txt 150 | ``` 151 | 152 | Create a test packet and verify the BNN computation 153 | ``` 154 | sudo ./test_bnn.py -n 32,8,32 -f bnn -i 0x8000 155 | ``` 156 | 157 | When using BNN header field, the NN input has to be specified as a 158 | hexadecimal number. 159 | When using IPv4 source address, the NN input has to be specified with 160 | dot-decimal notation. 161 | 162 | NB: the input/output is automatically truncated to match the 163 | BNN input/output (and the user is warned about it!) 164 | 165 | ## Example 2 166 | 167 | Generate the P4 code 168 | ``` 169 | ./gen_p4.py -n 8,8,8 -t tmpl_ipv4_src.p4 170 | ``` 171 | 172 | Since the IPv4 address is bigger (32 bits) than the 173 | BNN input and output (8 bits) you have to reply twice with `>`. 174 | 175 | In this way the generated p4 file already read/write from the 8 176 | LSB of the IPv4 address. 177 | The user can customize the slicing by manually editing the generated p4 file. 178 | 179 | Run the bmv2 switch and load the `out.p4` code with 180 | ``` 181 | sudo ./run_p4.sh out 182 | ``` 183 | 184 | From a second terminal, load the flow entries with the BNN weights 185 | ``` 186 | sudo simple_switch_CLI < cmd_txt/cmd_8_8_8_bnn.txt 187 | ``` 188 | 189 | Create a test packet and verify the BNN computation 190 | ``` 191 | sudo ./test_bnn.py -n 8,8,8 -f ipv4_src -i 128.0.0.0 192 | ``` 193 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_32_32_32_32_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_32_32 2 | table_add l1_xor_table xor_32_32 => 0x76ced201 0xc12e8fcd 0xf28a043b 0xb6794bea 0x2f4a4018 0x89ea24ea 0xfc615308 0x1622052f 0x739db96 0x3f6100ed 0x9b304f19 0x460623a1 0xd21478d 0x4d14d0b 0xcae57470 0x8c3f42 0xa364d18 0x3560ffb6 0x70ce8213 0xb3382e2f 0x280379c1 0xc85f445b 0x9ef2184 0x9412630d 0x1ef7d6f1 0x9e4d997f 0x6e598c54 0xd6c57dea 0x29d1af7e 0xb0dae2c9 0x310d4941 0xec6aa1db 3 | table_set_default l2_xor_table xor_32_32 4 | table_add l2_xor_table xor_32_32 => 0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 0x435a9cb8 0x10606d4a 0xd0269cd3 0x41e8174d 0x9a91a923 0x93a1161d 0xc6b580b7 0xc967049 0xd1f518eb 0x20553b50 0x27efdab3 0x98485a1c 0x2370fe70 0x14e2c158 0x6e0f238f 0xf942a305 0xf50d4088 0x212b2db4 0x9bcf06d8 0x50b36bf1 0xe62403f7 0xb59e59f 0x16eebedc 0xfbd9a663 5 | table_set_default l3_xor_table xor_32_32 6 | table_add l3_xor_table xor_32_32 => 0x1680d952 0x1ab08c42 0xa9b1c67f 0x337c40e3 0x15a07afe 0x6b8d5534 0x8805de23 0x20469baf 0x3f9c28b7 0x83899d82 0x323566b4 0xcef168c0 0x9ef1724a 0x8bb0f056 0xa743bb41 0x28b9fc77 0xc9eccaf7 0x85b1dbe3 0x86747c76 0xbd9f8977 0x9b945aa6 0x11c96e82 0xac054462 0x33d1efbf 0xf2860164 0x9487593f 0x26a3116a 0xa6d3096d 0x71808ef3 0x1b55d542 0x448cc470 0x2c95db63 7 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_32_32_32_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_32_32 2 | table_add l1_xor_table xor_32_32 => 0x76ced201 0xc12e8fcd 0xf28a043b 0xb6794bea 0x2f4a4018 0x89ea24ea 0xfc615308 0x1622052f 0x739db96 0x3f6100ed 0x9b304f19 0x460623a1 0xd21478d 0x4d14d0b 0xcae57470 0x8c3f42 0xa364d18 0x3560ffb6 0x70ce8213 0xb3382e2f 0x280379c1 0xc85f445b 0x9ef2184 0x9412630d 0x1ef7d6f1 0x9e4d997f 0x6e598c54 0xd6c57dea 0x29d1af7e 0xb0dae2c9 0x310d4941 0xec6aa1db 3 | table_set_default l2_xor_table xor_32_32 4 | table_add l2_xor_table xor_32_32 => 0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 0x435a9cb8 0x10606d4a 0xd0269cd3 0x41e8174d 0x9a91a923 0x93a1161d 0xc6b580b7 0xc967049 0xd1f518eb 0x20553b50 0x27efdab3 0x98485a1c 0x2370fe70 0x14e2c158 0x6e0f238f 0xf942a305 0xf50d4088 0x212b2db4 0x9bcf06d8 0x50b36bf1 0xe62403f7 0xb59e59f 0x16eebedc 0xfbd9a663 5 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_32_32_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_32_32 2 | table_add l1_xor_table xor_32_32 => 0x76ced201 0xc12e8fcd 0xf28a043b 0xb6794bea 0x2f4a4018 0x89ea24ea 0xfc615308 0x1622052f 0x739db96 0x3f6100ed 0x9b304f19 0x460623a1 0xd21478d 0x4d14d0b 0xcae57470 0x8c3f42 0xa364d18 0x3560ffb6 0x70ce8213 0xb3382e2f 0x280379c1 0xc85f445b 0x9ef2184 0x9412630d 0x1ef7d6f1 0x9e4d997f 0x6e598c54 0xd6c57dea 0x29d1af7e 0xb0dae2c9 0x310d4941 0xec6aa1db 3 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_32_8_32_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_32_8 2 | table_add l1_xor_table xor_32_8 => 0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 3 | table_set_default l2_xor_table xor_8_32 4 | table_add l2_xor_table xor_8_32 => 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 5 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_32_8_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_32_8 2 | table_add l1_xor_table xor_32_8 => 0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 3 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_8_32_8_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_8_32 2 | table_add l1_xor_table xor_8_32 => 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 3 | table_set_default l2_xor_table xor_32_8 4 | table_add l2_xor_table xor_32_8 => 0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 5 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_8_32_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_8_32 2 | table_add l1_xor_table xor_8_32 => 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 3 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_8_8_8_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_8_8 2 | table_add l1_xor_table xor_8_8 => 0xa0 0xb1 0xc2 0xd3 0xe4 0xf5 0x06 0x17 3 | table_set_default l2_xor_table xor_8_8 4 | table_add l2_xor_table xor_8_8 => 0xa0 0xb1 0xc2 0xd3 0xe4 0xf5 0x06 0x17 5 | -------------------------------------------------------------------------------- /NNtoP4/cmd_txt/cmd_8_8_bnn.txt: -------------------------------------------------------------------------------- 1 | table_set_default l1_xor_table xor_8_8 2 | table_add l1_xor_table xor_8_8 => 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 3 | -------------------------------------------------------------------------------- /NNtoP4/gen_p4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | ''' 4 | N3IC - NSDI 2022 5 | 6 | File: gen_p4.py 7 | Authors: Davide Sanvito (Davide.Sanvito@neclab.eu) 8 | Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu) 9 | Roberto Bifulco (Roberto.Bifulco@neclab.eu) 10 | 11 | NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved. 12 | 13 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 14 | 15 | PROPRIETARY INFORMATION --- 16 | 17 | SOFTWARE LICENSE AGREEMENT 18 | 19 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 20 | 21 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 22 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 23 | DOWNLOAD THE SOFTWARE. 24 | 25 | This is a license agreement ("Agreement") between your academic institution 26 | or non-profit organization or self (called "Licensee" or "You" in this 27 | Agreement) and NEC Laboratories Europe GmbH (called "Licensor" in this 28 | Agreement). All rights not specifically granted to you in this Agreement 29 | are reserved for Licensor. 30 | 31 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 32 | ownership of any copy of the Software (as defined below) licensed under this 33 | Agreement and hereby grants to Licensee a personal, non-exclusive, 34 | non-transferable license to use the Software for noncommercial research 35 | purposes, without the right to sublicense, pursuant to the terms and 36 | conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF 37 | LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this 38 | Agreement, the term "Software" means (i) the actual copy of all or any 39 | portion of code for program routines made accessible to Licensee by Licensor 40 | pursuant to this Agreement, inclusive of backups, updates, and/or merged 41 | copies permitted hereunder or subsequently supplied by Licensor, including 42 | all or any file structures, programming instructions, user interfaces and 43 | screen formats and sequences as well as any and all documentation and 44 | instructions related to it, and (ii) all or any derivatives and/or 45 | modifications created or made by You to any of the items specified in (i). 46 | 47 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 48 | proprietary to Licensor, and as such, Licensee agrees to receive all such 49 | materials and to use the Software only in accordance with the terms of this 50 | Agreement. Licensee agrees to use reasonable effort to protect the Software 51 | from unauthorized use, reproduction, distribution, or publication. All 52 | publication materials mentioning features or use of this software must 53 | explicitly include an acknowledgement the software was developed by NEC 54 | Laboratories Europe GmbH. 55 | 56 | COPYRIGHT: The Software is owned by Licensor. 57 | 58 | PERMITTED USES: The Software may be used for your own noncommercial 59 | internal research purposes. You understand and agree that Licensor is not 60 | obligated to implement any suggestions and/or feedback you might provide 61 | regarding the Software, but to the extent Licensor does so, you are not 62 | entitled to any compensation related thereto. 63 | 64 | DERIVATIVES: You may create derivatives of or make modifications to the 65 | Software, however, You agree that all and any such derivatives and 66 | modifications will be owned by Licensor and become a part of the Software 67 | licensed to You under this Agreement. You may only use such derivatives and 68 | modifications for your own noncommercial internal research purposes, and you 69 | may not otherwise use, distribute or copy such derivatives and modifications 70 | in violation of this Agreement. 71 | 72 | BACKUPS: If Licensee is an organization, it may make that number of copies 73 | of the Software necessary for internal noncommercial use at a single site 74 | within its organization provided that all information appearing in or on the 75 | original labels, including the copyright and trademark notices are copied 76 | onto the labels of the copies. 77 | 78 | USES NOT PERMITTED: You may not distribute, copy or use the Software except 79 | as explicitly permitted herein. Licensee has not been granted any trademark 80 | license as part of this Agreement. Neither the name of NEC Laboratories 81 | Europe GmbH nor the names of its contributors may be used to endorse or 82 | promote products derived from this Software without specific prior written 83 | permission. 84 | 85 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 86 | whole or in part, or provide third parties access to prior or present 87 | versions (or any parts thereof) of the Software. 88 | 89 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder 90 | without the prior written consent of Licensor. Any attempted assignment 91 | without such consent shall be null and void. 92 | 93 | TERM: The term of the license granted by this Agreement is from Licensee's 94 | acceptance of this Agreement by downloading the Software or by using the 95 | Software until terminated as provided below. 96 | 97 | The Agreement automatically terminates without notice if you fail to comply 98 | with any provision of this Agreement. Licensee may terminate this Agreement 99 | by ceasing using the Software. Upon any termination of this Agreement, 100 | Licensee will delete any and all copies of the Software. You agree that all 101 | provisions which operate to protect the proprietary rights of Licensor shall 102 | remain in force should breach occur and that the obligation of 103 | confidentiality described in this Agreement is binding in perpetuity and, as 104 | such, survives the term of the Agreement. 105 | 106 | FEE: Provided Licensee abides completely by the terms and conditions of this 107 | Agreement, there is no fee due to Licensor for Licensee's use of the 108 | Software in accordance with this Agreement. 109 | 110 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY 111 | OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR 112 | FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE 113 | BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND 114 | RELATED MATERIALS. 115 | 116 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 117 | provided as part of this Agreement. 118 | 119 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent 120 | permitted under applicable law, Licensor shall not be liable for direct, 121 | indirect, special, incidental, or consequential damages or lost profits 122 | related to Licensee's use of and/or inability to use the Software, even if 123 | Licensor is advised of the possibility of such damage. 124 | 125 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 126 | export control laws, regulations, and/or other laws related to embargoes and 127 | sanction programs administered by law. 128 | 129 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 130 | invalid, illegal, or unenforceable by a court or other tribunal of competent 131 | jurisdiction, the validity, legality and enforceability of the remaining 132 | provisions shall not in any way be affected or impaired thereby. 133 | 134 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right 135 | or remedy under this Agreement shall be construed as a waiver of any future 136 | or other exercise of such right or remedy by Licensor. 137 | 138 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 139 | with the laws of Germany without reference to conflict of laws principles. 140 | You consent to the personal jurisdiction of the courts of this country and 141 | waive their rights to venue outside of Germany. 142 | 143 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and 144 | entire agreement between Licensee and Licensor as to the matter set forth 145 | herein and supersedes any previous agreements, understandings, and 146 | arrangements between the parties relating hereto. 147 | 148 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 149 | ''' 150 | 151 | import argparse 152 | import fileinput 153 | import math 154 | from shutil import copyfile 155 | 156 | class FcLayer: 157 | 158 | def __init__(self, layer_size, layer_id, output_size, next_out_size): 159 | 160 | self.layer_size = layer_size 161 | self.layer_id = layer_id 162 | self.output_size = output_size 163 | self.p4code = '' 164 | self.next_out_size = next_out_size 165 | 166 | def gen_fold(self): 167 | s = '\taction l%d_fold(){\n' % self.layer_id 168 | for w in range(self.output_size): 169 | s += '\t\tmeta.meta%d_%d.x1_0[%d:%d] = meta.meta%d_%d.x%d_0[0:0];\n' %(self.output_size, self.next_out_size, self.output_size-w-1, self.output_size-w-1, self.layer_size, self.output_size, w+1 ) 170 | s += '\t}\n\n' 171 | return s 172 | 173 | def gen_l_xor_table(self): 174 | s = '\ttable l%d_xor_table {\n' %(self.layer_id) 175 | s += '\t\tactions = { xor_%d_%d; NoAction; } \n\t\tdefault_action = NoAction();\n\t}\n\n' % (self.layer_size, self.output_size) 176 | 177 | return s 178 | 179 | def gen_l_popcount(self): 180 | s = '' 181 | 182 | s += '\taction l%d_popcount(){\n' % (self.layer_id) 183 | 184 | for i in range(int(math.log(self.layer_size,2))): 185 | s += '\t\tcpy_%d_%d();\n' % (self.layer_size, self.output_size) 186 | s += '\t\tstep_pop_%d_%d(m%d_%d,%d);\n' % (self.layer_size, self.output_size,2**i ,self.layer_size, 2**i) 187 | s += '\t\tsum_%d_%d();\n' %(self.layer_size, self.output_size) 188 | 189 | s += '\t\tsign_%d_%d();\n' % (self.layer_size, self.output_size) 190 | s += '\t\tl%d_fold();\n' % (self.layer_id) 191 | s += '\t\tmcpy_%d_%d();\n' % (self.output_size, self.next_out_size) 192 | s += '\t}\n\n' 193 | 194 | return s 195 | 196 | def gen_l_popcount_table(self): 197 | s = '\ttable l%d_popcount_table {\n' %(self.layer_id) 198 | s += '\t\tactions = { l%d_popcount; } \n\t\tdefault_action = l%d_popcount();\n\t}\n\n' % (self.layer_id, self.layer_id) 199 | return s 200 | 201 | 202 | class MLP: 203 | 204 | # TODO net_desc=hidden_layers_neurons, output_size=last_layer_neurons 205 | def __init__(self, input_size, net_desc, output_size, template, outname): 206 | 207 | self.POP_CONST = '==POP_CONST==' 208 | self.BNN_META_T = '==BNN_META_T==' 209 | self.BNN_ACT = '==BNN_ACT==' 210 | self.BNN_NN_IN = '==BNN_NN_IN==' 211 | self.BNN_NN_OUT = '==BNN_NN_OUT==' 212 | self.BNN_TAB = '==BNN_TAB==' 213 | self.BNN_APPLY = '==BNN_APPLY==' 214 | 215 | self.template = template 216 | self.input_size = input_size 217 | self.output_size = output_size 218 | self.net_desc = net_desc 219 | self.p4code = '' 220 | self.layers = [] 221 | self.outname = outname 222 | self.sizes = [input_size] + net_desc + [output_size] 223 | self.size_pairs = list(zip(self.sizes, self.sizes[1:])) 224 | self.meta_sizes_pairs = set() 225 | for pair in self.size_pairs: 226 | self.meta_sizes_pairs.add(tuple(pair)) 227 | self.meta_sizes_pairs.add((output_size, output_size)) 228 | self.meta_sizes_pairs = list(self.meta_sizes_pairs) 229 | 230 | assert self.input_size in [8, 16, 32, 64], 'Input size not supported' 231 | assert self.output_size in [8, 16, 32, 64], 'Output size not supported' 232 | for l in self.net_desc: 233 | assert l in [8, 16, 32, 64], 'Layer size not supported' 234 | assert max([input_size, output_size] + net_desc) <= 64, 'Popcount for layer size > 64 is not implemented' 235 | 236 | copyfile(template, outname) 237 | 238 | # const 239 | 240 | self.p4code += self.gen_step_pop_const() 241 | self.add_to_template(self.POP_CONST, self.gen_step_pop_const()) 242 | 243 | # meta 244 | 245 | self.p4code += self.gen_meta_hdr() 246 | self.add_to_template(self.BNN_META_T, self.gen_meta_hdr()) 247 | 248 | # action 249 | 250 | actions = '' 251 | actions += self.gen_xor() 252 | actions += self.gen_step_pop() 253 | actions += self.gen_sum() 254 | actions += self.gen_sign() 255 | actions += self.gen_cpy() 256 | actions += self.gen_mcpy() 257 | 258 | self.p4code += self.gen_xor() 259 | self.p4code += self.gen_step_pop() 260 | self.p4code += self.gen_sum() 261 | self.p4code += self.gen_sign() 262 | self.p4code += self.gen_cpy() 263 | self.p4code += self.gen_mcpy() 264 | 265 | # create layers 266 | 267 | if len(self.net_desc) > 0: 268 | self.layers.append(FcLayer(self.input_size, 1, self.net_desc[0], self.sizes[2])) 269 | for layer_id, (layer_size, output_size) in enumerate(zip(self.net_desc, self.net_desc[1:])): 270 | self.layers.append(FcLayer(layer_size, layer_id + 2, output_size, self.sizes[layer_id + 3])) 271 | self.layers.append(FcLayer(self.net_desc[-1], len(self.net_desc) + 1, self.output_size, self.output_size)) 272 | else: 273 | self.layers.append(FcLayer(self.input_size, 1, self.output_size, self.output_size)) 274 | 275 | # per layer action 276 | 277 | for l in self.layers: 278 | actions += l.gen_fold() 279 | actions += l.gen_l_popcount() 280 | self.p4code += l.gen_fold() 281 | self.p4code += l.gen_l_popcount() 282 | 283 | self.add_to_template(self.BNN_ACT, actions) 284 | 285 | # user actions 286 | 287 | code = self.gen_get_nn_input() 288 | self.p4code += code 289 | self.add_to_template(self.BNN_NN_IN, code) 290 | code = self.gen_get_nn_output() 291 | self.p4code += code 292 | self.add_to_template(self.BNN_NN_OUT, code) 293 | 294 | # per layer tables 295 | 296 | tables = '' 297 | 298 | for l in self.layers: 299 | tables += l.gen_l_xor_table() 300 | tables += l.gen_l_popcount_table() 301 | self.p4code += l.gen_l_xor_table() 302 | self.p4code += l.gen_l_popcount_table() 303 | 304 | self.add_to_template(self.BNN_TAB, tables) 305 | 306 | # apply block 307 | 308 | self.p4code += self.gen_mpl_apply_list() 309 | self.add_to_template(self.BNN_APPLY,self.gen_mpl_apply_list()) 310 | 311 | def add_to_template(self, placeholder, code): 312 | with fileinput.FileInput(self.outname, inplace=True) as file: 313 | for line in file: 314 | print(line.replace(placeholder, code), end='') 315 | 316 | def gen_meta_hdr(self): 317 | s = '' 318 | # gen metadata fields for each layer size in nn 319 | for inp,out in self.meta_sizes_pairs: 320 | s += 'struct meta%d_%d_t {\n' % (inp,out) 321 | for i in range(1, out + 1): 322 | s += '\tbit<%d> x%d_0;\n' % (inp, i) 323 | s += '\tbit<%d> x%d_1;\n' % (inp, i) 324 | s += '}\n\n' 325 | s += 'struct metadata {\n' 326 | 327 | for inp,out in self.meta_sizes_pairs: 328 | s += '\tmeta%d_%d_t meta%d_%d;\n' % (inp, out, inp, out) 329 | 330 | s += '}\n\n' 331 | return s 332 | 333 | def gen_step_pop_const(self): 334 | s = '' 335 | 336 | for size in sorted(list(set([self.input_size, self.output_size] + self.net_desc))): 337 | 338 | if (size == 8): 339 | s += 'const bit<8> m1_8 = 0x55;\n' 340 | s += 'const bit<8> m2_8 = 0x33;\n' 341 | s += 'const bit<8> m4_8 = 0x0f;\n' 342 | elif (size == 16): 343 | s += 'const bit<16> m1_16 = 0x5555;\n' 344 | s += 'const bit<16> m2_16 = 0x3333;\n' 345 | s += 'const bit<16> m4_16 = 0x0f0f;\n' 346 | s += 'const bit<16> m8_16 = 0x00ff;\n' 347 | elif (size == 32): 348 | s += 'const bit<32> m1_32 = 0x55555555;\n' 349 | s += 'const bit<32> m2_32 = 0x33333333;\n' 350 | s += 'const bit<32> m4_32 = 0x0f0f0f0f;\n' 351 | s += 'const bit<32> m8_32 = 0x00ff00ff;\n' 352 | s += 'const bit<32> m16_32 = 0x0000ffff;\n' 353 | elif (size == 64): 354 | s += 'const bit<64> m1_64 = 0x5555555555555555;\n' 355 | s += 'const bit<64> m2_64 = 0x3333333333333333;\n' 356 | s += 'const bit<64> m4_64 = 0x0f0f0f0f0f0f0f0f;\n' 357 | s += 'const bit<64> m8_64 = 0x00ff00ff00ff00ff;\n' 358 | s += 'const bit<64> m16_64 = 0x0000ffff0000ffff;\n' 359 | s += 'const bit<64> m32_64 = 0x00000000ffffffff;\n' 360 | 361 | s += '\n' 362 | return s 363 | 364 | def gen_step_pop(self): 365 | s = '' 366 | 367 | for inp,out in self.meta_sizes_pairs: 368 | s += '\taction step_pop_%d_%d(bit<%d> m, bit<8> s){\n' % (inp, out, inp) 369 | 370 | for i in range(1, out + 1): 371 | s += '\t\tmeta.meta%d_%d.x%d_0 = (meta.meta%d_%d.x%d_0 & m);\n' % (inp, out, i, inp, out, i) 372 | s += '\t\tmeta.meta%d_%d.x%d_1 = ((meta.meta%d_%d.x%d_1 >> s) & m);\n' % (inp, out, i, inp, out, i) 373 | 374 | s += '\t}\n\n' 375 | 376 | return s 377 | 378 | def gen_xor(self): 379 | s = '' 380 | 381 | for inp,out in self.meta_sizes_pairs: 382 | s += '\taction xor_%d_%d(' % (inp, out) 383 | s += ', '.join(['bit<%d> w_%d' % (inp, w) for w in range(1, out+1)]) 384 | s += '){\n' 385 | for w in range(1, out+1): 386 | s += '\t\tmeta.meta%d_%d.x%d_0 = (meta.meta%d_%d.x%d_0 ^ w_%d);\n' %(inp, out, w, inp, out, w, w) 387 | s += '\t}\n\n' 388 | return s 389 | 390 | def gen_cpy(self): 391 | s = '' 392 | 393 | for inp,out in self.meta_sizes_pairs: 394 | s += '\taction cpy_%d_%d(){\n' % (inp, out) 395 | 396 | for i in range(1, out + 1): 397 | s += '\t\tmeta.meta%d_%d.x%d_1 = meta.meta%d_%d.x%d_0;\n' % (inp, out, i, inp, out, i) 398 | s += '\t}\n\n' 399 | 400 | return s 401 | 402 | def gen_mcpy(self): 403 | s = '' 404 | 405 | for inp,out in self.meta_sizes_pairs: 406 | s += '\taction mcpy_%d_%d(){\n' % (inp, out) 407 | 408 | for i in range(1, out + 1): 409 | if i > 1: 410 | s += '\t\tmeta.meta%d_%d.x%d_0 = meta.meta%d_%d.x1_0;\n' % (inp, out, i, inp, out) 411 | s += '\t\tmeta.meta%d_%d.x%d_1 = meta.meta%d_%d.x1_0;\n' % (inp, out, i, inp, out) 412 | s += '\t}\n\n' 413 | 414 | return s 415 | 416 | def gen_sum(self): 417 | s = '' 418 | 419 | for inp,out in self.meta_sizes_pairs: 420 | s += '\taction sum_%d_%d(){\n' % (inp, out) 421 | 422 | for i in range(1, out + 1): 423 | s += '\t\tmeta.meta%d_%d.x%d_0 = (meta.meta%d_%d.x%d_0 + meta.meta%d_%d.x%d_1);\n' % (inp, out, i, inp, out, i, inp, out, i) 424 | s += '\t}\n\n' 425 | 426 | return s 427 | 428 | def gen_sign(self): 429 | s = '' 430 | 431 | for inp,out in self.meta_sizes_pairs: 432 | s += '\taction sign_%d_%d(){\n' % (inp, out) 433 | 434 | for i in range(1, out + 1): 435 | s += '\t\tif (meta.meta%d_%d.x%d_0 >= %d) \n\t\t\tmeta.meta%d_%d.x%d_0 = 0;\n' % (inp, out, i, inp/2, inp, out, i) 436 | s += '\t\telse \n\t\t\tmeta.meta%d_%d.x%d_0 = 1;\n' % (inp, out, i) 437 | 438 | s += '\t}\n\n' 439 | 440 | return s 441 | 442 | def gen_mpl_apply_list(self): 443 | s = '' 444 | 445 | for l in self.layers: 446 | s += '\t\tl%d_xor_table.apply();\n' % l.layer_id 447 | s += '\t\tl%d_popcount_table.apply();\n' % l.layer_id 448 | 449 | return s 450 | 451 | def gen_sign(self): 452 | s = '' 453 | 454 | for inp,out in self.meta_sizes_pairs: 455 | s += '\taction sign_%d_%d(){\n' % (inp, out) 456 | 457 | for i in range(1, out + 1): 458 | s += '\t\tif (meta.meta%d_%d.x%d_0 >= %d) \n\t\t\tmeta.meta%d_%d.x%d_0 = 0;\n' % (inp, out, i, inp/2, inp, out, i) 459 | s += '\t\telse \n\t\t\tmeta.meta%d_%d.x%d_0 = 1;\n' % (inp, out, i) 460 | 461 | s += '\t}\n\n' 462 | 463 | return s 464 | 465 | def gen_get_nn_input(self): 466 | s = '' 467 | 468 | header = 'hdr.bnn_pkt.x' if self.template == 'tmpl_bnn.p4' else 'hdr.ipv4.srcAddr' 469 | inp, out = self.size_pairs[0] 470 | s += '\taction get_nn_input(){\n' 471 | s += '\t\t//Here we can select the input features vector from packet header.\n' 472 | reply = '' 473 | while reply not in ['>', '<', '=']: 474 | reply = input('The \033[1mNN input\033[0m header field is ... than %d bits. [>,<,=]? ' % inp)[:1] 475 | if reply == '>': 476 | s += '\t\tmeta.meta%d_%d.x1_0 = %s[%d:0];\n\n' % (inp, out, header, inp-1) 477 | elif reply == '<': 478 | s += '\t\tmeta.meta%d_%d.x1_0[%d:0] = %s;\n\n' % (inp, out, inp-1, header) 479 | else: 480 | s += '\t\tmeta.meta%d_%d.x1_0 = %s;\n\n' % (inp, out, header) 481 | s += '\t\t//copy meta.meta%d_%d.x1_0 into meta.meta%d_%d.x**_0 and meta.meta%d_%d.x**_1\n' % (inp, out, inp, out, inp, out) 482 | s += '\t\tmcpy_%d_%d();\n' % (inp, out) 483 | s += '\t}\n\n' 484 | 485 | return s 486 | 487 | def gen_get_nn_output(self): 488 | s = '' 489 | 490 | header = 'hdr.bnn_pkt.x' if self.template == 'tmpl_bnn.p4' else 'hdr.ipv4.srcAddr' 491 | inp, out = self.size_pairs[-1] 492 | s += '\taction get_nn_output(){\n' 493 | s += '\t\t//Here we can select the destination packet header\n' 494 | reply = '' 495 | while reply not in ['>', '<', '=']: 496 | reply = input('The \033[1mNN output\033[0m header field is ... than %d bits. [>,<,=]? ' % out)[:1] 497 | if reply == '>': 498 | s += '\t\t%s[%d:0] = meta.meta%d_%d.x1_0;\n' % (header, out-1, out, out) 499 | elif reply == '<': 500 | s += '\t\t%s = meta.meta%d_%d.x1_0[%d:0];\n' % (header, out, out, out-1) 501 | else: 502 | s += '\t\t%s = meta.meta%d_%d.x1_0;\n' % (header, out, out) 503 | s += '\t}\n\n' 504 | 505 | return s 506 | 507 | def main(): 508 | 509 | parser = argparse.ArgumentParser() 510 | parser.add_argument('-n','--nn_desc', help='NN description (comma-separated list of number of neurons)', required=True) 511 | parser.add_argument('-t','--template', help='p4 template file (e.g. tmpl_bnn.p4 or tmpl_ipv4_src.p4)', required=True) 512 | parser.add_argument('-o','--out_file', help='p4 output file', required=False) 513 | args = parser.parse_args() 514 | 515 | nn_desc = list(map(int,args.nn_desc.split(','))) 516 | if len(nn_desc) < 2: 517 | print('The NN must have at least 2 layer (including the input)!') 518 | exit() 519 | 520 | if args.out_file is not None: 521 | pass 522 | else: 523 | out_file = 'out.p4' 524 | 525 | mlp = MLP(nn_desc[0], nn_desc[1:-1], nn_desc[-1], args.template, out_file) 526 | #print(mlp.p4code) 527 | print('%s file has been generated' % out_file) 528 | 529 | if __name__ == '__main__': 530 | main() 531 | -------------------------------------------------------------------------------- /NNtoP4/net_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | add(){ 4 | ip link add veth0_a type veth peer name veth0_b 5 | ip l s dev veth0_a address 00:00:00:00:00:0a 6 | ip l s dev veth0_b address 00:00:00:00:00:0b 7 | ip l s veth0_a up 8 | ip l s veth0_b up 9 | 10 | TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash" 11 | /sbin/ethtool --offload veth0_a "$TOE_OPTION" off 12 | /sbin/ethtool --offload veth0_b "$TOE_OPTION" off 13 | sysctl net.ipv6.conf.veth0_a.disable_ipv6=1 14 | sysctl net.ipv6.conf.veth0_b.disable_ipv6=1 15 | } 16 | 17 | del() { 18 | ip l d veth0_a 19 | ip l d veth1_b 20 | } 21 | 22 | $1 23 | -------------------------------------------------------------------------------- /NNtoP4/nn_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | N3IC - NSDI 2022 5 | 6 | File: nn_utils.py 7 | Authors: Davide Sanvito (Davide.Sanvito@neclab.eu) 8 | Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu) 9 | Roberto Bifulco (Roberto.Bifulco@neclab.eu) 10 | 11 | NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved. 12 | 13 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 14 | 15 | PROPRIETARY INFORMATION --- 16 | 17 | SOFTWARE LICENSE AGREEMENT 18 | 19 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 20 | 21 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 22 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 23 | DOWNLOAD THE SOFTWARE. 24 | 25 | This is a license agreement ("Agreement") between your academic institution 26 | or non-profit organization or self (called "Licensee" or "You" in this 27 | Agreement) and NEC Laboratories Europe GmbH (called "Licensor" in this 28 | Agreement). All rights not specifically granted to you in this Agreement 29 | are reserved for Licensor. 30 | 31 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 32 | ownership of any copy of the Software (as defined below) licensed under this 33 | Agreement and hereby grants to Licensee a personal, non-exclusive, 34 | non-transferable license to use the Software for noncommercial research 35 | purposes, without the right to sublicense, pursuant to the terms and 36 | conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF 37 | LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this 38 | Agreement, the term "Software" means (i) the actual copy of all or any 39 | portion of code for program routines made accessible to Licensee by Licensor 40 | pursuant to this Agreement, inclusive of backups, updates, and/or merged 41 | copies permitted hereunder or subsequently supplied by Licensor, including 42 | all or any file structures, programming instructions, user interfaces and 43 | screen formats and sequences as well as any and all documentation and 44 | instructions related to it, and (ii) all or any derivatives and/or 45 | modifications created or made by You to any of the items specified in (i). 46 | 47 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 48 | proprietary to Licensor, and as such, Licensee agrees to receive all such 49 | materials and to use the Software only in accordance with the terms of this 50 | Agreement. Licensee agrees to use reasonable effort to protect the Software 51 | from unauthorized use, reproduction, distribution, or publication. All 52 | publication materials mentioning features or use of this software must 53 | explicitly include an acknowledgement the software was developed by NEC 54 | Laboratories Europe GmbH. 55 | 56 | COPYRIGHT: The Software is owned by Licensor. 57 | 58 | PERMITTED USES: The Software may be used for your own noncommercial 59 | internal research purposes. You understand and agree that Licensor is not 60 | obligated to implement any suggestions and/or feedback you might provide 61 | regarding the Software, but to the extent Licensor does so, you are not 62 | entitled to any compensation related thereto. 63 | 64 | DERIVATIVES: You may create derivatives of or make modifications to the 65 | Software, however, You agree that all and any such derivatives and 66 | modifications will be owned by Licensor and become a part of the Software 67 | licensed to You under this Agreement. You may only use such derivatives and 68 | modifications for your own noncommercial internal research purposes, and you 69 | may not otherwise use, distribute or copy such derivatives and modifications 70 | in violation of this Agreement. 71 | 72 | BACKUPS: If Licensee is an organization, it may make that number of copies 73 | of the Software necessary for internal noncommercial use at a single site 74 | within its organization provided that all information appearing in or on the 75 | original labels, including the copyright and trademark notices are copied 76 | onto the labels of the copies. 77 | 78 | USES NOT PERMITTED: You may not distribute, copy or use the Software except 79 | as explicitly permitted herein. Licensee has not been granted any trademark 80 | license as part of this Agreement. Neither the name of NEC Laboratories 81 | Europe GmbH nor the names of its contributors may be used to endorse or 82 | promote products derived from this Software without specific prior written 83 | permission. 84 | 85 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 86 | whole or in part, or provide third parties access to prior or present 87 | versions (or any parts thereof) of the Software. 88 | 89 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder 90 | without the prior written consent of Licensor. Any attempted assignment 91 | without such consent shall be null and void. 92 | 93 | TERM: The term of the license granted by this Agreement is from Licensee's 94 | acceptance of this Agreement by downloading the Software or by using the 95 | Software until terminated as provided below. 96 | 97 | The Agreement automatically terminates without notice if you fail to comply 98 | with any provision of this Agreement. Licensee may terminate this Agreement 99 | by ceasing using the Software. Upon any termination of this Agreement, 100 | Licensee will delete any and all copies of the Software. You agree that all 101 | provisions which operate to protect the proprietary rights of Licensor shall 102 | remain in force should breach occur and that the obligation of 103 | confidentiality described in this Agreement is binding in perpetuity and, as 104 | such, survives the term of the Agreement. 105 | 106 | FEE: Provided Licensee abides completely by the terms and conditions of this 107 | Agreement, there is no fee due to Licensor for Licensee's use of the 108 | Software in accordance with this Agreement. 109 | 110 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY 111 | OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR 112 | FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE 113 | BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND 114 | RELATED MATERIALS. 115 | 116 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 117 | provided as part of this Agreement. 118 | 119 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent 120 | permitted under applicable law, Licensor shall not be liable for direct, 121 | indirect, special, incidental, or consequential damages or lost profits 122 | related to Licensee's use of and/or inability to use the Software, even if 123 | Licensor is advised of the possibility of such damage. 124 | 125 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 126 | export control laws, regulations, and/or other laws related to embargoes and 127 | sanction programs administered by law. 128 | 129 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 130 | invalid, illegal, or unenforceable by a court or other tribunal of competent 131 | jurisdiction, the validity, legality and enforceability of the remaining 132 | provisions shall not in any way be affected or impaired thereby. 133 | 134 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right 135 | or remedy under this Agreement shall be construed as a waiver of any future 136 | or other exercise of such right or remedy by Licensor. 137 | 138 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 139 | with the laws of Germany without reference to conflict of laws principles. 140 | You consent to the personal jurisdiction of the courts of this country and 141 | waive their rights to venue outside of Germany. 142 | 143 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and 144 | entire agreement between Licensee and Licensor as to the matter set forth 145 | herein and supersedes any previous agreements, understandings, and 146 | arrangements between the parties relating hereto. 147 | 148 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 149 | ''' 150 | 151 | class FcLayer: 152 | def __init__(self, input_size, output_size, layer_id): 153 | self.input_size = input_size 154 | self.output_size = output_size 155 | self.layer_id = layer_id 156 | 157 | class MLP: 158 | def __init__(self, input_layer_size, hidden_layers_sizes, output_layer_size): 159 | self.input_layer_size = input_layer_size 160 | self.output_layer_size = output_layer_size 161 | self.hidden_layers_sizes = hidden_layers_sizes 162 | 163 | self.layers = [] 164 | self.sizes = [input_layer_size] + hidden_layers_sizes + [output_layer_size] 165 | 166 | assert self.input_layer_size in [8, 16, 32, 64], 'Input size not supported' 167 | assert self.output_layer_size in [8, 16, 32, 64], 'Output size not supported' 168 | for l in self.hidden_layers_sizes: 169 | assert l in [8, 16, 32, 64], 'Layer size not supported' 170 | 171 | assert max([input_layer_size, output_layer_size] + hidden_layers_sizes) <= 64, 'Popcount for layer size > 64 is not implemented' 172 | 173 | if len(self.hidden_layers_sizes) > 0: 174 | self.layers.append(FcLayer(self.input_layer_size, self.hidden_layers_sizes[0], 1)) 175 | for layer_id, (layer_size, output_layer_size) in enumerate(zip(self.hidden_layers_sizes, self.hidden_layers_sizes[1:])): 176 | self.layers.append(FcLayer(layer_size, output_layer_size, layer_id + 2)) 177 | self.layers.append(FcLayer(self.hidden_layers_sizes[-1], self.output_layer_size, len(self.hidden_layers_sizes) + 1)) 178 | else: 179 | self.layers.append(FcLayer(self.input_layer_size, self.output_layer_size, 1)) 180 | 181 | def popcount(self, x): 182 | return bin(x).count('1') 183 | 184 | def sign(self, x, n): 185 | if x >= n/2: 186 | return 0 187 | else: 188 | return 1 189 | 190 | def binary_str(self, n, zero_pad_size): 191 | return format(n, '#0%db' % (zero_pad_size + 2)) 192 | 193 | def do_layer(self, input_data, weights, layer, reverse_output=False, verbose=False): 194 | if verbose: 195 | print('\033[1mL%d input_data\033[0m' % layer.layer_id, self.binary_str(input_data, layer.input_size)) 196 | print('\033[1mWeights\033[0m ', ','.join(map(lambda x: self.binary_str(x, layer.input_size), weights))) 197 | h = [input_data^w_ for w_ in weights] 198 | if verbose: 199 | print('\033[1mAfter XOR\033[0m', ','.join(map(lambda x: self.binary_str(x, layer.input_size), h))) 200 | print('\033[1mAfter popcount\033[0m', [self.popcount(h_) for h_ in h]) 201 | y = [self.sign(self.popcount(h_), layer.input_size) for h_ in h] 202 | if verbose: 203 | print('\033[1mAfter sign\033[0m', y) 204 | binary_list = list(map(str, y)) 205 | 206 | if reverse_output: 207 | binary_list = binary_list[::-1] 208 | 209 | folded_value = eval('0b'+''.join(binary_list)) 210 | if verbose: 211 | print('\033[1mAfter folding\033[0m', self.binary_str(folded_value, layer.output_size), '(%d)' % folded_value) 212 | 213 | return eval('0b'+''.join(binary_list)) 214 | 215 | def do_inference(self, input_data, weights, verbose=False): 216 | x = input_data 217 | for layer_idx, layer in enumerate(self.layers): 218 | x = self.do_layer(x, weights[layer_idx], layer, verbose=verbose) 219 | if verbose: 220 | if layer_idx != len(self.layers)-1: 221 | print('-'*80) 222 | else: 223 | print('\n'+'='*80+'\n') 224 | return x 225 | -------------------------------------------------------------------------------- /NNtoP4/run_p4.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | rm $1.json 4 | p4c-bm2-ss -o $1.json $1.p4 5 | simple_switch --log-console --dump-packet-data 64 -i 0@veth0_a $1.json 6 | -------------------------------------------------------------------------------- /NNtoP4/test_bnn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | N3IC - NSDI 2022 5 | 6 | File: test_bnn.py 7 | Authors: Davide Sanvito (Davide.Sanvito@neclab.eu) 8 | Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu) 9 | Roberto Bifulco (Roberto.Bifulco@neclab.eu) 10 | 11 | NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved. 12 | 13 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 14 | 15 | PROPRIETARY INFORMATION --- 16 | 17 | SOFTWARE LICENSE AGREEMENT 18 | 19 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 20 | 21 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 22 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 23 | DOWNLOAD THE SOFTWARE. 24 | 25 | This is a license agreement ("Agreement") between your academic institution 26 | or non-profit organization or self (called "Licensee" or "You" in this 27 | Agreement) and NEC Laboratories Europe GmbH (called "Licensor" in this 28 | Agreement). All rights not specifically granted to you in this Agreement 29 | are reserved for Licensor. 30 | 31 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 32 | ownership of any copy of the Software (as defined below) licensed under this 33 | Agreement and hereby grants to Licensee a personal, non-exclusive, 34 | non-transferable license to use the Software for noncommercial research 35 | purposes, without the right to sublicense, pursuant to the terms and 36 | conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF 37 | LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this 38 | Agreement, the term "Software" means (i) the actual copy of all or any 39 | portion of code for program routines made accessible to Licensee by Licensor 40 | pursuant to this Agreement, inclusive of backups, updates, and/or merged 41 | copies permitted hereunder or subsequently supplied by Licensor, including 42 | all or any file structures, programming instructions, user interfaces and 43 | screen formats and sequences as well as any and all documentation and 44 | instructions related to it, and (ii) all or any derivatives and/or 45 | modifications created or made by You to any of the items specified in (i). 46 | 47 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 48 | proprietary to Licensor, and as such, Licensee agrees to receive all such 49 | materials and to use the Software only in accordance with the terms of this 50 | Agreement. Licensee agrees to use reasonable effort to protect the Software 51 | from unauthorized use, reproduction, distribution, or publication. All 52 | publication materials mentioning features or use of this software must 53 | explicitly include an acknowledgement the software was developed by NEC 54 | Laboratories Europe GmbH. 55 | 56 | COPYRIGHT: The Software is owned by Licensor. 57 | 58 | PERMITTED USES: The Software may be used for your own noncommercial 59 | internal research purposes. You understand and agree that Licensor is not 60 | obligated to implement any suggestions and/or feedback you might provide 61 | regarding the Software, but to the extent Licensor does so, you are not 62 | entitled to any compensation related thereto. 63 | 64 | DERIVATIVES: You may create derivatives of or make modifications to the 65 | Software, however, You agree that all and any such derivatives and 66 | modifications will be owned by Licensor and become a part of the Software 67 | licensed to You under this Agreement. You may only use such derivatives and 68 | modifications for your own noncommercial internal research purposes, and you 69 | may not otherwise use, distribute or copy such derivatives and modifications 70 | in violation of this Agreement. 71 | 72 | BACKUPS: If Licensee is an organization, it may make that number of copies 73 | of the Software necessary for internal noncommercial use at a single site 74 | within its organization provided that all information appearing in or on the 75 | original labels, including the copyright and trademark notices are copied 76 | onto the labels of the copies. 77 | 78 | USES NOT PERMITTED: You may not distribute, copy or use the Software except 79 | as explicitly permitted herein. Licensee has not been granted any trademark 80 | license as part of this Agreement. Neither the name of NEC Laboratories 81 | Europe GmbH nor the names of its contributors may be used to endorse or 82 | promote products derived from this Software without specific prior written 83 | permission. 84 | 85 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 86 | whole or in part, or provide third parties access to prior or present 87 | versions (or any parts thereof) of the Software. 88 | 89 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder 90 | without the prior written consent of Licensor. Any attempted assignment 91 | without such consent shall be null and void. 92 | 93 | TERM: The term of the license granted by this Agreement is from Licensee's 94 | acceptance of this Agreement by downloading the Software or by using the 95 | Software until terminated as provided below. 96 | 97 | The Agreement automatically terminates without notice if you fail to comply 98 | with any provision of this Agreement. Licensee may terminate this Agreement 99 | by ceasing using the Software. Upon any termination of this Agreement, 100 | Licensee will delete any and all copies of the Software. You agree that all 101 | provisions which operate to protect the proprietary rights of Licensor shall 102 | remain in force should breach occur and that the obligation of 103 | confidentiality described in this Agreement is binding in perpetuity and, as 104 | such, survives the term of the Agreement. 105 | 106 | FEE: Provided Licensee abides completely by the terms and conditions of this 107 | Agreement, there is no fee due to Licensor for Licensee's use of the 108 | Software in accordance with this Agreement. 109 | 110 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY 111 | OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR 112 | FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE 113 | BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND 114 | RELATED MATERIALS. 115 | 116 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 117 | provided as part of this Agreement. 118 | 119 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent 120 | permitted under applicable law, Licensor shall not be liable for direct, 121 | indirect, special, incidental, or consequential damages or lost profits 122 | related to Licensee's use of and/or inability to use the Software, even if 123 | Licensor is advised of the possibility of such damage. 124 | 125 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 126 | export control laws, regulations, and/or other laws related to embargoes and 127 | sanction programs administered by law. 128 | 129 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 130 | invalid, illegal, or unenforceable by a court or other tribunal of competent 131 | jurisdiction, the validity, legality and enforceability of the remaining 132 | provisions shall not in any way be affected or impaired thereby. 133 | 134 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right 135 | or remedy under this Agreement shall be construed as a waiver of any future 136 | or other exercise of such right or remedy by Licensor. 137 | 138 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 139 | with the laws of Germany without reference to conflict of laws principles. 140 | You consent to the personal jurisdiction of the courts of this country and 141 | waive their rights to venue outside of Germany. 142 | 143 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and 144 | entire agreement between Licensee and Licensor as to the matter set forth 145 | herein and supersedes any previous agreements, understandings, and 146 | arrangements between the parties relating hereto. 147 | 148 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 149 | ''' 150 | 151 | from scapy.all import sendp, send, srp1, sniff 152 | from scapy.all import Packet, hexdump, binrepr 153 | from scapy.all import Ether, IP, IntField 154 | from scapy.all import bind_layers 155 | 156 | from nn_utils import MLP 157 | import struct 158 | import socket 159 | import time 160 | from threading import Thread 161 | import argparse 162 | 163 | class BNN_pkt(Packet): 164 | name = "BNN_pkt" 165 | fields_desc = [ IntField("x", 0x00)] 166 | 167 | 168 | bind_layers(Ether, BNN_pkt, type=0x2323) 169 | bind_layers(Ether, IP, type=0x800) 170 | 171 | def weights(nn_desc): 172 | # 32x32 layers 173 | w1 = "0x76ced201 0xc12e8fcd 0xf28a043b 0xb6794bea 0x2f4a4018 0x89ea24ea 0xfc615308 0x1622052f 0x739db96 0x3f6100ed 0x9b304f19 0x460623a1 0xd21478d 0x4d14d0b 0xcae57470 0x8c3f42 0xa364d18 0x3560ffb6 0x70ce8213 0xb3382e2f 0x280379c1 0xc85f445b 0x9ef2184 0x9412630d 0x1ef7d6f1 0x9e4d997f 0x6e598c54 0xd6c57dea 0x29d1af7e 0xb0dae2c9 0x310d4941 0xec6aa1db" 174 | w1 = list(map(eval, w1.split())) 175 | w2 = "0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa 0x435a9cb8 0x10606d4a 0xd0269cd3 0x41e8174d 0x9a91a923 0x93a1161d 0xc6b580b7 0xc967049 0xd1f518eb 0x20553b50 0x27efdab3 0x98485a1c 0x2370fe70 0x14e2c158 0x6e0f238f 0xf942a305 0xf50d4088 0x212b2db4 0x9bcf06d8 0x50b36bf1 0xe62403f7 0xb59e59f 0x16eebedc 0xfbd9a663" 176 | w2 = list(map(eval, w2.split())) 177 | w3 = "0x1680d952 0x1ab08c42 0xa9b1c67f 0x337c40e3 0x15a07afe 0x6b8d5534 0x8805de23 0x20469baf 0x3f9c28b7 0x83899d82 0x323566b4 0xcef168c0 0x9ef1724a 0x8bb0f056 0xa743bb41 0x28b9fc77 0xc9eccaf7 0x85b1dbe3 0x86747c76 0xbd9f8977 0x9b945aa6 0x11c96e82 0xac054462 0x33d1efbf 0xf2860164 0x9487593f 0x26a3116a 0xa6d3096d 0x71808ef3 0x1b55d542 0x448cc470 0x2c95db63" 178 | w3 = list(map(eval, w3.split())) 179 | 180 | # 8x8 layer 181 | w4 = "0xa0 0xb1 0xc2 0xd3 0xe4 0xf5 0x06 0x17" 182 | w4 = list(map(eval, w4.split())) 183 | 184 | # 8x32 layer 185 | w5 = "0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03 0x00 0x01 0x02 0x03" 186 | w5 = list(map(eval, w5.split())) 187 | 188 | # 32x8 layer 189 | w6 = "0x2b1939f6 0xdb2501f6 0xaa3a895f 0x1ca0e969 0x99a43cde 0xd0cad442 0xeacdfd01 0x35a170fa" 190 | w6 = list(map(eval, w6.split())) 191 | 192 | if nn_desc == [32, 32, 32, 32]: 193 | weights = [w1, w2, w3] 194 | elif nn_desc == [32, 32, 32]: 195 | weights = [w1, w2] 196 | elif nn_desc == [32, 32]: 197 | weights = [w1] 198 | elif nn_desc == [8, 8, 8]: 199 | weights = [w4, w4] 200 | elif nn_desc == [8, 8]: 201 | weights = [w4] 202 | elif nn_desc == [8, 32, 8]: 203 | weights = [w5, w6] 204 | elif nn_desc == [32, 8, 32]: 205 | weights = [w6, w5] 206 | elif nn_desc == [32, 8]: 207 | weights = [w6] 208 | elif nn_desc == [8, 32]: 209 | weights = [w5] 210 | else: 211 | print(yellow_str('The test packet has been sent, but the result cannot be verified because the NN weights for the %s network configuration are unknown!' % nn_desc)) 212 | exit() 213 | 214 | return weights 215 | 216 | def red_str(s): 217 | return '\x1b[6;30;31m%s\x1b[0m' % s 218 | 219 | def green_str(s): 220 | return '\x1b[6;30;32m%s\x1b[0m' % s 221 | 222 | def yellow_str(s): 223 | return '\x1b[6;30;33m%s\x1b[0m' % s 224 | 225 | def print_bin_hex_dec(value, nn_desc): 226 | print(yellow_str('0b') + format(value, '#0%db' % (nn_desc[0] + 2))[2:], yellow_str('0x') + hex(value)[2:], value) 227 | 228 | def main(): 229 | iface = 'veth0_b' 230 | src = '00:00:00:00:00:0a' 231 | dst = '00:00:00:00:00:0b' 232 | 233 | parser = argparse.ArgumentParser() 234 | parser.add_argument('-n','--nn_desc', help='NN description', required=True) 235 | parser.add_argument('-f','--header_field', help='packet header field', choices=['bnn', 'ipv4_src'], required=True) 236 | parser.add_argument('-i','--nn_input', help='NN input', required=True) 237 | args = parser.parse_args() 238 | 239 | nn_desc = list(map(int, args.nn_desc.split(','))) 240 | if len(nn_desc) < 2: 241 | print('The NN must have at least 1 layer!') 242 | exit() 243 | 244 | if args.header_field == 'bnn': 245 | nn_input = int(args.nn_input,16) 246 | else: 247 | nn_input = args.nn_input 248 | 249 | if args.header_field == 'ipv4_src': 250 | nn_input = struct.unpack("!I", socket.inet_aton(args.nn_input))[0] 251 | if nn_input >= 2 ** nn_desc[0]: 252 | nn_input = nn_input % (2 ** nn_desc[0]) 253 | print(red_str('WARNING: BNN input has been truncated to the %d LSB!' % nn_desc[0])) 254 | if args.header_field == 'bnn': 255 | print(red_str('%d' % nn_input + '\x1b[0m')) 256 | else: 257 | print(red_str('%s' % socket.inet_ntoa(struct.pack('!I', nn_input)) + ' (%d) \x1b[0m' % nn_input)) 258 | 259 | if args.header_field == 'bnn': 260 | pkt = Ether(src=src, dst=dst,type=0x2323)/BNN_pkt(x=nn_input) 261 | else: 262 | pkt = Ether(src=src, dst=dst,type=0x800)/IP(src=socket.inet_ntoa(struct.pack('!I', nn_input))) 263 | 264 | print(green_str('Sending packet...')) 265 | pkt.show() 266 | if args.header_field == 'bnn': 267 | print("BNN input: BNN_pkt.x header field") 268 | else: 269 | print("BNN input: IPv4.src header field") 270 | value = nn_input 271 | print_bin_hex_dec(value, nn_desc) 272 | print() 273 | 274 | if args.header_field == 'bnn': 275 | resp = srp1(pkt, iface=iface) 276 | else: 277 | def threaded_send(pkt): 278 | time.sleep(1) 279 | sendp(pkt, iface=iface) 280 | Thread(target = threaded_send, args = (pkt,)).start() 281 | resp = sniff(iface=iface, count=2)[1] 282 | if resp: 283 | print(green_str('...got reply packet!')) 284 | resp.show() 285 | else: 286 | print(red_str('...no reply packet received!')) 287 | exit() 288 | 289 | nn_weights = weights(nn_desc) 290 | 291 | mlp = MLP(nn_desc[0], nn_desc[1:-1], nn_desc[-1]) 292 | exp_output = mlp.do_inference(nn_input, nn_weights, verbose=False) 293 | rx_output = resp[BNN_pkt].x if args.header_field == 'bnn' else struct.unpack("!I", socket.inet_aton(resp[IP].dst))[0] 294 | 295 | # keeping just the "NN_output_size" LSB 296 | exp_output = exp_output % 2**nn_desc[-1] 297 | rx_output = rx_output % 2**nn_desc[-1] 298 | 299 | print() 300 | print('Expected:') 301 | print_bin_hex_dec(exp_output, nn_desc) 302 | print('Got:') 303 | print_bin_hex_dec(rx_output, nn_desc) 304 | if exp_output == rx_output: 305 | print(green_str('Success!')) 306 | else: 307 | print(red_str('Fail!')) 308 | 309 | if __name__ == '__main__': 310 | main() 311 | -------------------------------------------------------------------------------- /NNtoP4/tmpl_bnn.p4: -------------------------------------------------------------------------------- 1 | /* -*- P4_16 -*- */ 2 | #include 3 | #include 4 | 5 | /* 6 | N3IC - NSDI 2022 7 | 8 | File: tmpl_bnn.p4 9 | Authors: Davide Sanvito (Davide.Sanvito@neclab.eu) 10 | Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu) 11 | Roberto Bifulco (Roberto.Bifulco@neclab.eu) 12 | 13 | NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved. 14 | 15 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 16 | 17 | PROPRIETARY INFORMATION --- 18 | 19 | SOFTWARE LICENSE AGREEMENT 20 | 21 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 22 | 23 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 24 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 25 | DOWNLOAD THE SOFTWARE. 26 | 27 | This is a license agreement ("Agreement") between your academic institution 28 | or non-profit organization or self (called "Licensee" or "You" in this 29 | Agreement) and NEC Laboratories Europe GmbH (called "Licensor" in this 30 | Agreement). All rights not specifically granted to you in this Agreement 31 | are reserved for Licensor. 32 | 33 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 34 | ownership of any copy of the Software (as defined below) licensed under this 35 | Agreement and hereby grants to Licensee a personal, non-exclusive, 36 | non-transferable license to use the Software for noncommercial research 37 | purposes, without the right to sublicense, pursuant to the terms and 38 | conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF 39 | LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this 40 | Agreement, the term "Software" means (i) the actual copy of all or any 41 | portion of code for program routines made accessible to Licensee by Licensor 42 | pursuant to this Agreement, inclusive of backups, updates, and/or merged 43 | copies permitted hereunder or subsequently supplied by Licensor, including 44 | all or any file structures, programming instructions, user interfaces and 45 | screen formats and sequences as well as any and all documentation and 46 | instructions related to it, and (ii) all or any derivatives and/or 47 | modifications created or made by You to any of the items specified in (i). 48 | 49 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 50 | proprietary to Licensor, and as such, Licensee agrees to receive all such 51 | materials and to use the Software only in accordance with the terms of this 52 | Agreement. Licensee agrees to use reasonable effort to protect the Software 53 | from unauthorized use, reproduction, distribution, or publication. All 54 | publication materials mentioning features or use of this software must 55 | explicitly include an acknowledgement the software was developed by NEC 56 | Laboratories Europe GmbH. 57 | 58 | COPYRIGHT: The Software is owned by Licensor. 59 | 60 | PERMITTED USES: The Software may be used for your own noncommercial 61 | internal research purposes. You understand and agree that Licensor is not 62 | obligated to implement any suggestions and/or feedback you might provide 63 | regarding the Software, but to the extent Licensor does so, you are not 64 | entitled to any compensation related thereto. 65 | 66 | DERIVATIVES: You may create derivatives of or make modifications to the 67 | Software, however, You agree that all and any such derivatives and 68 | modifications will be owned by Licensor and become a part of the Software 69 | licensed to You under this Agreement. You may only use such derivatives and 70 | modifications for your own noncommercial internal research purposes, and you 71 | may not otherwise use, distribute or copy such derivatives and modifications 72 | in violation of this Agreement. 73 | 74 | BACKUPS: If Licensee is an organization, it may make that number of copies 75 | of the Software necessary for internal noncommercial use at a single site 76 | within its organization provided that all information appearing in or on the 77 | original labels, including the copyright and trademark notices are copied 78 | onto the labels of the copies. 79 | 80 | USES NOT PERMITTED: You may not distribute, copy or use the Software except 81 | as explicitly permitted herein. Licensee has not been granted any trademark 82 | license as part of this Agreement. Neither the name of NEC Laboratories 83 | Europe GmbH nor the names of its contributors may be used to endorse or 84 | promote products derived from this Software without specific prior written 85 | permission. 86 | 87 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 88 | whole or in part, or provide third parties access to prior or present 89 | versions (or any parts thereof) of the Software. 90 | 91 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder 92 | without the prior written consent of Licensor. Any attempted assignment 93 | without such consent shall be null and void. 94 | 95 | TERM: The term of the license granted by this Agreement is from Licensee's 96 | acceptance of this Agreement by downloading the Software or by using the 97 | Software until terminated as provided below. 98 | 99 | The Agreement automatically terminates without notice if you fail to comply 100 | with any provision of this Agreement. Licensee may terminate this Agreement 101 | by ceasing using the Software. Upon any termination of this Agreement, 102 | Licensee will delete any and all copies of the Software. You agree that all 103 | provisions which operate to protect the proprietary rights of Licensor shall 104 | remain in force should breach occur and that the obligation of 105 | confidentiality described in this Agreement is binding in perpetuity and, as 106 | such, survives the term of the Agreement. 107 | 108 | FEE: Provided Licensee abides completely by the terms and conditions of this 109 | Agreement, there is no fee due to Licensor for Licensee's use of the 110 | Software in accordance with this Agreement. 111 | 112 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY 113 | OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR 114 | FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE 115 | BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND 116 | RELATED MATERIALS. 117 | 118 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 119 | provided as part of this Agreement. 120 | 121 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent 122 | permitted under applicable law, Licensor shall not be liable for direct, 123 | indirect, special, incidental, or consequential damages or lost profits 124 | related to Licensee's use of and/or inability to use the Software, even if 125 | Licensor is advised of the possibility of such damage. 126 | 127 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 128 | export control laws, regulations, and/or other laws related to embargoes and 129 | sanction programs administered by law. 130 | 131 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 132 | invalid, illegal, or unenforceable by a court or other tribunal of competent 133 | jurisdiction, the validity, legality and enforceability of the remaining 134 | provisions shall not in any way be affected or impaired thereby. 135 | 136 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right 137 | or remedy under this Agreement shall be construed as a waiver of any future 138 | or other exercise of such right or remedy by Licensor. 139 | 140 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 141 | with the laws of Germany without reference to conflict of laws principles. 142 | You consent to the personal jurisdiction of the courts of this country and 143 | waive their rights to venue outside of Germany. 144 | 145 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and 146 | entire agreement between Licensee and Licensor as to the matter set forth 147 | herein and supersedes any previous agreements, understandings, and 148 | arrangements between the parties relating hereto. 149 | 150 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 151 | */ 152 | 153 | /* 154 | * Standard ethernet header 155 | */ 156 | header ethernet_t { 157 | bit<48> dstAddr; 158 | bit<48> srcAddr; 159 | bit<16> etherType; 160 | } 161 | 162 | header ipv4_t { 163 | bit<4> version; 164 | bit<4> ihl; 165 | bit<8> diffserv; 166 | bit<16> totalLen; 167 | bit<16> identification; 168 | bit<3> flags; 169 | bit<13> fragOffset; 170 | bit<8> ttl; 171 | bit<8> protocol; 172 | bit<16> hdrChecksum; 173 | bit<32> srcAddr; 174 | bit<32> dstAddr; 175 | } 176 | 177 | 178 | const bit<48> MAC_SND = 0x00000000000a; 179 | const bit<16> BNN_PKT_ETYPE = 0x2323; 180 | 181 | ==POP_CONST== 182 | 183 | /* 184 | * BNN packet 185 | */ 186 | 187 | header bnn_pkt_t { 188 | bit<32> x; 189 | } 190 | 191 | 192 | /* 193 | * All headers must be assembled in a signle struct, no need to be instanctiated 194 | */ 195 | struct my_headers_t { 196 | ethernet_t ethernet; 197 | ipv4_t ipv4; 198 | bnn_pkt_t bnn_pkt; 199 | } 200 | 201 | ==BNN_META_T== 202 | 203 | 204 | /************************************************************************* 205 | *********************** P A R S E R *********************************** 206 | *************************************************************************/ 207 | 208 | parser MyParser( 209 | packet_in packet, 210 | out my_headers_t hdr, 211 | inout metadata meta, 212 | inout standard_metadata_t standard_metadata) 213 | { 214 | state start { 215 | packet.extract(hdr.ethernet); 216 | transition select(hdr.ethernet.etherType) { 217 | 0x800: parse_ipv4; 218 | BNN_PKT_ETYPE : bnn_found; 219 | default : accept; 220 | } 221 | } 222 | 223 | state bnn_found { 224 | packet.extract(hdr.bnn_pkt); 225 | transition accept; 226 | } 227 | 228 | state parse_ipv4 { 229 | packet.extract(hdr.ipv4); 230 | transition accept; 231 | } 232 | } 233 | 234 | /************************************************************************* 235 | ************ C H E C K S U M V E R I F I C A T I O N ************* 236 | *************************************************************************/ 237 | 238 | control MyVerifyChecksum( 239 | inout my_headers_t hdr, 240 | inout metadata meta) 241 | { 242 | apply { } 243 | } 244 | /************************************************************************* 245 | ************** I N G R E S S P R O C E S S I N G ******************* 246 | *************************************************************************/ 247 | 248 | control MyIngress( 249 | inout my_headers_t hdr, 250 | inout metadata meta, 251 | inout standard_metadata_t standard_metadata) 252 | { 253 | action _drop() { 254 | mark_to_drop(standard_metadata); 255 | } 256 | 257 | action send_back() { 258 | bit<48> tmp; 259 | /* Swap the MAC addresses */ 260 | tmp = hdr.ethernet.dstAddr; 261 | hdr.ethernet.dstAddr = hdr.ethernet.srcAddr; 262 | hdr.ethernet.srcAddr = tmp; 263 | bit<32> tmp2; 264 | 265 | /* Send the packet back to the port it came from */ 266 | standard_metadata.egress_spec = standard_metadata.ingress_port; 267 | } 268 | 269 | ==BNN_ACT== 270 | 271 | /***** user actions *****/ 272 | 273 | ==BNN_NN_IN== 274 | 275 | ==BNN_NN_OUT== 276 | 277 | ==BNN_TAB== 278 | 279 | /****** user tables ******/ 280 | 281 | table replication_table { 282 | 283 | key = { 284 | hdr.ethernet.srcAddr: exact; 285 | } 286 | actions = { 287 | get_nn_input; 288 | } 289 | const default_action = get_nn_input(); 290 | } 291 | 292 | 293 | table folding_table { 294 | 295 | key = { 296 | hdr.ethernet.srcAddr: exact; 297 | } 298 | actions = { 299 | get_nn_output; 300 | } 301 | const default_action = get_nn_output(); 302 | } 303 | 304 | 305 | table send_back_table { 306 | 307 | key = { 308 | hdr.ethernet.srcAddr: exact; 309 | } 310 | actions = { 311 | send_back; 312 | _drop; 313 | } 314 | const default_action = _drop(); 315 | const entries = { 316 | MAC_SND : send_back(); 317 | } 318 | 319 | } 320 | 321 | apply { 322 | replication_table.apply(); 323 | 324 | ==BNN_APPLY== 325 | 326 | folding_table.apply(); 327 | send_back_table.apply(); 328 | } 329 | 330 | } 331 | /************************************************************************* 332 | **************** E G R E S S P R O C E S S I N G ******************* 333 | *************************************************************************/ 334 | 335 | control MyEgress( 336 | inout my_headers_t hdr, 337 | inout metadata meta, 338 | inout standard_metadata_t standard_metadata) 339 | { 340 | apply { } 341 | } 342 | 343 | /************************************************************************* 344 | ************* C H E C K S U M C O M P U T A T I O N ************** 345 | *************************************************************************/ 346 | control MyComputeChecksum( 347 | inout my_headers_t hdr, 348 | inout metadata meta) 349 | { 350 | apply { } 351 | } 352 | 353 | /************************************************************************* 354 | *********************** D E P A R S E R ******************************* 355 | *************************************************************************/ 356 | control MyDeparser( 357 | packet_out packet, 358 | in my_headers_t hdr) 359 | { 360 | apply { 361 | packet.emit(hdr.ethernet); 362 | packet.emit(hdr.bnn_pkt); 363 | } 364 | } 365 | 366 | 367 | 368 | V1Switch( 369 | MyParser(), 370 | MyVerifyChecksum(), 371 | MyIngress(), 372 | MyEgress(), 373 | MyComputeChecksum(), 374 | MyDeparser() 375 | ) main; 376 | -------------------------------------------------------------------------------- /NNtoP4/tmpl_ipv4_src.p4: -------------------------------------------------------------------------------- 1 | /* -*- P4_16 -*- */ 2 | #include 3 | #include 4 | 5 | /* 6 | N3IC - NSDI 2022 7 | 8 | File: tmpl_ipv4_src.p4 9 | Authors: Davide Sanvito (Davide.Sanvito@neclab.eu) 10 | Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu) 11 | Roberto Bifulco (Roberto.Bifulco@neclab.eu) 12 | 13 | NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved. 14 | 15 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 16 | 17 | PROPRIETARY INFORMATION --- 18 | 19 | SOFTWARE LICENSE AGREEMENT 20 | 21 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 22 | 23 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS 24 | LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR 25 | DOWNLOAD THE SOFTWARE. 26 | 27 | This is a license agreement ("Agreement") between your academic institution 28 | or non-profit organization or self (called "Licensee" or "You" in this 29 | Agreement) and NEC Laboratories Europe GmbH (called "Licensor" in this 30 | Agreement). All rights not specifically granted to you in this Agreement 31 | are reserved for Licensor. 32 | 33 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive 34 | ownership of any copy of the Software (as defined below) licensed under this 35 | Agreement and hereby grants to Licensee a personal, non-exclusive, 36 | non-transferable license to use the Software for noncommercial research 37 | purposes, without the right to sublicense, pursuant to the terms and 38 | conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF 39 | LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this 40 | Agreement, the term "Software" means (i) the actual copy of all or any 41 | portion of code for program routines made accessible to Licensee by Licensor 42 | pursuant to this Agreement, inclusive of backups, updates, and/or merged 43 | copies permitted hereunder or subsequently supplied by Licensor, including 44 | all or any file structures, programming instructions, user interfaces and 45 | screen formats and sequences as well as any and all documentation and 46 | instructions related to it, and (ii) all or any derivatives and/or 47 | modifications created or made by You to any of the items specified in (i). 48 | 49 | CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is 50 | proprietary to Licensor, and as such, Licensee agrees to receive all such 51 | materials and to use the Software only in accordance with the terms of this 52 | Agreement. Licensee agrees to use reasonable effort to protect the Software 53 | from unauthorized use, reproduction, distribution, or publication. All 54 | publication materials mentioning features or use of this software must 55 | explicitly include an acknowledgement the software was developed by NEC 56 | Laboratories Europe GmbH. 57 | 58 | COPYRIGHT: The Software is owned by Licensor. 59 | 60 | PERMITTED USES: The Software may be used for your own noncommercial 61 | internal research purposes. You understand and agree that Licensor is not 62 | obligated to implement any suggestions and/or feedback you might provide 63 | regarding the Software, but to the extent Licensor does so, you are not 64 | entitled to any compensation related thereto. 65 | 66 | DERIVATIVES: You may create derivatives of or make modifications to the 67 | Software, however, You agree that all and any such derivatives and 68 | modifications will be owned by Licensor and become a part of the Software 69 | licensed to You under this Agreement. You may only use such derivatives and 70 | modifications for your own noncommercial internal research purposes, and you 71 | may not otherwise use, distribute or copy such derivatives and modifications 72 | in violation of this Agreement. 73 | 74 | BACKUPS: If Licensee is an organization, it may make that number of copies 75 | of the Software necessary for internal noncommercial use at a single site 76 | within its organization provided that all information appearing in or on the 77 | original labels, including the copyright and trademark notices are copied 78 | onto the labels of the copies. 79 | 80 | USES NOT PERMITTED: You may not distribute, copy or use the Software except 81 | as explicitly permitted herein. Licensee has not been granted any trademark 82 | license as part of this Agreement. Neither the name of NEC Laboratories 83 | Europe GmbH nor the names of its contributors may be used to endorse or 84 | promote products derived from this Software without specific prior written 85 | permission. 86 | 87 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in 88 | whole or in part, or provide third parties access to prior or present 89 | versions (or any parts thereof) of the Software. 90 | 91 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder 92 | without the prior written consent of Licensor. Any attempted assignment 93 | without such consent shall be null and void. 94 | 95 | TERM: The term of the license granted by this Agreement is from Licensee's 96 | acceptance of this Agreement by downloading the Software or by using the 97 | Software until terminated as provided below. 98 | 99 | The Agreement automatically terminates without notice if you fail to comply 100 | with any provision of this Agreement. Licensee may terminate this Agreement 101 | by ceasing using the Software. Upon any termination of this Agreement, 102 | Licensee will delete any and all copies of the Software. You agree that all 103 | provisions which operate to protect the proprietary rights of Licensor shall 104 | remain in force should breach occur and that the obligation of 105 | confidentiality described in this Agreement is binding in perpetuity and, as 106 | such, survives the term of the Agreement. 107 | 108 | FEE: Provided Licensee abides completely by the terms and conditions of this 109 | Agreement, there is no fee due to Licensor for Licensee's use of the 110 | Software in accordance with this Agreement. 111 | 112 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY 113 | OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR 114 | FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE 115 | BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND 116 | RELATED MATERIALS. 117 | 118 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is 119 | provided as part of this Agreement. 120 | 121 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent 122 | permitted under applicable law, Licensor shall not be liable for direct, 123 | indirect, special, incidental, or consequential damages or lost profits 124 | related to Licensee's use of and/or inability to use the Software, even if 125 | Licensor is advised of the possibility of such damage. 126 | 127 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 128 | export control laws, regulations, and/or other laws related to embargoes and 129 | sanction programs administered by law. 130 | 131 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be 132 | invalid, illegal, or unenforceable by a court or other tribunal of competent 133 | jurisdiction, the validity, legality and enforceability of the remaining 134 | provisions shall not in any way be affected or impaired thereby. 135 | 136 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right 137 | or remedy under this Agreement shall be construed as a waiver of any future 138 | or other exercise of such right or remedy by Licensor. 139 | 140 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance 141 | with the laws of Germany without reference to conflict of laws principles. 142 | You consent to the personal jurisdiction of the courts of this country and 143 | waive their rights to venue outside of Germany. 144 | 145 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and 146 | entire agreement between Licensee and Licensor as to the matter set forth 147 | herein and supersedes any previous agreements, understandings, and 148 | arrangements between the parties relating hereto. 149 | 150 | THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. 151 | */ 152 | 153 | /* 154 | * Standard ethernet header 155 | */ 156 | header ethernet_t { 157 | bit<48> dstAddr; 158 | bit<48> srcAddr; 159 | bit<16> etherType; 160 | } 161 | 162 | header ipv4_t { 163 | bit<4> version; 164 | bit<4> ihl; 165 | bit<8> diffserv; 166 | bit<16> totalLen; 167 | bit<16> identification; 168 | bit<3> flags; 169 | bit<13> fragOffset; 170 | bit<8> ttl; 171 | bit<8> protocol; 172 | bit<16> hdrChecksum; 173 | bit<32> srcAddr; 174 | bit<32> dstAddr; 175 | } 176 | 177 | 178 | const bit<48> MAC_SND = 0x00000000000a; 179 | 180 | ==POP_CONST== 181 | 182 | /* 183 | * All headers must be assembled in a signle struct, no need to be instanctiated 184 | */ 185 | struct my_headers_t { 186 | ethernet_t ethernet; 187 | ipv4_t ipv4; 188 | } 189 | 190 | ==BNN_META_T== 191 | 192 | 193 | /************************************************************************* 194 | *********************** P A R S E R *********************************** 195 | *************************************************************************/ 196 | 197 | parser MyParser( 198 | packet_in packet, 199 | out my_headers_t hdr, 200 | inout metadata meta, 201 | inout standard_metadata_t standard_metadata) 202 | { 203 | state start { 204 | packet.extract(hdr.ethernet); 205 | transition select(hdr.ethernet.etherType) { 206 | 0x800: parse_ipv4; 207 | default : accept; 208 | } 209 | } 210 | 211 | state parse_ipv4 { 212 | packet.extract(hdr.ipv4); 213 | transition accept; 214 | } 215 | } 216 | 217 | /************************************************************************* 218 | ************ C H E C K S U M V E R I F I C A T I O N ************* 219 | *************************************************************************/ 220 | control MyVerifyChecksum( 221 | inout my_headers_t hdr, 222 | inout metadata meta) 223 | { 224 | apply { } 225 | } 226 | /************************************************************************* 227 | ************** I N G R E S S P R O C E S S I N G ******************* 228 | *************************************************************************/ 229 | 230 | control MyIngress( 231 | inout my_headers_t hdr, 232 | inout metadata meta, 233 | inout standard_metadata_t standard_metadata) 234 | { 235 | action _drop() { 236 | mark_to_drop(standard_metadata); 237 | } 238 | 239 | action send_back() { 240 | bit<48> tmp; 241 | /* Swap the MAC addresses */ 242 | tmp = hdr.ethernet.dstAddr; 243 | hdr.ethernet.dstAddr = hdr.ethernet.srcAddr; 244 | hdr.ethernet.srcAddr = tmp; 245 | bit<32> tmp2; 246 | /* Swap the IP addresses */ 247 | tmp2 = hdr.ipv4.dstAddr; 248 | hdr.ipv4.dstAddr = hdr.ipv4.srcAddr; 249 | hdr.ipv4.srcAddr = tmp2; 250 | 251 | /* Send the packet back to the port it came from */ 252 | standard_metadata.egress_spec = standard_metadata.ingress_port; 253 | } 254 | 255 | ==BNN_ACT== 256 | 257 | /***** user actions *****/ 258 | 259 | ==BNN_NN_IN== 260 | 261 | ==BNN_NN_OUT== 262 | 263 | ==BNN_TAB== 264 | 265 | /****** user tables ******/ 266 | 267 | table replication_table { 268 | 269 | key = { 270 | hdr.ethernet.srcAddr: exact; 271 | } 272 | actions = { 273 | get_nn_input; 274 | } 275 | const default_action = get_nn_input(); 276 | } 277 | 278 | 279 | table folding_table { 280 | 281 | key = { 282 | hdr.ethernet.srcAddr: exact; 283 | } 284 | actions = { 285 | get_nn_output; 286 | } 287 | const default_action = get_nn_output(); 288 | } 289 | 290 | 291 | table send_back_table { 292 | 293 | key = { 294 | hdr.ethernet.srcAddr: exact; 295 | } 296 | actions = { 297 | send_back; 298 | _drop; 299 | } 300 | const default_action = _drop(); 301 | const entries = { 302 | MAC_SND : send_back(); 303 | } 304 | 305 | } 306 | 307 | apply { 308 | replication_table.apply(); 309 | 310 | ==BNN_APPLY== 311 | 312 | folding_table.apply(); 313 | send_back_table.apply(); 314 | } 315 | 316 | } 317 | /************************************************************************* 318 | **************** E G R E S S P R O C E S S I N G ******************* 319 | *************************************************************************/ 320 | 321 | control MyEgress( 322 | inout my_headers_t hdr, 323 | inout metadata meta, 324 | inout standard_metadata_t standard_metadata) 325 | { 326 | apply { } 327 | } 328 | 329 | /************************************************************************* 330 | ************* C H E C K S U M C O M P U T A T I O N ************** 331 | *************************************************************************/ 332 | control MyComputeChecksum( 333 | inout my_headers_t hdr, 334 | inout metadata meta) 335 | { 336 | apply { } 337 | } 338 | 339 | /************************************************************************* 340 | *********************** D E P A R S E R ******************************* 341 | *************************************************************************/ 342 | control MyDeparser( 343 | packet_out packet, 344 | in my_headers_t hdr) 345 | { 346 | apply { 347 | packet.emit(hdr.ethernet); 348 | packet.emit(hdr.ipv4); 349 | } 350 | } 351 | 352 | 353 | 354 | V1Switch( 355 | MyParser(), 356 | MyVerifyChecksum(), 357 | MyIngress(), 358 | MyEgress(), 359 | MyComputeChecksum(), 360 | MyDeparser() 361 | ) main; 362 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Re-architecting Traffic Analysis with _Neural_ Network Interface Cards 2 | 3 | This repository contains the code for the paper 4 | 5 | [_G. Siracusano, S. Galea, D. Sanvito, M. Malekzadeh, G. Antichi, P. Costa, H. Haddadi, R. Bifulco - **Re-architecting Traffic Analysis with Neural Network Interface Cards** [USENIX NSDI 2022]_](https://www.usenix.org/conference/nsdi22/presentation/siracusano) 6 | 7 | The structure of the directories is the following: 8 | - `dt_rf_bnn`: Jupyter notebooks comparing Decision Tree (DT), Random Forest (RF) and Binary Neural Network (BNN) models on Security and IoT datasets 9 | - `NNtoP4`: BNN to P4 compiler 10 | 11 | Additional `README.md` files are provided in the sub-directories above. 12 | 13 | ## Reference 14 | If you use `N3IC` for your research, please cite the following paper: 15 | ``` 16 | @inproceedings{siracusano2022n3ic, 17 | title={Re-architecting Traffic Analysis with Neural Network Interface Cards}, 18 | author={Siracusano, Giuseppe and Galea, Salvator and Sanvito, Davide and Malekzadeh, Mohammad and Antichi, Gianni and Costa, Paolo and Haddadi, Hamed and Bifulco, Roberto}, 19 | booktitle={19th USENIX Symposium on Networked Systems Design and Implementation (NSDI 22)}, 20 | year={2022}, 21 | address = {Renton, WA}, 22 | url = {https://www.usenix.org/conference/nsdi22/presentation/siracusano}, 23 | publisher = {USENIX Association}, 24 | month = apr, 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /dt_rf_bnn/README.md: -------------------------------------------------------------------------------- 1 | # Requirements (tested on Ubuntu 20.04.3 LTS) 2 | 3 | ``` 4 | sudo apt update 5 | sudo apt install -y python3-pip python3-dev 6 | pip install notebook numpy sklearn matplotlib pandas larq tensorflow==2.5 7 | python3 -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))" 8 | ``` 9 | 10 | ## UNSW-NB15 dataset 11 | 12 | Download `UNSW-NB15` dataset from https://research.unsw.edu.au/projects/unsw-nb15-dataset. 13 | 14 | Put `UNSW_NB15_testing-set.csv` and `UNSW_NB15_training-set.csv` from `UNSW_NB15 - CSV Files/a part of training and testing set` into `datasets/UNSW_NB15`. 15 | 16 | ## UNSW-IoT dataset 17 | 18 | Download `UNSW-IoT` dataset from https://iotanalytics.unsw.edu.au/iottraces.html into `datasets/UNSW_IOT` and extract the pcap files using `tar -xf`. 19 | ``` 20 | set -o xtrace 21 | cd datasets/UNSW_IOT 22 | wget https://iotanalytics.unsw.edu.au/iottestbed/pcap/filelist.txt -O filelist.txt 23 | cat filelist.txt | egrep -v "(^#.*|^$)" | xargs -n 1 wget 24 | ls *.tar.gz | xargs -n 1 tar -xf 25 | rm *.tar.gz filelist.txt 26 | ``` 27 | Extract the features using `argus` and create a single `dataset.csv` file. 28 | ``` 29 | sudo apt install -y argus-client 30 | for f in *.pcap; do argus -r $f -AZJmR -w $f.argus; done 31 | for f in *.argus; do ra -r $f -u -n -c , -s +dur +sbytes +dbytes +sttl +dttl +sload +dload +spkts +dpkts +smeansz +dmeansz +sintpkt +dintpkt +tcprtt +synack +ackdat +smac +dmac > $f.csv; done 32 | # Get header line from a single CSV file 33 | ls *csv | head -n 1 | xargs -n 1 head -n 1 > dataset_hdr.csv 34 | # Concatenate all the CSV files 35 | awk FNR!=1 *.csv > dataset_data.csv 36 | # Create a single dataset.csv file 37 | cat dataset_hdr.csv dataset_data.csv > dataset.csv 38 | rm *.argus* dataset_hdr.csv dataset_data.csv 39 | ``` 40 | Finally, download `List_Of_Devices.txt` into the same `datasets/UNSW_IOT` folder. 41 | ``` 42 | wget https://iotanalytics.unsw.edu.au/resources/List_Of_Devices.txt 43 | ``` 44 | You are now ready to run the two Jupyter notebooks `sec_dataset.ipynb` and `iot_dataset.ipynb`. 45 | -------------------------------------------------------------------------------- /dt_rf_bnn/datasets/UNSW_IOT/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /dt_rf_bnn/datasets/UNSW_NB15/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /dt_rf_bnn/iot_dataset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "```\n", 8 | " N3IC - NSDI 2022\n", 9 | "\n", 10 | " File: iot_dataset.ipynb\n", 11 | " Authors: Roberto Bifulco (Roberto.Bifulco@neclab.eu)\n", 12 | " Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu)\n", 13 | " Davide Sanvito (Davide.Sanvito@neclab.eu)\n", 14 | "\n", 15 | "NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved.\n", 16 | "\n", 17 | " THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.\n", 18 | "\n", 19 | " PROPRIETARY INFORMATION ---\n", 20 | "\n", 21 | "SOFTWARE LICENSE AGREEMENT\n", 22 | "\n", 23 | "ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY\n", 24 | "\n", 25 | "BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS\n", 26 | "LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR\n", 27 | "DOWNLOAD THE SOFTWARE.\n", 28 | "\n", 29 | "This is a license agreement (\"Agreement\") between your academic institution\n", 30 | "or non-profit organization or self (called \"Licensee\" or \"You\" in this\n", 31 | "Agreement) and NEC Laboratories Europe GmbH (called \"Licensor\" in this\n", 32 | "Agreement). All rights not specifically granted to you in this Agreement\n", 33 | "are reserved for Licensor.\n", 34 | "\n", 35 | "RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive\n", 36 | "ownership of any copy of the Software (as defined below) licensed under this\n", 37 | "Agreement and hereby grants to Licensee a personal, non-exclusive,\n", 38 | "non-transferable license to use the Software for noncommercial research\n", 39 | "purposes, without the right to sublicense, pursuant to the terms and\n", 40 | "conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF\n", 41 | "LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this\n", 42 | "Agreement, the term \"Software\" means (i) the actual copy of all or any\n", 43 | "portion of code for program routines made accessible to Licensee by Licensor\n", 44 | "pursuant to this Agreement, inclusive of backups, updates, and/or merged\n", 45 | "copies permitted hereunder or subsequently supplied by Licensor, including\n", 46 | "all or any file structures, programming instructions, user interfaces and\n", 47 | "screen formats and sequences as well as any and all documentation and\n", 48 | "instructions related to it, and (ii) all or any derivatives and/or\n", 49 | "modifications created or made by You to any of the items specified in (i).\n", 50 | "\n", 51 | "CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is\n", 52 | "proprietary to Licensor, and as such, Licensee agrees to receive all such\n", 53 | "materials and to use the Software only in accordance with the terms of this\n", 54 | "Agreement. Licensee agrees to use reasonable effort to protect the Software\n", 55 | "from unauthorized use, reproduction, distribution, or publication. All\n", 56 | "publication materials mentioning features or use of this software must\n", 57 | "explicitly include an acknowledgement the software was developed by NEC\n", 58 | "Laboratories Europe GmbH.\n", 59 | "\n", 60 | "COPYRIGHT: The Software is owned by Licensor.\n", 61 | "\n", 62 | "PERMITTED USES: The Software may be used for your own noncommercial\n", 63 | "internal research purposes. You understand and agree that Licensor is not\n", 64 | "obligated to implement any suggestions and/or feedback you might provide\n", 65 | "regarding the Software, but to the extent Licensor does so, you are not\n", 66 | "entitled to any compensation related thereto.\n", 67 | "\n", 68 | "DERIVATIVES: You may create derivatives of or make modifications to the\n", 69 | "Software, however, You agree that all and any such derivatives and\n", 70 | "modifications will be owned by Licensor and become a part of the Software\n", 71 | "licensed to You under this Agreement. You may only use such derivatives and\n", 72 | "modifications for your own noncommercial internal research purposes, and you\n", 73 | "may not otherwise use, distribute or copy such derivatives and modifications\n", 74 | "in violation of this Agreement.\n", 75 | "\n", 76 | "BACKUPS: If Licensee is an organization, it may make that number of copies\n", 77 | "of the Software necessary for internal noncommercial use at a single site\n", 78 | "within its organization provided that all information appearing in or on the\n", 79 | "original labels, including the copyright and trademark notices are copied\n", 80 | "onto the labels of the copies.\n", 81 | "\n", 82 | "USES NOT PERMITTED: You may not distribute, copy or use the Software except\n", 83 | "as explicitly permitted herein. Licensee has not been granted any trademark\n", 84 | "license as part of this Agreement. Neither the name of NEC Laboratories\n", 85 | "Europe GmbH nor the names of its contributors may be used to endorse or\n", 86 | "promote products derived from this Software without specific prior written\n", 87 | "permission.\n", 88 | "\n", 89 | "You may not sell, rent, lease, sublicense, lend, time-share or transfer, in\n", 90 | "whole or in part, or provide third parties access to prior or present\n", 91 | "versions (or any parts thereof) of the Software.\n", 92 | "\n", 93 | "ASSIGNMENT: You may not assign this Agreement or your rights hereunder\n", 94 | "without the prior written consent of Licensor. Any attempted assignment\n", 95 | "without such consent shall be null and void.\n", 96 | "\n", 97 | "TERM: The term of the license granted by this Agreement is from Licensee's\n", 98 | "acceptance of this Agreement by downloading the Software or by using the\n", 99 | "Software until terminated as provided below.\n", 100 | "\n", 101 | "The Agreement automatically terminates without notice if you fail to comply\n", 102 | "with any provision of this Agreement. Licensee may terminate this Agreement\n", 103 | "by ceasing using the Software. Upon any termination of this Agreement,\n", 104 | "Licensee will delete any and all copies of the Software. You agree that all\n", 105 | "provisions which operate to protect the proprietary rights of Licensor shall\n", 106 | "remain in force should breach occur and that the obligation of\n", 107 | "confidentiality described in this Agreement is binding in perpetuity and, as\n", 108 | "such, survives the term of the Agreement.\n", 109 | "\n", 110 | "FEE: Provided Licensee abides completely by the terms and conditions of this\n", 111 | "Agreement, there is no fee due to Licensor for Licensee's use of the\n", 112 | "Software in accordance with this Agreement.\n", 113 | "\n", 114 | "DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED \"AS-IS\" WITHOUT WARRANTY\n", 115 | "OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR\n", 116 | "FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE\n", 117 | "BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND\n", 118 | "RELATED MATERIALS.\n", 119 | "\n", 120 | "SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is\n", 121 | "provided as part of this Agreement.\n", 122 | "\n", 123 | "EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent\n", 124 | "permitted under applicable law, Licensor shall not be liable for direct,\n", 125 | "indirect, special, incidental, or consequential damages or lost profits\n", 126 | "related to Licensee's use of and/or inability to use the Software, even if\n", 127 | "Licensor is advised of the possibility of such damage.\n", 128 | "\n", 129 | "EXPORT REGULATION: Licensee agrees to comply with any and all applicable\n", 130 | "export control laws, regulations, and/or other laws related to embargoes and\n", 131 | "sanction programs administered by law.\n", 132 | "\n", 133 | "SEVERABILITY: If any provision(s) of this Agreement shall be held to be\n", 134 | "invalid, illegal, or unenforceable by a court or other tribunal of competent\n", 135 | "jurisdiction, the validity, legality and enforceability of the remaining\n", 136 | "provisions shall not in any way be affected or impaired thereby.\n", 137 | "\n", 138 | "NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right\n", 139 | "or remedy under this Agreement shall be construed as a waiver of any future\n", 140 | "or other exercise of such right or remedy by Licensor.\n", 141 | "\n", 142 | "GOVERNING LAW: This Agreement shall be construed and enforced in accordance\n", 143 | "with the laws of Germany without reference to conflict of laws principles.\n", 144 | "You consent to the personal jurisdiction of the courts of this country and\n", 145 | "waive their rights to venue outside of Germany.\n", 146 | "\n", 147 | "ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and\n", 148 | "entire agreement between Licensee and Licensor as to the matter set forth\n", 149 | "herein and supersedes any previous agreements, understandings, and\n", 150 | "arrangements between the parties relating hereto.\n", 151 | "\n", 152 | " THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.\n", 153 | "```" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "from __future__ import print_function\n", 163 | "\n", 164 | "import larq as lq\n", 165 | "import matplotlib.pyplot as plt\n", 166 | "import numpy as np\n", 167 | "import os\n", 168 | "import pandas as pd\n", 169 | "import pickle\n", 170 | "\n", 171 | "from sklearn.metrics import accuracy_score\n", 172 | "from sklearn.metrics import auc\n", 173 | "from sklearn.metrics import ConfusionMatrixDisplay\n", 174 | "from sklearn.metrics import confusion_matrix\n", 175 | "from sklearn.metrics import multilabel_confusion_matrix\n", 176 | "from sklearn.metrics import f1_score\n", 177 | "from sklearn.metrics import precision_score\n", 178 | "from sklearn.metrics import recall_score\n", 179 | "from sklearn.metrics import roc_auc_score\n", 180 | "from sklearn.metrics import roc_curve\n", 181 | "from sklearn.model_selection import StratifiedShuffleSplit, StratifiedKFold\n", 182 | "from sklearn.ensemble import RandomForestClassifier\n", 183 | "from sklearn.tree import DecisionTreeClassifier\n", 184 | "from tensorflow.keras.callbacks import ModelCheckpoint\n", 185 | "from tensorflow.keras.utils import to_categorical\n", 186 | "from tensorflow.python.keras.utils import np_utils\n", 187 | "import tensorflow as tf\n", 188 | "\n", 189 | "np.random.seed(1337)" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "### Dataset" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "device_list = pd.read_csv('datasets/UNSW_IOT/List_Of_Devices.txt', sep='\\t+')\n", 206 | "data_df = pd.read_csv('datasets/UNSW_IOT/dataset.csv')" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [ 215 | "# Add DeviceName column from List_Of_Devices.txt\n", 216 | "\n", 217 | "device_list['MAC ADDRESS'] = device_list['MAC ADDRESS'].str.strip()\n", 218 | "macs = set(data_df.SrcMac.unique()).union( set(data_df.DstMac.unique()) )\n", 219 | "\n", 220 | "mac_to_device = {}\n", 221 | "for m in macs:\n", 222 | " dev_name = device_list[device_list['MAC ADDRESS'] == m]['List of Devices'].values\n", 223 | " if len(dev_name) == 0:\n", 224 | " mac_to_device[m] = None\n", 225 | " else:\n", 226 | " mac_to_device[m] = dev_name[0]\n", 227 | "\n", 228 | "def mac_label(x, labels):\n", 229 | " if x['SrcMac'] == 'ff:ff:ff:ff:ff:ff':\n", 230 | " label_mac = x['DstMac']\n", 231 | " elif x['DstMac'] == 'ff:ff:ff:ff:ff:ff':\n", 232 | " label_mac = x['SrcMac']\n", 233 | " elif x['SrcMac'] == '14:cc:20:51:33:ea':\n", 234 | " label_mac = x['DstMac']\n", 235 | " elif x['DstMac'] == '14:cc:20:51:33:ea':\n", 236 | " label_mac = x['SrcMac']\n", 237 | " else:\n", 238 | " return None\n", 239 | " \n", 240 | " return labels[label_mac]\n", 241 | "\n", 242 | "data_df['DeviceName'] = data_df.apply(lambda x: mac_label(x, mac_to_device), axis=1)" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": null, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "# Data pre-processing\n", 252 | "\n", 253 | "columns_to_drop = ['State', 'Dir', 'SrcMac', 'DstMac', 'SrcAddr', 'DstAddr',\n", 254 | " 'StartTime', 'TotPkts', 'TotBytes', 'Flgs', 'Sport', 'Dport']\n", 255 | "data_df = data_df.drop(columns_to_drop, axis=1)\n", 256 | "\n", 257 | "cols = ['Proto']\n", 258 | "for col in cols:\n", 259 | " data_df[col] = data_df[col].astype('category')\n", 260 | " data_df[col] = data_df[col].cat.codes\n", 261 | "\n", 262 | "# Removing rows with NaN in any column\n", 263 | "data_df.dropna(inplace=True)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": null, 269 | "metadata": {}, 270 | "outputs": [], 271 | "source": [ 272 | "SAMPLES_PER_CLS_THRESHOLD = 40000\n", 273 | "\n", 274 | "to_classify = []\n", 275 | "for item in data_df.DeviceName.value_counts().items():\n", 276 | " if (item[1] > SAMPLES_PER_CLS_THRESHOLD and not (item[0] in ['Laptop', 'Samsung Galaxy Tab', 'MacBook'])):\n", 277 | " print(item)\n", 278 | " to_classify.append(item[0])\n", 279 | "len(to_classify)\n", 280 | "\n", 281 | "assert len(to_classify) == 9, 'Tune SAMPLES_PER_CLS_THRESHOLD to obtain 9 classes (got %d)' % len(to_classify)" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [ 290 | "# Assigning the group labels, keeping at most 43k samples per class\n", 291 | "\n", 292 | "label_array = np.zeros(data_df.shape[0])\n", 293 | "data_df['label'] = label_array.astype(int)\n", 294 | "\n", 295 | "for i, name in enumerate(to_classify):\n", 296 | " index = data_df[data_df.DeviceName == name ].index\n", 297 | " data_df.loc[index,'label'] = int(i+1)\n", 298 | "\n", 299 | "# Shuffling data around to ensure we do not select devices of a single time from the \"rest\" catory\n", 300 | "data_df = data_df.sample(frac=1, random_state=0)\n", 301 | "\n", 302 | "data_df = data_df.groupby(data_df.label).head(43000)\n", 303 | "\n", 304 | "# Dropping non numerical columns\n", 305 | "data_df = data_df.drop('DeviceName', axis=1)\n", 306 | "\n", 307 | "data_df = data_df.apply(pd.to_numeric, errors='raise')" 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "### Feature selection" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [ 323 | "selected_columns = [\n", 324 | " 'proto',\n", 325 | " 'dur',\n", 326 | " 'sbytes', 'dbytes',\n", 327 | " 'sttl', 'dttl',\n", 328 | " 'sload', 'dload',\n", 329 | " 'spkts', 'dpkts',\n", 330 | " 'smean', 'dmean',\n", 331 | " 'sinpkt', 'dinpkt',\n", 332 | " 'tcprtt', 'synack', 'ackdat',\n", 333 | " 'label'\n", 334 | "]" 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": null, 340 | "metadata": {}, 341 | "outputs": [], 342 | "source": [ 343 | "columns_to_drop = ['State', 'Dir', 'SrcMac', 'DstMac', 'SrcAddr', 'DstAddr',\n", 344 | " 'StartTime', 'TotPkts', 'TotBytes', 'Flgs', 'Sport', 'Dport']" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": null, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "X = data_df[data_df.columns[:17]].values\n", 354 | "Y = data_df[data_df.columns[17]].values" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "### Data binarization" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "Xint = X.astype(\"int\")" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": null, 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "size_in_bits = {\n", 380 | " 'proto': 8,\n", 381 | " 'dur': 16,\n", 382 | " 'sbytes': 24, 'dbytes': 24,\n", 383 | " 'sttl': 8, 'dttl': 8,\n", 384 | " 'sload': 24, 'dload': 24,\n", 385 | " 'spkts': 16, 'dpkts': 16,\n", 386 | " 'smean': 16, 'dmean': 16,\n", 387 | " 'sinpkt': 16, 'dinpkt': 16,\n", 388 | " 'tcprtt': 8, 'synack': 8, 'ackdat': 8,\n", 389 | "}\n", 390 | "\n", 391 | "sum(size_in_bits.values())" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": null, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [ 400 | "Xbin = np.zeros( (Xint.shape[0], sum(size_in_bits.values())) )\n", 401 | "for i, feature_row in enumerate(Xint):\n", 402 | " # the index at which the next binary value should be written\n", 403 | " write_ptr = 0\n", 404 | " for j, column_val in enumerate(feature_row):\n", 405 | " # Transforming in KB sbytes, dbytes, sload, dload\n", 406 | " if j in [2,3,6,7]:\n", 407 | " column_val = int(column_val/1000) \n", 408 | " # Setting to maximum any value above the max given the number of b\n", 409 | " if (column_val > 2**size_in_bits[selected_columns[j]] - 1):\n", 410 | " column_val = 2**size_in_bits[selected_columns[j]] - 1\n", 411 | " tmp = list(bin(column_val)[2:])\n", 412 | " tmp = [int(x) for x in tmp]\n", 413 | " # zero padding to the left\n", 414 | " tmp = [0]*(size_in_bits[selected_columns[j]] - len(tmp)) + tmp\n", 415 | " for k, bin_val in enumerate(tmp):\n", 416 | " Xbin[i,write_ptr] = bin_val\n", 417 | " write_ptr += 1" 418 | ] 419 | }, 420 | { 421 | "cell_type": "code", 422 | "execution_count": null, 423 | "metadata": {}, 424 | "outputs": [], 425 | "source": [ 426 | "# BNN dataset\n", 427 | "Xbin[Xbin == 0] = -1\n", 428 | "X_bin = Xbin\n", 429 | "\n", 430 | "Y_cat = np_utils.to_categorical(Y)" 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": null, 436 | "metadata": {}, 437 | "outputs": [], 438 | "source": [ 439 | "def plot_confusion_matrix_wo_clf(y_true, y_pred, class_names, normalize='true'):\n", 440 | " cm = confusion_matrix(y_true, y_pred, normalize=normalize)\n", 441 | " disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_names)\n", 442 | " fig, ax = plt.subplots(figsize=(6, 6))\n", 443 | " if normalize == 'true':\n", 444 | " disp.plot(cmap=plt.cm.Blues, ax=ax, values_format='.2f')\n", 445 | " else:\n", 446 | " disp.plot(cmap=plt.cm.Blues, ax=ax)\n", 447 | " \n", 448 | " plt.show()" 449 | ] 450 | }, 451 | { 452 | "cell_type": "code", 453 | "execution_count": null, 454 | "metadata": {}, 455 | "outputs": [], 456 | "source": [ 457 | "def metrics_multiclass_dataset(clf, X_test, y_test, y_pred, y_score, is_bnn=False):\n", 458 | " \n", 459 | " if is_bnn:\n", 460 | " # Make y_test 1D\n", 461 | " y_test = np.argmax(y_test, axis=1)\n", 462 | " \n", 463 | " cm_data = plot_confusion_matrix_wo_clf(y_test, y_pred, map(str,range(max(y_test)+1)))\n", 464 | " \n", 465 | " mcf = multilabel_confusion_matrix(y_test, y_pred)\n", 466 | " fpr_list = []\n", 467 | " fnr_list = []\n", 468 | " tpr_list = []\n", 469 | " for cf in mcf:\n", 470 | " tn, fp, fn, tp = cf.ravel()\n", 471 | " fpr_list.append(fp / (fp+tn))\n", 472 | " fnr_list.append(fn / (fn+tp))\n", 473 | " tpr_list.append(tp / (tp+fn))\n", 474 | " \n", 475 | " a = accuracy_score(y_test, y_pred)\n", 476 | " p = precision_score(y_test, y_pred, average='macro')\n", 477 | " r = recall_score(y_test, y_pred, average='macro')\n", 478 | " tpr_ = r # TPR = Recall\n", 479 | " assert np.average(tpr_list) == tpr_\n", 480 | " fpr_ = np.average(fpr_list)\n", 481 | " fnr_ = np.average(fnr_list)\n", 482 | " f1 = f1_score(y_test, y_pred, average='macro')\n", 483 | "\n", 484 | " y_score = to_categorical(y_pred)\n", 485 | " fpr = {}\n", 486 | " tpr = {}\n", 487 | " roc_auc = {}\n", 488 | " num_classes = clf.output.shape[1] if isinstance(clf, tf.keras.models.Sequential) else len(clf.classes_)\n", 489 | " for i in range(num_classes):\n", 490 | " fpr[i], tpr[i], _ = roc_curve(to_categorical(y_test)[:, i], y_score[:, i])\n", 491 | " roc_auc[i] = auc(fpr[i], tpr[i])\n", 492 | " ra = roc_auc_score(y_test, y_score, average='macro', multi_class='ovr')\n", 493 | "\n", 494 | " return a, p, r, tpr_, fpr_, fnr_, f1, ra, cm_data" 495 | ] 496 | }, 497 | { 498 | "cell_type": "code", 499 | "execution_count": null, 500 | "metadata": {}, 501 | "outputs": [], 502 | "source": [ 503 | "def build_bnn_model(neurons, \n", 504 | " input_shape, \n", 505 | " last_act=\"softmax\", \n", 506 | " learning_rate=0.0001, \n", 507 | " loss='squared_hinge'):\n", 508 | " \n", 509 | " kwargs = dict(input_quantizer=\"ste_sign\",\n", 510 | " kernel_quantizer=\"ste_sign\",\n", 511 | " kernel_constraint=\"weight_clip\")\n", 512 | "\n", 513 | " model = tf.keras.models.Sequential()\n", 514 | " model.add(lq.layers.QuantDense(neurons[0], use_bias=False,\n", 515 | " input_quantizer=\"ste_sign\",\n", 516 | " kernel_quantizer=\"ste_sign\",\n", 517 | " kernel_constraint=\"weight_clip\",\n", 518 | " input_shape=(input_shape,) ) )\n", 519 | " model.add(tf.keras.layers.BatchNormalization(scale=False, momentum=0.9))\n", 520 | " model.add(lq.layers.QuantDense(neurons[1], use_bias=False, **kwargs))\n", 521 | " model.add(tf.keras.layers.BatchNormalization(scale=False, momentum=0.9))\n", 522 | " model.add(lq.layers.QuantDense(neurons[2], use_bias=False, activation=last_act, **kwargs))\n", 523 | "\n", 524 | " # lq.models.summary(model)\n", 525 | " \n", 526 | " opt = tf.keras.optimizers.Adam(learning_rate=learning_rate)\n", 527 | " model.compile(optimizer=opt, loss=loss, metrics=['accuracy'])\n", 528 | " \n", 529 | " return model" 530 | ] 531 | }, 532 | { 533 | "cell_type": "markdown", 534 | "metadata": {}, 535 | "source": [ 536 | "# Select configs" 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": null, 542 | "metadata": {}, 543 | "outputs": [], 544 | "source": [ 545 | "depths_range = [3, 6, 9]\n", 546 | "estimators_range = [5]\n", 547 | "\n", 548 | "bnn_models = [\n", 549 | " [32, 16, 10],\n", 550 | " [64, 32, 10],\n", 551 | " [128, 64, 10]\n", 552 | "]" 553 | ] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "execution_count": null, 558 | "metadata": {}, 559 | "outputs": [], 560 | "source": [ 561 | "batch_size = 256\n", 562 | "num_folds = 5\n", 563 | "train_epochs = 15" 564 | ] 565 | }, 566 | { 567 | "cell_type": "code", 568 | "execution_count": null, 569 | "metadata": {}, 570 | "outputs": [], 571 | "source": [ 572 | "accuracy_store_iot = {}\n", 573 | "precision_store_iot = {}\n", 574 | "recall_store_iot = {}\n", 575 | "tpr_store_iot = {}\n", 576 | "fpr_store_iot = {}\n", 577 | "fnr_store_iot = {}\n", 578 | "f1_store_iot = {}\n", 579 | "roc_auc_store_iot = {}\n", 580 | "cm_data_store_iot = {}\n", 581 | "\n", 582 | "########################################\n", 583 | "\n", 584 | "skf = StratifiedKFold(n_splits=num_folds)\n", 585 | "\n", 586 | "for depth in depths_range:\n", 587 | " label = 'dt__depth_%d' % (depth)\n", 588 | " accuracy_store_iot[label] = np.zeros(num_folds)\n", 589 | " precision_store_iot[label] = np.zeros(num_folds)\n", 590 | " recall_store_iot[label] = np.zeros(num_folds)\n", 591 | " tpr_store_iot[label] = np.zeros(num_folds)\n", 592 | " fpr_store_iot[label] = np.zeros(num_folds)\n", 593 | " fnr_store_iot[label] = np.zeros(num_folds)\n", 594 | " f1_store_iot[label] = np.zeros(num_folds)\n", 595 | " roc_auc_store_iot[label] = np.zeros(num_folds)\n", 596 | " cm_data_store_iot[label] = {}\n", 597 | " \n", 598 | " fold_idx = 0\n", 599 | " for train_index, test_index in skf.split(X, Y):\n", 600 | " print('DT: depth=%d, fold_idx=%d' % (depth, fold_idx))\n", 601 | " X_train, X_test = X[train_index], X[test_index]\n", 602 | " y_train, y_test = Y[train_index], Y[test_index]\n", 603 | " \n", 604 | " dt = DecisionTreeClassifier(criterion='entropy', max_depth=depth, random_state=0)\n", 605 | " dt = dt.fit(X_train, y_train)\n", 606 | " y_pred = dt.predict(X_test)\n", 607 | " y_score = dt.predict_proba(X_test)\n", 608 | " \n", 609 | " a, p, r, tpr, fpr, fnr, f1, roc_auc, cm_data = metrics_multiclass_dataset(dt, X_test, y_test, y_pred, y_score)\n", 610 | " accuracy_store_iot[label][fold_idx] = a\n", 611 | " precision_store_iot[label][fold_idx] = p\n", 612 | " recall_store_iot[label][fold_idx] = r\n", 613 | " tpr_store_iot[label][fold_idx] = tpr\n", 614 | " fpr_store_iot[label][fold_idx] = fpr\n", 615 | " fnr_store_iot[label][fold_idx] = fnr\n", 616 | " f1_store_iot[label][fold_idx] = f1\n", 617 | " roc_auc_store_iot[label][fold_idx] = roc_auc\n", 618 | " cm_data_store_iot[label][fold_idx] = cm_data\n", 619 | " \n", 620 | " fold_idx += 1\n", 621 | "\n", 622 | " print('-'*40)\n", 623 | " print('='*80)\n", 624 | "\n", 625 | "########################################################################################\n", 626 | "\n", 627 | "for depth in depths_range:\n", 628 | " for estimators in estimators_range:\n", 629 | " label = 'rf__depth_%d__estimators_%d' % (depth, estimators)\n", 630 | " accuracy_store_iot[label] = np.zeros(num_folds)\n", 631 | " precision_store_iot[label] = np.zeros(num_folds)\n", 632 | " recall_store_iot[label] = np.zeros(num_folds)\n", 633 | " tpr_store_iot[label] = np.zeros(num_folds)\n", 634 | " fpr_store_iot[label] = np.zeros(num_folds)\n", 635 | " fnr_store_iot[label] = np.zeros(num_folds)\n", 636 | " f1_store_iot[label] = np.zeros(num_folds)\n", 637 | " roc_auc_store_iot[label] = np.zeros(num_folds)\n", 638 | " cm_data_store_iot[label] = {}\n", 639 | "\n", 640 | " fold_idx = 0\n", 641 | " for train_index, test_index in skf.split(X, Y):\n", 642 | " print('RF: depth=%d, estimators=%d, fold_idx=%d' % (depth, estimators, fold_idx))\n", 643 | " X_train, X_test = X[train_index], X[test_index]\n", 644 | " y_train, y_test = Y[train_index], Y[test_index]\n", 645 | "\n", 646 | " rf = RandomForestClassifier(criterion='entropy', max_depth=depth, n_estimators=estimators, random_state=0)\n", 647 | " rf = rf.fit(X_train, y_train)\n", 648 | " y_pred = rf.predict(X_test)\n", 649 | " y_score = rf.predict_proba(X_test)\n", 650 | "\n", 651 | " a, p, r, tpr, fpr, fnr, f1, roc_auc, cm_data = metrics_multiclass_dataset(rf, X_test, y_test, y_pred, y_score)\n", 652 | " accuracy_store_iot[label][fold_idx] = a\n", 653 | " precision_store_iot[label][fold_idx] = p\n", 654 | " recall_store_iot[label][fold_idx] = r\n", 655 | " tpr_store_iot[label][fold_idx] = tpr\n", 656 | " fpr_store_iot[label][fold_idx] = fpr\n", 657 | " fnr_store_iot[label][fold_idx] = fnr\n", 658 | " f1_store_iot[label][fold_idx] = f1\n", 659 | " roc_auc_store_iot[label][fold_idx] = roc_auc\n", 660 | " cm_data_store_iot[label][fold_idx] = cm_data\n", 661 | " \n", 662 | " fold_idx += 1\n", 663 | "\n", 664 | " print('-'*40)\n", 665 | " print('='*80)\n", 666 | "\n", 667 | "########################################################################################\n", 668 | "\n", 669 | "for neurons in bnn_models:\n", 670 | " label = 'bnn__%s' % ('_'.join(map(str, neurons)))\n", 671 | " accuracy_store_iot[label] = np.zeros(num_folds)\n", 672 | " precision_store_iot[label] = np.zeros(num_folds)\n", 673 | " recall_store_iot[label] = np.zeros(num_folds)\n", 674 | " tpr_store_iot[label] = np.zeros(num_folds)\n", 675 | " fpr_store_iot[label] = np.zeros(num_folds)\n", 676 | " fnr_store_iot[label] = np.zeros(num_folds)\n", 677 | " f1_store_iot[label] = np.zeros(num_folds)\n", 678 | " roc_auc_store_iot[label] = np.zeros(num_folds)\n", 679 | " cm_data_store_iot[label] = {}\n", 680 | " \n", 681 | " fold_idx = 0\n", 682 | " for train_index, test_index in skf.split(X, Y):\n", 683 | " print('BNN', neurons ,', fold_idx=%d' % (fold_idx))\n", 684 | " X_train, X_test = X_bin[train_index], X_bin[test_index]\n", 685 | " y_train, y_test = Y_cat[train_index], Y_cat[test_index]\n", 686 | " \n", 687 | " model = build_bnn_model(neurons, X_bin.shape[1]) \n", 688 | " fname = 'bnn__iot__%s__fold%d.h5' % ('_'.join(map(str, neurons)), fold_idx)\n", 689 | " \n", 690 | " model_checkpoint_callback = ModelCheckpoint(\n", 691 | " filepath='models/' + fname,\n", 692 | " monitor='val_accuracy',\n", 693 | " mode='max',\n", 694 | " save_best_only=True,\n", 695 | " verbose=1)\n", 696 | " \n", 697 | " if not os.path.isfile('models/' + fname):\n", 698 | " train_history = model.fit(X_train, y_train, \n", 699 | " batch_size=batch_size, \n", 700 | " epochs=train_epochs,\n", 701 | " verbose=0,\n", 702 | " validation_data=(X_test, y_test),\n", 703 | " callbacks=[model_checkpoint_callback])\n", 704 | " \n", 705 | " # Reload best weights\n", 706 | " model.load_weights('models/' + fname)\n", 707 | " else:\n", 708 | " # Reload stored weights\n", 709 | " print('Loading models/' + fname)\n", 710 | " model.load_weights('models/' + fname)\n", 711 | "\n", 712 | " y_pred = model.predict_classes(X_test)\n", 713 | " y_score = model.predict_proba(X_test)\n", 714 | " \n", 715 | " a, p, r, tpr, fpr, fnr, f1, roc_auc, cm_data = metrics_multiclass_dataset(model, X_test, y_test, y_pred, y_score, is_bnn=True)\n", 716 | " accuracy_store_iot[label][fold_idx] = a\n", 717 | " precision_store_iot[label][fold_idx] = p\n", 718 | " recall_store_iot[label][fold_idx] = r\n", 719 | " tpr_store_iot[label][fold_idx] = tpr\n", 720 | " fpr_store_iot[label][fold_idx] = fpr\n", 721 | " fnr_store_iot[label][fold_idx] = fnr\n", 722 | " f1_store_iot[label][fold_idx] = f1\n", 723 | " roc_auc_store_iot[label][fold_idx] = roc_auc\n", 724 | " cm_data_store_iot[label][fold_idx] = cm_data\n", 725 | " \n", 726 | " fold_idx += 1\n", 727 | "\n", 728 | " print('-'*40)\n", 729 | " print('='*80)" 730 | ] 731 | }, 732 | { 733 | "cell_type": "code", 734 | "execution_count": null, 735 | "metadata": {}, 736 | "outputs": [], 737 | "source": [ 738 | "for store,metric in zip([accuracy_store_iot, precision_store_iot, recall_store_iot,\n", 739 | " fnr_store_iot, fpr_store_iot, f1_store_iot, roc_auc_store_iot],\n", 740 | " ['Accuracy', 'Precision', 'Recall', 'FNR', 'FPR', 'F1-score', 'ROC-AUC']):\n", 741 | " print('[%s]' % metric)\n", 742 | " for key in store:\n", 743 | " print('%s: %.1f ± %.1f' % (key, 100*store[key].mean(), 100*store[key].std()))\n", 744 | " print()" 745 | ] 746 | }, 747 | { 748 | "cell_type": "code", 749 | "execution_count": null, 750 | "metadata": {}, 751 | "outputs": [], 752 | "source": [] 753 | } 754 | ], 755 | "metadata": { 756 | "kernelspec": { 757 | "display_name": "Python 3 (ipykernel)", 758 | "language": "python", 759 | "name": "python3" 760 | }, 761 | "language_info": { 762 | "codemirror_mode": { 763 | "name": "ipython", 764 | "version": 3 765 | }, 766 | "file_extension": ".py", 767 | "mimetype": "text/x-python", 768 | "name": "python", 769 | "nbconvert_exporter": "python", 770 | "pygments_lexer": "ipython3", 771 | "version": "3.8.10" 772 | } 773 | }, 774 | "nbformat": 4, 775 | "nbformat_minor": 4 776 | } 777 | -------------------------------------------------------------------------------- /dt_rf_bnn/models/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /dt_rf_bnn/sec_dataset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "```\n", 8 | " N3IC - NSDI 2022\n", 9 | "\n", 10 | " File: sec_dataset.ipynb\n", 11 | " Authors: Roberto Bifulco (Roberto.Bifulco@neclab.eu)\n", 12 | " Giuseppe Siracusano (Giuseppe.Siracusano@neclab.eu)\n", 13 | " Davide Sanvito (Davide.Sanvito@neclab.eu)\n", 14 | "\n", 15 | "NEC Laboratories Europe GmbH, Copyright (c) 2022, All rights reserved.\n", 16 | "\n", 17 | " THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.\n", 18 | "\n", 19 | " PROPRIETARY INFORMATION ---\n", 20 | "\n", 21 | "SOFTWARE LICENSE AGREEMENT\n", 22 | "\n", 23 | "ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY\n", 24 | "\n", 25 | "BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS\n", 26 | "LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR\n", 27 | "DOWNLOAD THE SOFTWARE.\n", 28 | "\n", 29 | "This is a license agreement (\"Agreement\") between your academic institution\n", 30 | "or non-profit organization or self (called \"Licensee\" or \"You\" in this\n", 31 | "Agreement) and NEC Laboratories Europe GmbH (called \"Licensor\" in this\n", 32 | "Agreement). All rights not specifically granted to you in this Agreement\n", 33 | "are reserved for Licensor.\n", 34 | "\n", 35 | "RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive\n", 36 | "ownership of any copy of the Software (as defined below) licensed under this\n", 37 | "Agreement and hereby grants to Licensee a personal, non-exclusive,\n", 38 | "non-transferable license to use the Software for noncommercial research\n", 39 | "purposes, without the right to sublicense, pursuant to the terms and\n", 40 | "conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF\n", 41 | "LICENSOR'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this\n", 42 | "Agreement, the term \"Software\" means (i) the actual copy of all or any\n", 43 | "portion of code for program routines made accessible to Licensee by Licensor\n", 44 | "pursuant to this Agreement, inclusive of backups, updates, and/or merged\n", 45 | "copies permitted hereunder or subsequently supplied by Licensor, including\n", 46 | "all or any file structures, programming instructions, user interfaces and\n", 47 | "screen formats and sequences as well as any and all documentation and\n", 48 | "instructions related to it, and (ii) all or any derivatives and/or\n", 49 | "modifications created or made by You to any of the items specified in (i).\n", 50 | "\n", 51 | "CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is\n", 52 | "proprietary to Licensor, and as such, Licensee agrees to receive all such\n", 53 | "materials and to use the Software only in accordance with the terms of this\n", 54 | "Agreement. Licensee agrees to use reasonable effort to protect the Software\n", 55 | "from unauthorized use, reproduction, distribution, or publication. All\n", 56 | "publication materials mentioning features or use of this software must\n", 57 | "explicitly include an acknowledgement the software was developed by NEC\n", 58 | "Laboratories Europe GmbH.\n", 59 | "\n", 60 | "COPYRIGHT: The Software is owned by Licensor.\n", 61 | "\n", 62 | "PERMITTED USES: The Software may be used for your own noncommercial\n", 63 | "internal research purposes. You understand and agree that Licensor is not\n", 64 | "obligated to implement any suggestions and/or feedback you might provide\n", 65 | "regarding the Software, but to the extent Licensor does so, you are not\n", 66 | "entitled to any compensation related thereto.\n", 67 | "\n", 68 | "DERIVATIVES: You may create derivatives of or make modifications to the\n", 69 | "Software, however, You agree that all and any such derivatives and\n", 70 | "modifications will be owned by Licensor and become a part of the Software\n", 71 | "licensed to You under this Agreement. You may only use such derivatives and\n", 72 | "modifications for your own noncommercial internal research purposes, and you\n", 73 | "may not otherwise use, distribute or copy such derivatives and modifications\n", 74 | "in violation of this Agreement.\n", 75 | "\n", 76 | "BACKUPS: If Licensee is an organization, it may make that number of copies\n", 77 | "of the Software necessary for internal noncommercial use at a single site\n", 78 | "within its organization provided that all information appearing in or on the\n", 79 | "original labels, including the copyright and trademark notices are copied\n", 80 | "onto the labels of the copies.\n", 81 | "\n", 82 | "USES NOT PERMITTED: You may not distribute, copy or use the Software except\n", 83 | "as explicitly permitted herein. Licensee has not been granted any trademark\n", 84 | "license as part of this Agreement. Neither the name of NEC Laboratories\n", 85 | "Europe GmbH nor the names of its contributors may be used to endorse or\n", 86 | "promote products derived from this Software without specific prior written\n", 87 | "permission.\n", 88 | "\n", 89 | "You may not sell, rent, lease, sublicense, lend, time-share or transfer, in\n", 90 | "whole or in part, or provide third parties access to prior or present\n", 91 | "versions (or any parts thereof) of the Software.\n", 92 | "\n", 93 | "ASSIGNMENT: You may not assign this Agreement or your rights hereunder\n", 94 | "without the prior written consent of Licensor. Any attempted assignment\n", 95 | "without such consent shall be null and void.\n", 96 | "\n", 97 | "TERM: The term of the license granted by this Agreement is from Licensee's\n", 98 | "acceptance of this Agreement by downloading the Software or by using the\n", 99 | "Software until terminated as provided below.\n", 100 | "\n", 101 | "The Agreement automatically terminates without notice if you fail to comply\n", 102 | "with any provision of this Agreement. Licensee may terminate this Agreement\n", 103 | "by ceasing using the Software. Upon any termination of this Agreement,\n", 104 | "Licensee will delete any and all copies of the Software. You agree that all\n", 105 | "provisions which operate to protect the proprietary rights of Licensor shall\n", 106 | "remain in force should breach occur and that the obligation of\n", 107 | "confidentiality described in this Agreement is binding in perpetuity and, as\n", 108 | "such, survives the term of the Agreement.\n", 109 | "\n", 110 | "FEE: Provided Licensee abides completely by the terms and conditions of this\n", 111 | "Agreement, there is no fee due to Licensor for Licensee's use of the\n", 112 | "Software in accordance with this Agreement.\n", 113 | "\n", 114 | "DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED \"AS-IS\" WITHOUT WARRANTY\n", 115 | "OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR\n", 116 | "FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON- INFRINGEMENT. LICENSEE\n", 117 | "BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND\n", 118 | "RELATED MATERIALS.\n", 119 | "\n", 120 | "SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is\n", 121 | "provided as part of this Agreement.\n", 122 | "\n", 123 | "EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent\n", 124 | "permitted under applicable law, Licensor shall not be liable for direct,\n", 125 | "indirect, special, incidental, or consequential damages or lost profits\n", 126 | "related to Licensee's use of and/or inability to use the Software, even if\n", 127 | "Licensor is advised of the possibility of such damage.\n", 128 | "\n", 129 | "EXPORT REGULATION: Licensee agrees to comply with any and all applicable\n", 130 | "export control laws, regulations, and/or other laws related to embargoes and\n", 131 | "sanction programs administered by law.\n", 132 | "\n", 133 | "SEVERABILITY: If any provision(s) of this Agreement shall be held to be\n", 134 | "invalid, illegal, or unenforceable by a court or other tribunal of competent\n", 135 | "jurisdiction, the validity, legality and enforceability of the remaining\n", 136 | "provisions shall not in any way be affected or impaired thereby.\n", 137 | "\n", 138 | "NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right\n", 139 | "or remedy under this Agreement shall be construed as a waiver of any future\n", 140 | "or other exercise of such right or remedy by Licensor.\n", 141 | "\n", 142 | "GOVERNING LAW: This Agreement shall be construed and enforced in accordance\n", 143 | "with the laws of Germany without reference to conflict of laws principles.\n", 144 | "You consent to the personal jurisdiction of the courts of this country and\n", 145 | "waive their rights to venue outside of Germany.\n", 146 | "\n", 147 | "ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and\n", 148 | "entire agreement between Licensee and Licensor as to the matter set forth\n", 149 | "herein and supersedes any previous agreements, understandings, and\n", 150 | "arrangements between the parties relating hereto.\n", 151 | "\n", 152 | " THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.\n", 153 | "```" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "from __future__ import print_function\n", 163 | "\n", 164 | "import larq as lq\n", 165 | "import matplotlib.pyplot as plt\n", 166 | "import numpy as np\n", 167 | "import os\n", 168 | "import pandas as pd\n", 169 | "import pickle\n", 170 | "\n", 171 | "from sklearn.metrics import accuracy_score\n", 172 | "from sklearn.metrics import auc\n", 173 | "from sklearn.metrics import ConfusionMatrixDisplay\n", 174 | "from sklearn.metrics import confusion_matrix\n", 175 | "from sklearn.metrics import f1_score\n", 176 | "from sklearn.metrics import precision_score\n", 177 | "from sklearn.metrics import recall_score\n", 178 | "from sklearn.metrics import roc_auc_score\n", 179 | "from sklearn.metrics import roc_curve\n", 180 | "from sklearn.model_selection import StratifiedShuffleSplit\n", 181 | "from sklearn.ensemble import RandomForestClassifier\n", 182 | "from sklearn.tree import DecisionTreeClassifier\n", 183 | "from tensorflow.keras.callbacks import ModelCheckpoint\n", 184 | "from tensorflow.keras.utils import to_categorical\n", 185 | "from tensorflow.python.keras.utils import np_utils\n", 186 | "import tensorflow as tf\n", 187 | "\n", 188 | "np.random.seed(1337)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "### Dataset" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [ 204 | "train_df = pd.read_csv('datasets/UNSW_NB15/UNSW_NB15_training-set.csv', delimiter=',')\n", 205 | "test_df = pd.read_csv('datasets/UNSW_NB15/UNSW_NB15_testing-set.csv', delimiter=',')" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "data_df = train_df.append(test_df)" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "data_df = data_df.drop(['id'], axis=1)\n", 224 | "cols = ['proto', 'service', 'state']\n", 225 | "for col in cols:\n", 226 | " data_df[col] = data_df[col].astype('category')\n", 227 | " data_df[col] = data_df[col].cat.codes" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "### Feature selection" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [ 243 | "selected_columns = [\n", 244 | " 'dur',\n", 245 | " 'proto',\n", 246 | " 'sbytes', 'dbytes',\n", 247 | " 'sttl', 'dttl',\n", 248 | " 'sload', 'dload',\n", 249 | " 'spkts', 'dpkts',\n", 250 | " 'smean', 'dmean',\n", 251 | " 'sinpkt', 'dinpkt',\n", 252 | " 'tcprtt', 'synack', 'ackdat',\n", 253 | " 'ct_src_ltm', 'ct_dst_ltm',\n", 254 | " 'ct_dst_src_ltm',\n", 255 | "\n", 256 | " 'attack_cat'\n", 257 | "]" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [ 266 | "data_df = data_df[selected_columns]\n", 267 | "X = data_df[data_df.columns[:20]].values\n", 268 | "Y = data_df[data_df.columns[20]].values" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "### Data binarization" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": null, 281 | "metadata": {}, 282 | "outputs": [], 283 | "source": [ 284 | "Xint = X.astype(\"int\")" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": null, 290 | "metadata": {}, 291 | "outputs": [], 292 | "source": [ 293 | "size_in_bits = {\n", 294 | " 'dur': 8,\n", 295 | " 'proto': 8,\n", 296 | " 'sbytes': 16, 'dbytes': 16,\n", 297 | " 'sttl': 8, 'dttl': 8,\n", 298 | " 'sload': 24, 'dload': 24,\n", 299 | " 'spkts': 16, 'dpkts': 16,\n", 300 | " 'smean': 16, 'dmean': 16,\n", 301 | " 'sinpkt': 16, 'dinpkt': 16,\n", 302 | " 'tcprtt': 8, 'synack': 8, 'ackdat': 8,\n", 303 | " 'ct_src_ltm': 8, 'ct_dst_ltm': 8,\n", 304 | " 'ct_dst_src_ltm': 8,\n", 305 | "}\n", 306 | "\n", 307 | "sum(size_in_bits.values())" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": null, 313 | "metadata": {}, 314 | "outputs": [], 315 | "source": [ 316 | "Xbin = np.zeros( (Xint.shape[0], sum(size_in_bits.values())) )\n", 317 | "for i, feature_row in enumerate(Xint):\n", 318 | " # the index at which the next binary value should be written\n", 319 | " write_ptr = 0\n", 320 | " for j, column_val in enumerate(feature_row):\n", 321 | " # Transforming in KB sbytes, dbytes, sload, dload\n", 322 | " if j in [2,3,6,7]:\n", 323 | " column_val = int(column_val/1000) \n", 324 | " # Setting to maximum any value above the max given the number of b\n", 325 | " if (column_val > 2**size_in_bits[selected_columns[j]] - 1):\n", 326 | " column_val = 2**size_in_bits[selected_columns[j]] - 1\n", 327 | " tmp = list(bin(column_val)[2:])\n", 328 | " tmp = [int(x) for x in tmp]\n", 329 | " # zero padding to the left\n", 330 | " tmp = [0]*(size_in_bits[selected_columns[j]] - len(tmp)) + tmp\n", 331 | " for k, bin_val in enumerate(tmp):\n", 332 | " Xbin[i,write_ptr] = bin_val\n", 333 | " write_ptr += 1" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": null, 339 | "metadata": {}, 340 | "outputs": [], 341 | "source": [ 342 | "# DT/RF dataset\n", 343 | "Y__2_classes = Y.copy()\n", 344 | "Y__2_classes[Y == 'Normal'] = 0\n", 345 | "Y__2_classes[Y != 'Normal'] = 1\n", 346 | "Y__2_classes = Y__2_classes.astype('int')\n", 347 | "\n", 348 | "# BNN dataset\n", 349 | "Xbin[Xbin == 0] = -1\n", 350 | "X_bin = Xbin\n", 351 | "\n", 352 | "Y_cat__2_classes = np_utils.to_categorical(Y__2_classes)" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": null, 358 | "metadata": {}, 359 | "outputs": [], 360 | "source": [ 361 | "def plot_confusion_matrix_wo_clf(y_true, y_pred, class_names, normalize='true'):\n", 362 | " cm = confusion_matrix(y_true, y_pred, normalize=normalize)\n", 363 | " disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_names)\n", 364 | " fig, ax = plt.subplots(figsize=(6, 6))\n", 365 | " if normalize == 'true':\n", 366 | " disp.plot(cmap=plt.cm.Blues, ax=ax, values_format='.2f')\n", 367 | " else:\n", 368 | " disp.plot(cmap=plt.cm.Blues, ax=ax)\n", 369 | " \n", 370 | " plt.show()" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": null, 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "def metrics_binary_dataset(clf, X_test, y_test, y_pred, y_score, is_bnn=False):\n", 380 | " \n", 381 | " if is_bnn:\n", 382 | " # Make y_test 1D\n", 383 | " y_test = np.argmax(y_test, axis=1)\n", 384 | " \n", 385 | " plot_confusion_matrix_wo_clf(y_test, y_pred, ['0','1'])\n", 386 | " \n", 387 | " a = accuracy_score(y_test, y_pred)\n", 388 | " p = precision_score(y_test, y_pred)\n", 389 | " r = recall_score(y_test, y_pred)\n", 390 | " f1 = f1_score(y_test, y_pred, average='macro')\n", 391 | "\n", 392 | " tn, fp, fn, tp = confusion_matrix(y_test, y_pred).ravel()\n", 393 | " \n", 394 | " tpr = r\n", 395 | " fpr = fp / (fp+tn)\n", 396 | " fnr = fn / (fn+tp)\n", 397 | " tnr = tn / (tn+fp)\n", 398 | " \n", 399 | " y_score = to_categorical(y_pred)\n", 400 | " fpr_, tpr_, _ = roc_curve(y_test, y_score[:, 1])\n", 401 | " roc_auc = auc(fpr_, tpr_)\n", 402 | "\n", 403 | " return a, p, r, tpr, fpr, fnr, f1, roc_auc" 404 | ] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "execution_count": null, 409 | "metadata": {}, 410 | "outputs": [], 411 | "source": [ 412 | "def build_bnn_model(neurons, \n", 413 | " input_shape, \n", 414 | " last_act=\"softmax\", \n", 415 | " learning_rate=0.0001, \n", 416 | " loss='squared_hinge'):\n", 417 | " \n", 418 | " kwargs = dict(input_quantizer=\"ste_sign\",\n", 419 | " kernel_quantizer=\"ste_sign\",\n", 420 | " kernel_constraint=\"weight_clip\")\n", 421 | "\n", 422 | " model = tf.keras.models.Sequential()\n", 423 | " model.add(lq.layers.QuantDense(neurons[0], use_bias=False,\n", 424 | " input_quantizer=\"ste_sign\",\n", 425 | " kernel_quantizer=\"ste_sign\",\n", 426 | " kernel_constraint=\"weight_clip\",\n", 427 | " input_shape=(input_shape,) ) )\n", 428 | " model.add(tf.keras.layers.BatchNormalization(scale=False, momentum=0.9))\n", 429 | " model.add(lq.layers.QuantDense(neurons[1], use_bias=False, **kwargs))\n", 430 | " model.add(tf.keras.layers.BatchNormalization(scale=False, momentum=0.9))\n", 431 | " model.add(lq.layers.QuantDense(neurons[2], use_bias=False, activation=last_act, **kwargs))\n", 432 | "\n", 433 | " # lq.models.summary(model)\n", 434 | " \n", 435 | " opt = tf.keras.optimizers.Adam(learning_rate=learning_rate)\n", 436 | " model.compile(optimizer=opt, loss=loss, metrics=['accuracy'])\n", 437 | " \n", 438 | " return model" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": null, 444 | "metadata": {}, 445 | "outputs": [], 446 | "source": [ 447 | "depths_range = [3, 6, 9]\n", 448 | "estimators_range = [5]\n", 449 | "\n", 450 | "bnn_models = [\n", 451 | " [32, 16, 2],\n", 452 | " [64, 32, 2],\n", 453 | " [128, 64, 2]\n", 454 | "]" 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": null, 460 | "metadata": {}, 461 | "outputs": [], 462 | "source": [ 463 | "batch_size = 256\n", 464 | "num_folds = 5\n", 465 | "train_epochs = 15" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": null, 471 | "metadata": { 472 | "scrolled": true 473 | }, 474 | "outputs": [], 475 | "source": [ 476 | "accuracy_store_sec = {}\n", 477 | "precision_store_sec = {}\n", 478 | "recall_store_sec = {}\n", 479 | "tpr_store_sec = {}\n", 480 | "fpr_store_sec = {}\n", 481 | "fnr_store_sec = {}\n", 482 | "f1_store_sec = {}\n", 483 | "roc_auc_store_sec = {}\n", 484 | "\n", 485 | "########################################\n", 486 | "\n", 487 | "skf = StratifiedShuffleSplit(n_splits=num_folds, random_state=0)\n", 488 | "\n", 489 | "for depth in depths_range: \n", 490 | " label = 'dt__depth_%d' % (depth)\n", 491 | " accuracy_store_sec[label] = np.zeros(num_folds)\n", 492 | " precision_store_sec[label] = np.zeros(num_folds)\n", 493 | " recall_store_sec[label] = np.zeros(num_folds)\n", 494 | " tpr_store_sec[label] = np.zeros(num_folds)\n", 495 | " fpr_store_sec[label] = np.zeros(num_folds)\n", 496 | " fnr_store_sec[label] = np.zeros(num_folds)\n", 497 | " f1_store_sec[label] = np.zeros(num_folds)\n", 498 | " roc_auc_store_sec[label] = np.zeros(num_folds)\n", 499 | " \n", 500 | " fold_idx = 0\n", 501 | " for train_index, test_index in skf.split(X, Y):\n", 502 | " print('DT: depth=%d, fold_idx=%d' % (depth, fold_idx))\n", 503 | " X_train, X_test = X[train_index], X[test_index]\n", 504 | " y_train, y_test = Y__2_classes[train_index], Y__2_classes[test_index]\n", 505 | " \n", 506 | " dt = DecisionTreeClassifier(criterion='entropy', max_depth=depth, random_state=0)\n", 507 | " dt = dt.fit(X_train, y_train)\n", 508 | " y_pred = dt.predict(X_test)\n", 509 | " y_score = dt.predict_proba(X_test)\n", 510 | "\n", 511 | " a, p, r, tpr, fpr, fnr, f1, roc_auc = metrics_binary_dataset(dt, X_test, y_test, y_pred, y_score)\n", 512 | " accuracy_store_sec[label][fold_idx] = a\n", 513 | " precision_store_sec[label][fold_idx] = p\n", 514 | " recall_store_sec[label][fold_idx] = r\n", 515 | " tpr_store_sec[label][fold_idx] = tpr\n", 516 | " fpr_store_sec[label][fold_idx] = fpr\n", 517 | " fnr_store_sec[label][fold_idx] = fnr\n", 518 | " f1_store_sec[label][fold_idx] = f1\n", 519 | " roc_auc_store_sec[label][fold_idx] = roc_auc\n", 520 | "\n", 521 | " fold_idx += 1\n", 522 | "\n", 523 | " print('-'*40)\n", 524 | " \n", 525 | " print('='*80)\n", 526 | "\n", 527 | "########################################################################################\n", 528 | "\n", 529 | "for depth in depths_range:\n", 530 | " for estimators in estimators_range:\n", 531 | " label = 'rf__depth_%d__estimators_%d' % (depth, estimators)\n", 532 | " accuracy_store_sec[label] = np.zeros(num_folds)\n", 533 | " precision_store_sec[label] = np.zeros(num_folds)\n", 534 | " recall_store_sec[label] = np.zeros(num_folds)\n", 535 | " tpr_store_sec[label] = np.zeros(num_folds)\n", 536 | " fpr_store_sec[label] = np.zeros(num_folds)\n", 537 | " fnr_store_sec[label] = np.zeros(num_folds)\n", 538 | " f1_store_sec[label] = np.zeros(num_folds)\n", 539 | " roc_auc_store_sec[label] = np.zeros(num_folds)\n", 540 | "\n", 541 | " fold_idx = 0\n", 542 | " for train_index, test_index in skf.split(X, Y):\n", 543 | " print('RF: depth=%d, estimators=%d, fold_idx=%d' % (depth, estimators, fold_idx))\n", 544 | " X_train, X_test = X[train_index], X[test_index]\n", 545 | " y_train, y_test = Y__2_classes[train_index], Y__2_classes[test_index]\n", 546 | "\n", 547 | " rf = RandomForestClassifier(criterion='entropy', max_depth=depth, n_estimators=estimators, random_state=0)\n", 548 | " rf = rf.fit(X_train, y_train)\n", 549 | " y_pred = rf.predict(X_test)\n", 550 | " y_score = rf.predict_proba(X_test)\n", 551 | "\n", 552 | " a, p, r, tpr, fpr, fnr, f1, roc_auc = metrics_binary_dataset(rf, X_test, y_test, y_pred, y_score)\n", 553 | " accuracy_store_sec[label][fold_idx] = a\n", 554 | " precision_store_sec[label][fold_idx] = p\n", 555 | " recall_store_sec[label][fold_idx] = r\n", 556 | " tpr_store_sec[label][fold_idx] = tpr\n", 557 | " fpr_store_sec[label][fold_idx] = fpr\n", 558 | " fnr_store_sec[label][fold_idx] = fnr\n", 559 | " f1_store_sec[label][fold_idx] = f1\n", 560 | " roc_auc_store_sec[label][fold_idx] = roc_auc\n", 561 | " \n", 562 | " fold_idx += 1\n", 563 | "\n", 564 | " print('-'*40)\n", 565 | " \n", 566 | " print('='*40)\n", 567 | "\n", 568 | " print('='*80)\n", 569 | "\n", 570 | "########################################################################################\n", 571 | "\n", 572 | "for neurons in bnn_models:\n", 573 | " label = 'bnn__%s' % ('_'.join(map(str, neurons)))\n", 574 | " accuracy_store_sec[label] = np.zeros(num_folds)\n", 575 | " precision_store_sec[label] = np.zeros(num_folds)\n", 576 | " recall_store_sec[label] = np.zeros(num_folds)\n", 577 | " tpr_store_sec[label] = np.zeros(num_folds)\n", 578 | " fpr_store_sec[label] = np.zeros(num_folds)\n", 579 | " fnr_store_sec[label] = np.zeros(num_folds)\n", 580 | " f1_store_sec[label] = np.zeros(num_folds)\n", 581 | " roc_auc_store_sec[label] = np.zeros(num_folds)\n", 582 | " \n", 583 | " fold_idx = 0\n", 584 | " for train_index, test_index in skf.split(X, Y):\n", 585 | " print('BNN', neurons ,', fold_idx=%d' % (fold_idx))\n", 586 | " X_train, X_test = X_bin[train_index], X_bin[test_index]\n", 587 | " y_train, y_test = Y_cat__2_classes[train_index], Y_cat__2_classes[test_index]\n", 588 | " \n", 589 | " model = build_bnn_model(neurons, X_bin.shape[1]) \n", 590 | " fname = 'bnn__sec_StratifiedShuffleSplit__%s__fold%d.h5' % ('_'.join(map(str, neurons)), fold_idx)\n", 591 | " \n", 592 | " model_checkpoint_callback = ModelCheckpoint(\n", 593 | " filepath='models/' + fname,\n", 594 | " monitor='val_accuracy',\n", 595 | " mode='max',\n", 596 | " save_best_only=True,\n", 597 | " verbose=1)\n", 598 | " \n", 599 | " if not os.path.isfile('models/' + fname):\n", 600 | " train_history = model.fit(X_train, y_train, \n", 601 | " batch_size=batch_size, \n", 602 | " epochs=train_epochs,\n", 603 | " verbose=1,\n", 604 | " validation_data=(X_test, y_test),\n", 605 | " callbacks=[model_checkpoint_callback])\n", 606 | " \n", 607 | " # Reload best weights\n", 608 | " model.load_weights('models/' + fname)\n", 609 | " else:\n", 610 | " # Reload stored weights\n", 611 | " print('Loading models/' + fname)\n", 612 | " model.load_weights('models/' + fname)\n", 613 | "\n", 614 | " y_pred = model.predict_classes(X_test)\n", 615 | " y_score = model.predict_proba(X_test)\n", 616 | " \n", 617 | " a, p, r, tpr, fpr, fnr, f1, roc_auc = metrics_binary_dataset(model, X_test, y_test, y_pred, y_score, is_bnn=True)\n", 618 | " accuracy_store_sec[label][fold_idx] = a\n", 619 | " precision_store_sec[label][fold_idx] = p\n", 620 | " recall_store_sec[label][fold_idx] = r\n", 621 | " tpr_store_sec[label][fold_idx] = tpr\n", 622 | " fpr_store_sec[label][fold_idx] = fpr\n", 623 | " fnr_store_sec[label][fold_idx] = fnr\n", 624 | " f1_store_sec[label][fold_idx] = f1\n", 625 | " roc_auc_store_sec[label][fold_idx] = roc_auc\n", 626 | " \n", 627 | " fold_idx += 1\n", 628 | " \n", 629 | " print('-'*40)\n", 630 | " \n", 631 | " print('='*80)" 632 | ] 633 | }, 634 | { 635 | "cell_type": "code", 636 | "execution_count": null, 637 | "metadata": {}, 638 | "outputs": [], 639 | "source": [ 640 | "for store,metric in zip([accuracy_store_sec, precision_store_sec, recall_store_sec,\n", 641 | " fnr_store_sec, fpr_store_sec, f1_store_sec, roc_auc_store_sec],\n", 642 | " ['Accuracy', 'Precision', 'Recall', 'FNR', 'FPR', 'F1-score', 'ROC-AUC']):\n", 643 | " print('[%s]' % metric)\n", 644 | " for key in store:\n", 645 | " print('%s: %.1f ± %.1f' % (key, 100*store[key].mean(), 100*store[key].std()))\n", 646 | " print()" 647 | ] 648 | }, 649 | { 650 | "cell_type": "code", 651 | "execution_count": null, 652 | "metadata": {}, 653 | "outputs": [], 654 | "source": [] 655 | } 656 | ], 657 | "metadata": { 658 | "kernelspec": { 659 | "display_name": "Python 3 (ipykernel)", 660 | "language": "python", 661 | "name": "python3" 662 | }, 663 | "language_info": { 664 | "codemirror_mode": { 665 | "name": "ipython", 666 | "version": 3 667 | }, 668 | "file_extension": ".py", 669 | "mimetype": "text/x-python", 670 | "name": "python", 671 | "nbconvert_exporter": "python", 672 | "pygments_lexer": "ipython3", 673 | "version": "3.8.10" 674 | } 675 | }, 676 | "nbformat": 4, 677 | "nbformat_minor": 2 678 | } 679 | --------------------------------------------------------------------------------