forked from cog-imperial/OMLT
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request cog-imperial#136 from zshiqiang/add_documentations
add documentations
- Loading branch information
Showing
13 changed files
with
411 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Index handling\n", | ||
"\n", | ||
"Sometimes moving from layer to layer in a neural network involves rearranging the size from the output of the previous layer to the input of the next layer. This notebook demonstrates how to use this functionality in OMLT.\n", | ||
"\n", | ||
"## Library Setup\n", | ||
"\n", | ||
"Start by importing the libraries used in this project:\n", | ||
"\n", | ||
" - `numpy`: a general-purpose numerical library\n", | ||
" - `omlt`: the package this notebook demonstates.\n", | ||
" \n", | ||
"We import the following classes from `omlt`:\n", | ||
"\n", | ||
" - `NetworkDefinition`: class that contains the nodes in a Neural Network\n", | ||
" - `InputLayer`, `DenseLayer`, `PoolingLayer2D`: the three types of layers used in this example\n", | ||
" - `IndexMapper`: used to reshape the data between layers" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import numpy as np\n", | ||
"from omlt.neuralnet import NetworkDefinition\n", | ||
"from omlt.neuralnet.layer import IndexMapper, InputLayer, DenseLayer, PoolingLayer2D" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Then we define a simple network that consists of a max pooling layer and a dense layer:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"0\tInputLayer(input_size=[9], output_size=[9])\n", | ||
"1\tPoolingLayer(input_size=[1, 3, 3], output_size=[1, 2, 2], strides=[2, 2], kernel_shape=[2, 2]), pool_func_name=max\n", | ||
"2\tDenseLayer(input_size=[4], output_size=[1])\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"# define bounds for inputs\n", | ||
"input_size = [9]\n", | ||
"input_bounds = {}\n", | ||
"for i in range(input_size[0]):\n", | ||
" input_bounds[(i)] = (-10.0, 10.0)\n", | ||
"\n", | ||
"net = NetworkDefinition(scaled_input_bounds=input_bounds)\n", | ||
"\n", | ||
"# define the input layer\n", | ||
"input_layer = InputLayer(input_size)\n", | ||
"\n", | ||
"net.add_layer(input_layer)\n", | ||
"\n", | ||
"# define the pooling layer\n", | ||
"input_index_mapper_1 = IndexMapper([9], [1, 3, 3])\n", | ||
"maxpooling_layer = PoolingLayer2D(\n", | ||
" [1, 3, 3],\n", | ||
" [1, 2, 2],\n", | ||
" [2, 2],\n", | ||
" \"max\",\n", | ||
" [2, 2],\n", | ||
" 1,\n", | ||
" input_index_mapper=input_index_mapper_1,\n", | ||
")\n", | ||
"\n", | ||
"net.add_layer(maxpooling_layer)\n", | ||
"net.add_edge(input_layer, maxpooling_layer)\n", | ||
"\n", | ||
"# define the dense layer\n", | ||
"input_index_mapper_2 = IndexMapper([1, 2, 2], [4])\n", | ||
"dense_layer = DenseLayer(\n", | ||
" [4],\n", | ||
" [1],\n", | ||
" activation=\"linear\",\n", | ||
" weights=np.ones([4, 1]),\n", | ||
" biases=np.zeros(1),\n", | ||
" input_index_mapper=input_index_mapper_2,\n", | ||
")\n", | ||
"\n", | ||
"net.add_layer(dense_layer)\n", | ||
"net.add_edge(maxpooling_layer, dense_layer)\n", | ||
"\n", | ||
"for layer_id, layer in enumerate(net.layers):\n", | ||
" print(f\"{layer_id}\\t{layer}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"In this example, `input_index_mapper_1` maps outputs of `input_layer` (with size [9]) to the inputs of `maxpooling_layer` (with size [1, 3, 3]), `input_index_mapper_2` maps the outputs of `maxpooling_layer` (with size [1, 2, 2]) to the inputs of `dense_layer` (with size [4]). Given an input, we can evaluate each layer to see how `IndexMapper` works: " | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"outputs of maxpooling_layer:\n", | ||
" [[[5. 6.]\n", | ||
" [8. 9.]]]\n", | ||
"outputs of dense_layer:\n", | ||
" [28.]\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])\n", | ||
"y1 = maxpooling_layer.eval_single_layer(x)\n", | ||
"print(\"outputs of maxpooling_layer:\\n\", y1)\n", | ||
"y2 = dense_layer.eval_single_layer(y1)\n", | ||
"print(\"outputs of dense_layer:\\n\", y2)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Without `IndexMapper`, the output of `maxpooling_layer` is identical to the input of `dense_layer`. When using `IndexMapper`, using `input_indexes_with_input_layer_indexes` can provide the mapping between indexes. Therefore, there is no need to define variables for the inputs of each layer (except for `input_layer`). As shown in the following, we print both input indexes and output indexes for each layer. Also, we give the mapping between indexes of two adjacent layers, where `local_index` corresponds to the input indexes of the current layer and `input_index` corresponds to the output indexes of previous layer." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"input indexes of input_layer:\n", | ||
"[(0,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,)]\n", | ||
"output indexes of input_layer:\n", | ||
"[(0,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,)]\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(\"input indexes of input_layer:\")\n", | ||
"print(input_layer.input_indexes)\n", | ||
"print(\"output indexes of input_layer:\")\n", | ||
"print(input_layer.output_indexes)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"input indexes of maxpooling_layer:\n", | ||
"[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2)]\n", | ||
"output indexes of maxpooling_layer:\n", | ||
"[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]\n", | ||
"input_index_mapping_1:\n", | ||
"local_index: (0, 0, 0) input_index: (0,)\n", | ||
"local_index: (0, 0, 1) input_index: (1,)\n", | ||
"local_index: (0, 0, 2) input_index: (2,)\n", | ||
"local_index: (0, 1, 0) input_index: (3,)\n", | ||
"local_index: (0, 1, 1) input_index: (4,)\n", | ||
"local_index: (0, 1, 2) input_index: (5,)\n", | ||
"local_index: (0, 2, 0) input_index: (6,)\n", | ||
"local_index: (0, 2, 1) input_index: (7,)\n", | ||
"local_index: (0, 2, 2) input_index: (8,)\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(\"input indexes of maxpooling_layer:\")\n", | ||
"print(maxpooling_layer.input_indexes)\n", | ||
"print(\"output indexes of maxpooling_layer:\")\n", | ||
"print(maxpooling_layer.output_indexes)\n", | ||
"print(\"input_index_mapping_1:\")\n", | ||
"for local_index, input_index in maxpooling_layer.input_indexes_with_input_layer_indexes:\n", | ||
" print(\"local_index:\", local_index, \"input_index:\", input_index)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"input indexes of dense_layer:\n", | ||
"[(0,), (1,), (2,), (3,)]\n", | ||
"output indexes of dense_layer:\n", | ||
"[(0,)]\n", | ||
"input_index_mapping_2:\n", | ||
"local_index: (0,) input_index: (0, 0, 0)\n", | ||
"local_index: (1,) input_index: (0, 0, 1)\n", | ||
"local_index: (2,) input_index: (0, 1, 0)\n", | ||
"local_index: (3,) input_index: (0, 1, 1)\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(\"input indexes of dense_layer:\")\n", | ||
"print(dense_layer.input_indexes)\n", | ||
"print(\"output indexes of dense_layer:\")\n", | ||
"print(dense_layer.output_indexes)\n", | ||
"print(\"input_index_mapping_2:\")\n", | ||
"for local_index, input_index in dense_layer.input_indexes_with_input_layer_indexes:\n", | ||
" print(\"local_index:\", local_index, \"input_index:\", input_index)" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "OMLT", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.8.16" | ||
}, | ||
"orig_nbformat": 4 | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.