├── .gitignore ├── .zenodo.json ├── CONTRIBUTING.md ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── README.rst ├── TeLL ├── __init__.py ├── activations.py ├── config.py ├── dataprocessing.py ├── datareaders.py ├── datasets.py ├── evaluation.py ├── initializations.py ├── layers.py ├── loss.py ├── normalizations.py ├── regularization.py ├── scripts │ ├── __init__.py │ ├── dropoutmask.py │ └── resume.py ├── session.py └── utility │ ├── __init__.py │ ├── gputools.py │ ├── misc.py │ ├── misc_tensorflow.py │ ├── plotting.py │ ├── plotting_daemons.py │ ├── timer.py │ └── workingdir.py ├── __init__.py ├── samples ├── config_convlstm.json ├── config_convlstm_mnist.json ├── config_dense.json ├── config_lstm.json ├── config_lstm3.json ├── main_convlstm.py ├── main_convlstm_mnist.py ├── main_lstm.py ├── mnist │ ├── architectures.py │ ├── config.json │ ├── main.py │ └── main_datapreprocessing.py ├── moving_mnist │ ├── architectures.py │ ├── config.json │ ├── config_gauss.json │ ├── config_lstm.json │ ├── dataset.py │ └── main.py └── sample_architectures.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # python 2 | *.pyc 3 | *.pyo 4 | 5 | # temporary files from text editors 6 | *~ 7 | 8 | # interim latex files 9 | *.log 10 | *.out 11 | *.aux 12 | *.tmp 13 | 14 | # pycharm project files 15 | *.iml 16 | #*.xml -------------------------------------------------------------------------------- /.zenodo.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "access_right": "open", 4 | "title": "Tensorflow Layer Library (TeLL): v1.0.0", 5 | "version": "v1.0.0", 6 | "upload_type": "software", 7 | "publication_date": "2018-06-14", 8 | "description": "

Tensorflow Layer Library (TeLL)

", 9 | "creators": [ 10 | { 11 | "name": "Michael Widrich" 12 | }, 13 | { 14 | "name": "Markus Hofmarcher" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Coding Conventions (Python) 2 | 3 | In general, stick to the [PEP standards](https://www.python.org/dev/peps/pep-0008) as good as possible. 4 | 5 | When adding new functions/modules, use the existing directory structure or include/describe the newly added folders or files in the README.md. 6 | 7 | Keep consistent with existing file, function, and class docstrings. Use and update comments, so that others can quickly see what your code is about. 8 | 9 | Thank you for contributing! :) 10 | 11 | ## Comments for File Structure 12 | 13 | Top-level comment: 14 | ```python 15 | code 16 | 17 | 18 | # ---------------------------------------------------------------------------------------------------------------------- 19 | # Comment 20 | # ---------------------------------------------------------------------------------------------------------------------- 21 | 22 | code 23 | ``` 24 | 25 | or 26 | 27 | ```python 28 | code 29 | 30 | 31 | # ---------------------------------------------------------------------------------------------------------------------- 32 | # Comment 33 | # Description of following section 34 | # ---------------------------------------------------------------------------------------------------------------------- 35 | 36 | code 37 | ``` 38 | 39 | Mid-level comment: 40 | ```python 41 | code 42 | 43 | # 44 | # Comment 45 | # 46 | code 47 | ``` 48 | 49 | or 50 | 51 | ```python 52 | code 53 | 54 | # 55 | # Comment 56 | # Description of following section 57 | # 58 | code 59 | ``` 60 | 61 | Low-level comment: 62 | 63 | ```python 64 | code 65 | 66 | # Comment 67 | code 68 | ``` 69 | 70 | 71 | ## PyCharm Configuration 72 | 73 | If working with PyCharm, please use the provided [configuration file](https://gitlab.markushofmarcher.at/markus.hofmarcher/tools/blob/b2556cd8a097377eb5bf55beedc21b4992a91724/misc/codestyle_cs.xml). Import via 74 | 75 | File->Settings->Editor->Code Style->Manage->Import... 76 | 77 | File->Settings->Editor->File and Code Templates->Python 78 | 79 | ## Docstring conventions 80 | 81 | [Numpy style](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt) is interpretable by sphinx and recommended: 82 | 83 | ## File Template 84 | 85 | ```python 86 | # -*- coding: utf-8 -*- 87 | """ 88 | Short discription of contents and purpose of file 89 | 90 | """ 91 | ``` -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Michael Widrich and Markus Hofmarcher, Institute of Bioinformatics, Johannes Kepler University Linz, Austria. 2 | Free for academic use, commercial license on request. 3 | 4 | The MIT License (MIT) 5 | 6 | Copyright (c) 2017 Michael Widrich and Markus Hofmarcher, Institute of Bioinformatics, Johannes Kepler University Linz, Austria. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the 9 | Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 16 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 17 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # Include the license file 2 | include LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tensorflow Layer Library (TeLL) 2 | [![DOI](https://zenodo.org/badge/87196662.svg)](https://zenodo.org/badge/latestdoi/87196662) 3 | 4 | Provides a variety of tensorflow-based network layers, flexible (recurrent) network designs, convenience routines for saving and resuming networks, and more! 5 | 6 | Copyright (c) Michael Widrich and Markus Hofmarcher, Institute of Bioinformatics, Johannes Kepler University Linz, Austria. 7 | 8 | If you use TeLL or parts of the code in your work, please cite us as 9 | 10 | @misc{tell, 11 | author = {Michael Widrich and Markus Hofmarcher}, 12 | title = {{Tensorflow Layer Library (TeLL)}}, 13 | publisher = {Zenodo}, 14 | journal = {GitHub repository}, 15 | howpublished = {\url{https://github.com/ml-jku/tensorflow-layer-library}}, 16 | year = {2018}, 17 | doi = {10.5281/zenodo.1292055}, 18 | url = {https://doi.org/10.5281/zenodo.1292055}, 19 | } 20 | 21 | ## Setup 22 | You can either install TeLL via pip, use TeLL as a git-submodule in your git project, or download it as a static Python package. 23 | 24 | If you intend on using multiple versions of TeLL in different projects, we recommend to use the [git-submodule](#tell-as-git-submodule) approach. 25 | If you use the same TeLL version with all of your projects, a [pip installation](#tell-as-pip-package) or [static Python package](#tell-as-static-python-package) is sufficient. 26 | 27 | TeLL will run with tensorflow version 1.0. 28 | 29 | ### TeLL as Pip Package 30 | Download the TeLL package and install it via 31 | 32 | ``` 33 | pip install yourpath/tensorflow-layer-library 34 | ``` 35 | 36 | If you want to install the tensorflow dependencies as well, specify "tensorflow" for CPU only or "tensorflow-gpu" for GPU support in brackets after the package, e.g. 37 | 38 | ``` 39 | pip install yourpath/tensorflow-layer-library[tensorflow-gpu] 40 | ``` 41 | 42 | Continue with section [Usage](#usage). 43 | 44 | ### TeLL as Static Python Package 45 | Download TeLL from GitLab or clone it to your disk. Continue with section [Usage](#usage). 46 | 47 | ### TeLL as Git-Submodule 48 | If you want to keep TeLL as a subfolder in your git-project, with different git-projects having different TeLL versions, it may be best to add TeLL as a git-submodule to your project. 49 | This will create a subfolder "tensorflow-layer-library" in your project folder, which can be separately updated to the last version of TeLL. 50 | Let us assume that your project folder has the following structure: 51 | ``` ruby 52 | myproject/ 53 | | 54 | +-- my_main_file. 55 | | 56 | +-- my_other_file.py 57 | ``` 58 | 59 | As described in [this](https://git-scm.com/book/en/v2/Git-Tools-Submodules) guide, you will have to move into your project directory and add the submodule: 60 | 61 | ``` 62 | cd myproject/ 63 | git submodule add https://the-git-repository-address.git 64 | ``` 65 | 66 | This will add the submodule and a .gitmodules file to your directory, resulting in the following structure: 67 | 68 | ``` ruby 69 | myproject/ 70 | | 71 | +-- my_main_file.py 72 | | 73 | +-- tensorflow-layer-library/ 74 | | | 75 | | +-- TeLL/ 76 | | 77 | +-- .gitmodules 78 | ``` 79 | 80 | Now you have to change the path in the .gitmodules file to a relative path, if your project is hosted on the same server as the submodule: 81 | 82 | ``` 83 | [submodule "tensorflow-layer-library"] 84 | path = tensorflow-layer-library 85 | url = ../../TeLL/tensorflow-layer-library.git 86 | ``` 87 | 88 | Sources: [https://git-scm.com/book/en/v2/Git-Tools-Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules), 89 | [https://docs.gitlab.com/ce/ci/git_submodules.html](https://docs.gitlab.com/ce/ci/git_submodules.html) 90 | 91 | ### Run Example Main-File 92 | Try to run one of the examples [samples/main_lstm.py](samples/main_lstm.py) or [samples/main_convlstm.py](samples/main_convlstm.py) provided in the tensorflow-layer-library folder. 93 | The following should start the computations and create a working_dir folder in the tensorflow-layer-library/samples folder: 94 | 95 | ``` 96 | cd tensorflow-layer-library/samples/ 97 | python3 main_lstm_example.py --config lstm_example.json 98 | ``` 99 | 100 | ## Usage: 101 | A focus of this project is to provide easy and fast usability while keeping the design flexible. 102 | There are three basic steps to perform to create and run your architecture: 103 | 104 | ### Design Dataloader 105 | In order to access/create your dataset, a reader/loader class should be used. This class has to contain a batch_loader() function to yield the minibatches. 106 | Examples for creator-classes are ShortLongDataset and MovingDotDataset in [TeLL/datasets.py](TeLL/datasets.py), which can be adapted for your needs. 107 | For reading data, [TeLL/datasets.py](TeLL/datasets.py) provides the classes DatareaderSimpleFiles and DatareaderAdvancedImageFiles, from which readers can be derived from. 108 | DatareaderSimpleFiles and DatareaderAdvancedImageFiles provide support for automatic loading of data in background processes, search for datafiles, etc.. 109 | 110 | ### Design Network Architecture 111 | It is advised to create a new class for each network architecture, e.g. in a file my_architectures.py in your project folder. 112 | In general, the layers can simply be stacked as follows: 113 | 114 | ```python 115 | # define some placeholder for the input and target 116 | X = tf.placeholder(tf.float32, shape=input_shape) 117 | y_ = tf.placeholder(tf.float32, shape=target_shape) 118 | 119 | # stack some layers 120 | layer1 = Layer(incoming=X, ...) 121 | layer2 = Layer(incoming=layer1, ...) 122 | outputlayer = Layer(incoming=layer2, ...) 123 | 124 | # calculate the output of the last layer 125 | output = outputlayer.get_output() 126 | ``` 127 | 128 | A collection of forward- and recurrent network sample architectures can be found in [TeLL/samples/sample_architectures.py](samples/sample_architectures.py). 129 | 130 | ### Adapt Main-File 131 | To adapt the main-file to your needs, copy the example file [samples/main_lstm.py](samples/main_lstm.py) or [samples/main_convlstm.py](samples/main_convlstm.py) and modify the loss calculations, starting at line 246, and the dataloader. 132 | 133 | Finally, you will need to create your configuration file (examples can be found in [samples/](samples)) and you are good to go! 134 | 135 | ### Utility Features 136 | 137 | #### Storage/Resumption 138 | By default, TeLL will create checkpoints for each run in the working_dir folder. 139 | These checkpoints contain a .zip of the directory the main file is located in, so that the code base is at the correct version when the run is resumed. 140 | 141 | To resume an experiment run the following command: 142 | 143 | ``` 144 | tell-resume --epochs --gpu --path 145 | ``` 146 | 147 | #### Plotting 148 | tba 149 | 150 | 151 | ## Directory Structure 152 | The project directory is structured as follows: 153 | ``` ruby 154 | tensorflow-layer-library/ 155 | | '''the TeLL project, including example scripts''' 156 | +-- TeLL/ 157 | | | '''the TeLL package''' 158 | | +-- architectures/ 159 | | | +-- sample_architectures.py 160 | | | '''some example network architectures''' 161 | | +-- configs/ 162 | | | +-- examples/ 163 | | | | '''example configuration files for usage with sample_architectures.py''' 164 | | | +-- config.py 165 | | | '''default configuration settings''' 166 | | +-- network_modules/ 167 | | | '''holds modules for network''' 168 | | | +-- datareader.py 169 | | | | '''base class for dataset readers''' 170 | | | +-- datasets.py 171 | | | | '''classes for dataset loaders and creators''' 172 | | | +-- initializations.py 173 | | | | '''initializers for variables''' 174 | | | +-- layers.py 175 | | | | '''network layer classes''' 176 | | | +-- loss.py 177 | | | | '''loss functions''' 178 | | | +-- regularization.py 179 | | | '''regularization functions''' 180 | | +-- utility/ 181 | | '''holds convenience functions''' 182 | | +-- misc.py 183 | | | '''unclassified convenience functions''' 184 | | +-- plotting.py 185 | | | '''functions for plotting and saving images/videos''' 186 | | +-- plotting_daemons.py 187 | | '''functions for creating and starting (sub)processes for plotting''' 188 | +-- README.md 189 | | '''this file''' 190 | +-- main_lstm_example.py 191 | | '''example main file for LSTM architectures''' 192 | +-- main_convlstm_example.py 193 | | '''example main file for convLSTM architectures''' 194 | +-- main_convlstm_advanced_example.py 195 | | '''example main file for advanced convLSTM architectures''' 196 | +-- todo.py 197 | '''todo-list: indicate on what you are working and strikethrough when you are done''' 198 | ``` 199 | 200 | ## Contributing 201 | 202 | If you want to contribute to TeLL, please read the [guidelines](CONTRIBUTING.md), create a branch or fork, and send merge-requests. 203 | For contribution to this project, your have to assign the copyright of the contribution to the TeLL project. 204 | Please include the statement "I hereby assign copyright in this code to the TeLL project, to be licensed under the same terms as the rest of the code." in your merge requests. 205 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Tensorflow Layer Library (TeLL) 2 | =============================== 3 | 4 | Provides a variety of tensorflow-based network layers, flexible 5 | (recurrent) network designs, convenience routines for saving and 6 | resuming networks, and more! 7 | 8 | Copyright (c) 2016-2017 Michael Widrich and Markus Hofmarcher, Institute 9 | of Bioinformatics, Johannes Kepler University Linz, Austria 10 | 11 | Setup 12 | ----- 13 | 14 | You can either use TeLL as a git-submodule in your git project or as a 15 | static Python package. 16 | 17 | If you intend on using multiple versions of TeLL in different projects, 18 | we recommend to use the `git-submodule <#tell-as-git-submodule>`__ 19 | approach. If you use the same TeLL version with all of your projects, a 20 | `static Python package <#tell-as-static-python-package>`__ is 21 | sufficient. 22 | 23 | TeLL will run with tensorflow version 1.0. 24 | 25 | TeLL as Pip Package 26 | ~~~~~~~~~~~~~~~~~~~ 27 | 28 | Download the TeLL package and install it via 29 | 30 | :: 31 | 32 | pip install 33 | 34 | If you want to install the tensorflow dependencies as well specify 35 | "tensorflow" or "tensorflow-gpu" in brackets after the package, e.g. 36 | 37 | :: 38 | 39 | pip install [tensorflow-gpu] 40 | 41 | TeLL as Static Python Package 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | Download TeLL from GitLab or clone it to your disk. Continue with 45 | section `Usage <#usage>`__. 46 | 47 | TeLL as Git-Submodule 48 | ~~~~~~~~~~~~~~~~~~~~~ 49 | 50 | If you want to keep TeLL as a subfolder in your git-project, with 51 | different git-projects having different TeLL versions, it may be best to 52 | add TeLL as a git-submodule to your project. This will create a 53 | subfolder "tensorflow-layer-library" in your project folder, which can 54 | be separately updated to the last version of TeLL. Let us assume that 55 | your project folder has the following structure: 56 | 57 | .. code:: ruby 58 | 59 | myproject/ 60 | | 61 | +-- my_main_file. 62 | | 63 | +-- my_other_file.py 64 | 65 | As described in 66 | `this `__ guide, 67 | you will have to move into your project directory and add the submodule: 68 | 69 | :: 70 | 71 | cd myproject/ 72 | git submodule add https://the-git-repository-address.git 73 | 74 | This will add the submodule and a .gitmodules file to your directory, 75 | resulting in the following structure: 76 | 77 | .. code:: ruby 78 | 79 | myproject/ 80 | | 81 | +-- my_main_file.py 82 | | 83 | +-- tensorflow-layer-library/ 84 | | | 85 | | +-- TeLL/ 86 | | 87 | +-- .gitmodules 88 | 89 | Now you have to change the path in the .gitmodules file to a relative 90 | path, if your project is hosted on the same server as the submodule: 91 | 92 | :: 93 | 94 | [submodule "tensorflow-layer-library"] 95 | path = tensorflow-layer-library 96 | url = ../../TeLL/tensorflow-layer-library.git 97 | 98 | Sources: https://git-scm.com/book/en/v2/Git-Tools-Submodules, 99 | https://docs.gitlab.com/ce/ci/git_submodules.html 100 | 101 | Run Example Main-File 102 | ~~~~~~~~~~~~~~~~~~~~~ 103 | 104 | Try to run one of the examples 105 | `main\_lstm\_example.py `__ 106 | or 107 | `main\_convlstm\_example.py `__ 108 | provided in the tensorflow-layer-library folder. The following should 109 | start the computations and create a working\_dir folder in the 110 | tensorflow-layer-library folder: 111 | 112 | :: 113 | 114 | cd tensorflow-layer-library/ 115 | python3 main_lstm_example.py --config TeLL/configs/examples/lstm_example.json 116 | 117 | Usage: 118 | ------ 119 | 120 | A focus of this project is to provide easy and fast usability while 121 | keeping the design flexible. There are three basic steps to perform to 122 | create and run your architecture: 123 | 124 | Design Dataloader 125 | ~~~~~~~~~~~~~~~~~ 126 | 127 | In order to access/create your dataset, a reader/loader class should be 128 | used. This class has to contain a batch\_loader() function to yield the 129 | minibatches. Examples for creator-classes are ShortLongDataset and 130 | MovingDotDataset in 131 | `TeLL/network\_modules/datasets.py `__, 132 | which can be adapted for your needs. For reading data, 133 | `TeLL/network\_modules/datasets.py `__ 134 | provides the classes DatareaderSimpleFiles and 135 | DatareaderAdvancedImageFiles, from which readers can be derived from. 136 | DatareaderSimpleFiles and DatareaderAdvancedImageFiles provide support 137 | for automatic loading of data in background processes, search for 138 | datafiles, etc.. 139 | 140 | Design Network Architecture 141 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 142 | 143 | It is advised to create a new class for each network architecture, e.g. 144 | in a file my\_architectures.py in your project folder. In general, the 145 | layers can simply be stacked as follows: 146 | 147 | .. code:: python 148 | 149 | # define some placeholder for the input and target 150 | X = tf.placeholder(tf.float32, shape=input_shape) 151 | y_ = tf.placeholder(tf.float32, shape=target_shape) 152 | 153 | # stack some layers 154 | layer1 = Layer(incoming=X, ...) 155 | layer2 = Layer(incoming=layer1, ...) 156 | outputlayer = Layer(incoming=layer2, ...) 157 | 158 | # calculate the output of the last layer 159 | output = outputlayer.get_output() 160 | 161 | A collection of forward- and recurrent network sample architectures can 162 | be found in 163 | `TeLL/architectures/sample\_architectures.py `__. 164 | 165 | Adapt Main-File 166 | ~~~~~~~~~~~~~~~ 167 | 168 | To adapt the main-file to your needs, copy the example file 169 | `TeLL/architectures/main\_lstm\_example.py `__ 170 | or 171 | `architectures/main\_lstm\_example.py `__ 172 | and modify the loss calculations, starting at line 246, and the 173 | dataloader. 174 | 175 | You will probably also have to adapt the path in variable 176 | tell\_library\_path (first code line in the main files) to your path 177 | '/somepath/tensorflow-layer-library/'. Alternatively, you may also add 178 | the path to the system's PYTHONPATH. 179 | 180 | Finally, you will need to create your configuration file (examples can 181 | be found in 182 | `TeLL/configs/examples `__) 183 | and you are good to go! 184 | 185 | Utility Features 186 | ~~~~~~~~~~~~~~~~ 187 | 188 | Storage/Resumption 189 | ^^^^^^^^^^^^^^^^^^ 190 | 191 | By default, TeLL will create checkpoints for each run in the 192 | working\_dir folder. These checkpoints contain a .zip of the directory 193 | the main file is located in, so that the code base is at the correct 194 | version when the run is resumed. 195 | 196 | To resume an experiment run the following command: 197 | 198 | :: 199 | 200 | tell-resume --epochs --gpu --path 201 | 202 | Plotting 203 | ^^^^^^^^ 204 | 205 | Directory Structure 206 | ------------------- 207 | 208 | The project directory is structured as follows: 209 | 210 | .. code:: ruby 211 | 212 | tensorflow-layer-library/ 213 | | '''the TeLL project, including example scripts''' 214 | +-- TeLL/ 215 | | | '''the TeLL package''' 216 | | +-- architectures/ 217 | | | +-- sample_architectures.py 218 | | | '''some example network architectures''' 219 | | +-- configs/ 220 | | | +-- examples/ 221 | | | | '''example configuration files for usage with sample_architectures.py''' 222 | | | +-- config.py 223 | | | '''default configuration settings''' 224 | | +-- network_modules/ 225 | | | '''holds modules for network''' 226 | | | +-- datareader.py 227 | | | | '''base class for dataset readers''' 228 | | | +-- datasets.py 229 | | | | '''classes for dataset loaders and creators''' 230 | | | +-- initializations.py 231 | | | | '''initializers for variables''' 232 | | | +-- layers.py 233 | | | | '''network layer classes''' 234 | | | +-- loss.py 235 | | | | '''loss functions''' 236 | | | +-- regularization.py 237 | | | '''regularization functions''' 238 | | +-- utility/ 239 | | '''holds convenience functions''' 240 | | +-- misc.py 241 | | | '''unclassified convenience functions''' 242 | | +-- plotting.py 243 | | | '''functions for plotting and saving images/videos''' 244 | | +-- plotting_daemons.py 245 | | '''functions for creating and starting (sub)processes for plotting''' 246 | +-- README.md 247 | | '''this file''' 248 | +-- main_lstm_example.py 249 | | '''example main file for LSTM architectures''' 250 | +-- main_convlstm_example.py 251 | | '''example main file for convLSTM architectures''' 252 | +-- main_convlstm_advanced_example.py 253 | | '''example main file for advanced convLSTM architectures''' 254 | +-- todo.py 255 | '''todo-list: indicate on what you are working and strikethrough when you are done''' -------------------------------------------------------------------------------- /TeLL/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """__init__.py.py: short description 3 | 4 | 5 | Author -- Michael Widrich 6 | Created on -- 2017-03-01 7 | Contact -- michael.widrich@jku.at 8 | 9 | long description 10 | 11 | 12 | ======= ========== ================= ================================ 13 | Version Date Author Description 14 | 0.1 2017-03-01 Michael Widrich - 15 | ======= ========== ================= ================================ 16 | 17 | """ -------------------------------------------------------------------------------- /TeLL/activations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Functions for regularization and convenience wrappers for tensorflow regularization functions 6 | 7 | """ 8 | import tensorflow as tf 9 | 10 | ''' 11 | Tensorflow Implementation of the Scaled ELU function and Dropout 12 | ''' 13 | 14 | 15 | def selu(x): 16 | """ When using SELUs you have to keep the following in mind: 17 | # (1) scale inputs to zero mean and unit variance 18 | # (2) use SELUs 19 | # (3) initialize weights with stddev sqrt(1/n) 20 | # (4) use SELU dropout 21 | """ 22 | with tf.name_scope('selu'): 23 | alpha = 1.6732632423543772848170429916717 24 | scale = 1.0507009873554804934193349852946 25 | return scale * tf.where(x >= 0.0, x, alpha * tf.nn.elu(x)) 26 | 27 | def selu_offset(offset=None): 28 | """selu with constant offset, offset defaults to alpha*scale, i.e. only positive activations""" 29 | with tf.name_scope('selu_offset'): 30 | alpha = 1.6732632423543772848170429916717+1e-7 31 | scale = 1.0507009873554804934193349852946 32 | if offset is None: 33 | offset = tf.constant(alpha*scale, dtype=tf.float32) 34 | return lambda *args, **kwargs: selu(*args, **kwargs) + offset 35 | -------------------------------------------------------------------------------- /TeLL/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Default configuration settings 6 | 7 | """ 8 | import json 9 | import os 10 | 11 | from TeLL.utility.misc import import_object, extract_named_args, try_to_number, parse_args 12 | 13 | 14 | class Config(object): 15 | def __init__(self, filename: str = None): 16 | """Create config object from json file. 17 | 18 | filename : optional; 19 | If passed read config from specified file, otherwise parse command line for config parameter and optionally 20 | override arguments. 21 | """ 22 | if filename is None: 23 | args, override_args = parse_args() 24 | config_file = args.config 25 | else: 26 | args = None 27 | override_args = None 28 | config_file = filename 29 | 30 | # Read config and override with args if passed 31 | if os.path.exists(config_file): 32 | with open(config_file) as f: 33 | self.initialize_from_json(json.loads(f.read()).items()) 34 | # set restore path if passed 35 | if args is not None and args.restore is not None: 36 | self.restore = args.restore 37 | # override if necessary 38 | if override_args is not None: 39 | self.override_from_commandline(override_args) 40 | else: 41 | raise Exception("Configuration file does not exist!") 42 | 43 | def override(self, name, value): 44 | if value is not None: 45 | setattr(self, name, value) 46 | print("CONFIG: {}={}".format(name, getattr(self, name))) 47 | 48 | def has_value(self, name): 49 | return hasattr(self, name) 50 | 51 | def get_value(self, name, default=None): 52 | return getattr(self, name, default) 53 | 54 | def import_architecture(self): 55 | if hasattr(self, "architecture"): 56 | return import_object(self.architecture) 57 | else: 58 | return None 59 | 60 | def initialize_from_json(self, nv_pairs=None): 61 | if nv_pairs: 62 | for i, (name, value) in enumerate(nv_pairs): 63 | self.override(name, value) 64 | 65 | def override_from_commandline(self, override_args=None): 66 | if override_args is not None: 67 | override = extract_named_args(override_args) 68 | for k, v in override.items(): 69 | name = k[2:] 70 | value = v if v.startswith('"') or v.startswith("'") else try_to_number(v) 71 | if "." in name: 72 | names = name.split(".") 73 | name = names[0] 74 | if len(names) == 2: 75 | if hasattr(self, names[0]): 76 | curdict = getattr(self, names[0]) 77 | else: 78 | curdict = dict() 79 | curdict[names[1]] = value 80 | value = curdict 81 | elif len(names) == 3: 82 | if hasattr(self, names[0]): 83 | curdict = getattr(self, names[0]) 84 | else: 85 | curdict = dict() 86 | 87 | if names[1] in curdict: 88 | subdict = curdict[names[1]] 89 | else: 90 | curdict[names[1]] = dict() 91 | subdict = curdict[names[1]] 92 | 93 | subdict[names[2]] = value 94 | value = curdict 95 | else: 96 | raise Exception("Unsupported command line option (can only override dicts with 1 or 2 levels)") 97 | self.override(name, value) 98 | 99 | # 100 | # Default settings 101 | # 102 | specs = 'default' 103 | 104 | # logging and plotting 105 | plot_at = 100 # plot at each xth weight update 106 | score_at = 100 # calculate score on validation set at each xth weight update 107 | 108 | # GPU and CPU usage 109 | cuda_gpu = "0" 110 | inter_op_parallelism_threads = 1 111 | intra_op_parallelism_threads = 1 112 | log_device_placement = False 113 | 114 | # Default paths 115 | restore = None 116 | working_dir = "working_dir" 117 | -------------------------------------------------------------------------------- /TeLL/evaluation.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | """ 4 | 5 | import sys 6 | import progressbar 7 | import numpy as np 8 | import tensorflow as tf 9 | from collections import OrderedDict 10 | 11 | from TeLL.utility.misc import custom_tensorflow_histogram, check_kill_file 12 | from TeLL.utility.timer import Timer 13 | from TeLL.utility.workingdir import Workspace 14 | 15 | 16 | class Evaluation(object): 17 | def __init__(self, dataset, session, model, workspace: Workspace, summary_tensor_dict=None, scope=None): 18 | """Evaluate model on dataset""" 19 | 20 | # 21 | # Create tensors and tf operations 22 | # 23 | if summary_tensor_dict is None: 24 | summary_tensor_dict = {} 25 | 26 | summary_tensors = [tens[0] if isinstance(tens, tuple) else tens for tens in summary_tensor_dict.values()] 27 | summary_tensor_is_op = [True if isinstance(tens, tuple) else False for tens in summary_tensor_dict.values()] 28 | summary_ops = [tens[1] for tens in summary_tensor_dict.values() if isinstance(tens, tuple)] 29 | 30 | self.dataset = dataset 31 | self.session = session 32 | self.model = model 33 | self.workspace = workspace 34 | self.scope = scope 35 | 36 | self.summary_tensor_dict = summary_tensor_dict 37 | self.summary_tensors = summary_tensors 38 | self.summary_tensor_is_op = summary_tensor_is_op 39 | self.summary_ops = summary_ops 40 | 41 | resetable_tensors = tf.get_collection(tf.GraphKeys.LOCAL_VARIABLES, scope=self.scope.name) 42 | self.variables_initializer = tf.variables_initializer(resetable_tensors) 43 | self.reset_tensors() 44 | 45 | def reset_tensors(self): 46 | if self.scope is not None: 47 | self.session.run([self.variables_initializer]) 48 | 49 | def evaluate(self, step: int, summary_writer, prefix='validation ', num_cached=5, num_threads=3, rnd_gen=None, 50 | plotter=None, model=None): 51 | # Reset streaming measures 52 | self.reset_tensors() 53 | 54 | # Get tensors to evaluate for plotting 55 | if plotter is not None: 56 | plot_tensors = plotter.get_tensors() 57 | 58 | # Set up progress bar 59 | _pbw = ['Evaluating on {}set:'.format(prefix), progressbar.ETA()] 60 | progress = progressbar.ProgressBar(widgets=_pbw, maxval=self.dataset.n_mbs - 1).start() 61 | 62 | # 63 | # Iterate over dataset minibatches 64 | # 65 | mb_validation = self.dataset.batch_loader(num_cached=num_cached, num_threads=num_threads, rnd_gen=rnd_gen) 66 | with Timer(verbose=True, name="Evaluate on {}set".format(prefix)): 67 | summary_values_filled = None 68 | 69 | for mb_i, mb in enumerate(mb_validation): 70 | 71 | # Abort if indicated by file 72 | check_kill_file(self.workspace) 73 | 74 | if mb.get('pixel_weights', None) is None: 75 | feed_dict = {self.model.X: mb['X'], self.model.y_: mb['y']} 76 | else: 77 | feed_dict = {self.model.X: mb['X'], self.model.y_: mb['y'], 78 | self.model.pixel_weights: mb['pixel_weights']} 79 | 80 | if plotter is not None: 81 | evaluated_tensors = self.session.run([*self.summary_ops, *self.summary_tensors, *plot_tensors], 82 | feed_dict=feed_dict) 83 | else: 84 | evaluated_tensors = self.session.run([*self.summary_ops, *self.summary_tensors], 85 | feed_dict=feed_dict) 86 | 87 | # Discard return values from summary_ops (=update operations) 88 | evaluated_tensors = evaluated_tensors[len(self.summary_ops):] 89 | summary_values = evaluated_tensors[:len(self.summary_tensors)] 90 | 91 | # Perform plotting 92 | if plotter is not None: 93 | plotter.set_tensor_values(evaluated_tensors[len(self.summary_tensors):len(self.plot_tensors) + 94 | len(plot_tensors)]) 95 | plotter.plot(evaluate_tensors=False) 96 | 97 | # Re-associate returned tensorflow values to keys and incorporate new minibatch values 98 | if summary_values_filled is None: 99 | # Fill summary_values_filled for the first time 100 | summary_values_filled = OrderedDict(zip(list(self.summary_tensor_dict.keys()), summary_values)) 101 | for key_i, key in enumerate(summary_values_filled.keys()): 102 | if not self.summary_tensor_is_op[key_i]: 103 | if isinstance(summary_values_filled[key], np.ndarray): 104 | summary_values_filled[key] = [summary_values_filled[key]] 105 | elif np.isfinite(summary_values_filled[key]): 106 | summary_values_filled[key] = [summary_values_filled[key]] 107 | else: 108 | summary_values_filled[key] = [] 109 | else: 110 | for key_i, key in enumerate(summary_values_filled.keys()): 111 | if not self.summary_tensor_is_op[key_i]: 112 | if isinstance(summary_values[key_i], np.ndarray): 113 | summary_values_filled[key].append(summary_values[key_i]) 114 | elif np.isfinite(summary_values[key_i]): 115 | summary_values_filled[key].append(summary_values[key_i]) 116 | else: 117 | summary_values_filled[key] = summary_values[key_i] 118 | 119 | # Update progress bar and clear minibatch 120 | progress.update(mb_i) 121 | mb.clear() 122 | del mb 123 | 124 | progress.finish() 125 | 126 | # 127 | # Divide sums by number of samples for tensors that do not have an update function 128 | # 129 | if len(summary_values_filled): 130 | for key_i, key in enumerate(summary_values_filled.keys()): 131 | if not self.summary_tensor_is_op[key_i]: 132 | if len(summary_values_filled[key]): 133 | if not isinstance(summary_values_filled[key][0], np.ndarray): 134 | summary_values_filled[key] = np.mean(summary_values_filled[key]) 135 | else: 136 | summary_values_filled[key] = np.concatenate(summary_values_filled[key]) 137 | else: 138 | summary_values_filled[key] = np.nan 139 | 140 | # 141 | # Go through values to use as summaries, create histograms if values are not scalars 142 | # 143 | values_to_print = OrderedDict() 144 | if len(summary_values_filled): 145 | for key_i, key in enumerate(summary_values_filled.keys()): 146 | if not isinstance(summary_values_filled[key], np.ndarray): 147 | values_to_print.update({key: summary_values_filled[key]}) 148 | summary = tf.Summary(value=[tf.Summary.Value(tag=prefix + key, 149 | simple_value=float(summary_values_filled[key]))]) 150 | else: 151 | hist = custom_tensorflow_histogram(summary_values_filled[key], bins=100) 152 | summary = tf.Summary(value=[tf.Summary.Value(tag=prefix + key, histo=hist)]) 153 | 154 | summary_writer.add_summary(summary, step) 155 | 156 | print("{}scores:\n\tstep {}, {}".format(prefix, step, values_to_print)) 157 | summary_writer.flush() 158 | sys.stdout.flush() 159 | -------------------------------------------------------------------------------- /TeLL/initializations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Functions for initializing tensorflow variables and wrappers for tensorflow initializers 6 | 7 | """ 8 | 9 | import numpy as np 10 | import tensorflow as tf 11 | 12 | 13 | def constant(shape=None, init=0.1, dtype=tf.float32): 14 | if isinstance(init, (float, int)): 15 | initial = tf.constant(init, shape=shape, dtype=dtype) 16 | else: 17 | initial = tf.constant(init, dtype=dtype) 18 | 19 | return initial 20 | 21 | 22 | def orthogonal(shape, gain=np.sqrt(2)): 23 | """ orthogonal initialization method 24 | 25 | Parameters 26 | ------- 27 | shape : array 28 | the shape of the weight matrix. Frist dimension contains the width of the layer below. 29 | """ 30 | return tf.initializers.orthogonal(gain=gain)(shape=shape) 31 | 32 | 33 | def scaled_elu_initialization(shape, truncated=True): 34 | """ Preferred variable initialization method for the scaled ELU activation function. 35 | 36 | Parameters 37 | ------- 38 | shape : array 39 | the shape of the weight matrix. Frist dimension contains the width of the layer below. 40 | truncated : boolean 41 | Whether the truncated normal distribution should be used. 42 | """ 43 | if len(shape) == 4: 44 | f_in = int(np.prod(shape[:-1])) 45 | else: 46 | f_in = shape[0] 47 | 48 | if truncated: 49 | return tf.truncated_normal(shape=shape, stddev=tf.cast(tf.sqrt(1 / f_in), tf.float32)) 50 | else: 51 | return tf.random_normal(shape=shape, stddev=tf.cast(tf.sqrt(1 / f_in), tf.float32)) 52 | 53 | 54 | def scaled_elu_initialization_rec(shape, truncated=True): 55 | """ Preferred variable initialization method for the scaled ELU activation function. 56 | 57 | Parameters 58 | ------- 59 | shape : array 60 | the shape of the weight matrix. Frist dimension contains the width of the layer below. 61 | truncated : boolean 62 | Whether the truncated normal distribution should be used. 63 | """ 64 | if len(shape) == 4: 65 | f_in = int(np.prod(shape[:-1])) 66 | else: 67 | f_in = shape[0] 68 | 69 | if truncated: 70 | return tf.truncated_normal(shape=shape, stddev=tf.cast(tf.sqrt(1 / f_in / 10), tf.float32)) 71 | else: 72 | return tf.random_normal(shape=shape, stddev=tf.cast(tf.sqrt(1 / f_in / 10), tf.float32)) 73 | 74 | 75 | def weight_klambauer_elu(shape, seed=None): 76 | """ Preferred variable initialization method for the non-scaled ELU activation function. 77 | 78 | Parameters 79 | ------- 80 | shape : array 81 | the shape of the weight matrix. First dimension contains the width of the layer below. 82 | seed : integer 83 | seed for the initialization 84 | """ 85 | 86 | klambauer_constat = 1.5505188080679277 87 | initial = tf.contrib.layers.variance_scaling_initializer(factor=klambauer_constat, mode='FAN_IN', 88 | uniform=False, seed=seed, dtype=tf.float32) 89 | return initial(shape) 90 | 91 | 92 | def gaussian(x, mu, std): 93 | return (1. / (np.sqrt(2 * np.pi) * std)) * (np.exp(- (x - mu) * (x - mu) / (2 * std * std))) 94 | 95 | 96 | def weight_xavier(shape, uniform=False, seed=None): 97 | initial = tf.contrib.layers.xavier_initializer(uniform=uniform, seed=seed, dtype=tf.float32) 98 | return initial(shape) 99 | 100 | 101 | def weight_xavier_conv2d(shape, uniform=False, seed=None): 102 | initial = tf.contrib.layers.xavier_initializer_conv2d(uniform=uniform, seed=seed, dtype=tf.float32) 103 | return initial(shape) 104 | 105 | 106 | def weight_he(shape, seed=None): 107 | initial = tf.contrib.layers.variance_scaling_initializer(factor=2.0, mode='FAN_IN', uniform=False, seed=seed, 108 | dtype=tf.float32) 109 | return initial(shape) 110 | 111 | 112 | weight_he_conv2d = weight_he 113 | 114 | 115 | def weight_truncated_normal(shape, stddev=0.1): 116 | initial = tf.truncated_normal(shape, stddev=stddev) 117 | return initial 118 | 119 | 120 | def weight_gauss_conv2d(shape, dtype=np.float32): 121 | # Use gauss PDF with center at middle of axes to initialize weights 122 | x = np.arange(np.ceil(shape[0] / 2)) 123 | if (shape[0] % 2) == 0: 124 | x = np.append(x, x[::-1]) 125 | else: 126 | x = np.append(x, x[-2::-1]) 127 | 128 | p_x = gaussian(x, mu=np.ceil(shape[0] / 2), std=np.ceil(shape[0] / 2) / 4) 129 | 130 | y = np.arange(np.ceil(shape[1] / 2)) 131 | if (shape[1] % 2) == 0: 132 | y = np.append(y, y[::-1]) 133 | else: 134 | y = np.append(y, y[-2::-1]) 135 | 136 | p_y = gaussian(y, mu=np.ceil(shape[1] / 2), std=np.ceil(shape[1] / 2) / 4) 137 | 138 | p_xy = np.outer(p_x, p_y) 139 | 140 | W = np.zeros(shape, dtype=dtype) 141 | W[:, :, :, :] = p_xy[:, :, None, None] 142 | 143 | return constant(init=W) 144 | -------------------------------------------------------------------------------- /TeLL/normalizations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | Functions for normalization 5 | 6 | """ 7 | 8 | import tensorflow as tf 9 | 10 | 11 | def max_norm(tensor): 12 | """Simple normalization by maximum""" 13 | maximum = tf.reduce_max(tf.abs(tensor)) 14 | tensor /= maximum 15 | return tensor 16 | 17 | 18 | def max_norm_all_tensors(tensor_list, clip: bool = True, max_val=tf.constant(1.0)): 19 | """Normalization of list of tensors by maximum of tensors""" 20 | maxima = [tf.reduce_max(tf.abs(tensor)) for tensor in tensor_list] 21 | maxima = tf.stack(maxima) 22 | if clip: 23 | maximum = tf.reduce_max(maxima) + 1e-16 24 | else: 25 | maximum = tf.reduce_max(maxima) 26 | return [tf.divide(tensor, maximum) * max_val for tensor in tensor_list] 27 | 28 | 29 | def euclid_norm(tensor): 30 | """Normalization by euclidean distance""" 31 | summation = tf.reduce_sum(tf.square(tensor)) 32 | tensor /= tf.sqrt(summation) 33 | return tensor 34 | -------------------------------------------------------------------------------- /TeLL/regularization.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Functions for regularization and convenience wrappers for tensorflow regularization functions 6 | 7 | """ 8 | import numbers 9 | 10 | import tensorflow as tf 11 | from tensorflow.python.framework import ops 12 | from tensorflow.python.framework import tensor_shape 13 | from tensorflow.python.framework import tensor_util 14 | from tensorflow.python.layers import utils 15 | from tensorflow.python.ops import array_ops 16 | from tensorflow.python.ops import math_ops 17 | from tensorflow.python.ops import random_ops 18 | 19 | from .layers import get_input 20 | 21 | 22 | def regularize(layers, l1=1e-6, l2=1e-3, regularize_weights=True, regularize_biases=True): 23 | """ Regularize weights and/or biases of given layers if they offer 24 | a function getWeigthts/getBiases respectively to retrieve them. 25 | 26 | Parameters 27 | ------- 28 | layers : objects implementing getWeights and/or getBiases 29 | Array of layers to regularize 30 | l1 : float 31 | Weight of L1 regularization (default = 1e-6) 32 | l2 : float 33 | Weight of L2 regularization (default = 1e-3) 34 | regularize_weights : bool 35 | Regularize only layer weights (default = True) 36 | regularize_biases : bool 37 | Regularize only layer biases (default = True) 38 | 39 | Returns 40 | ------- 41 | Returns combined regularization penalty. 42 | 43 | """ 44 | penalty = 0 45 | for layer in layers: 46 | get_weights = getattr(layer, "get_weights", None) 47 | get_biases = getattr(layer, "get_biases", None) 48 | if regularize_weights and callable(get_weights): 49 | weights = get_weights() 50 | for w in weights: 51 | if l1 != 0: 52 | penalty += l1 * tf.reduce_sum(tf.abs(w)) 53 | if l2 != 0: 54 | penalty += l2 * tf.nn.l2_loss(w) 55 | if regularize_biases and callable(get_biases): 56 | biases = get_biases() 57 | for b in biases: 58 | if l1 != 0: 59 | penalty += l1 * tf.reduce_sum(tf.abs(b)) 60 | if l2 != 0: 61 | penalty += l2 * tf.nn.l2_loss(b) 62 | return penalty 63 | 64 | 65 | def __covar_l1norm(hiddens, enum_dims, feature_dims, n_features): 66 | """ Compute the L1 norm of the covariance matrix of hiddens. """ 67 | enum_dims = list(set(range(len(hiddens.shape.as_list()))) - set(feature_dims)) 68 | centered = hiddens - tf.reduce_mean(hiddens, enum_dims, keep_dims=True) 69 | 70 | # quick-fix 71 | # data2d = tf.reshape(tf.transpose(centered, enum_dims + feature_dims), [-1, n_features]) 72 | data2d = tf.reshape(centered, [-1, n_features]) 73 | 74 | covar_scaled_matrix = tf.matmul(data2d, data2d, transpose_a=True) 75 | covar_l1norm = tf.reduce_sum(tf.abs(covar_scaled_matrix)) 76 | covar_num = tf.to_float(tf.shape(data2d)[0]) 77 | 78 | return covar_l1norm, covar_num 79 | 80 | 81 | def decor_penalty(layer, labels, n_classes, feature_dims, weight=1e-3, is_one_hot=True): 82 | """ Compute layer's decorrelation penalty conditioned on labels. 83 | 84 | For every class in labels, this function computes the L1-norm of the covariance 85 | matrix of the hiddens belonging to that class and returns the sum of these norms 86 | multiplied by weight. 87 | 88 | layer : The layer to regularize. 89 | labels : An integer tensor representing the labels of layer's output on which the 90 | decorrelation should be conditioned. The first tf.rank(labels) dimensions 91 | of labels and layer's output must match. If not one-hot encoded, the values of 92 | labels must be in [0 .. n_classes-1]. 93 | n_classes : The number of distinct classes in labels. 94 | feature_dims : The dimensions (as list) of layer's output representing the features 95 | which are to be decorrelated. 96 | weight : A factor by which to multiply the final score. 97 | is_one_hot : Whether the labels are one-hot or integer encoded. 98 | """ 99 | 100 | # TODO: maybe enable for a list of layers 101 | # TODO: make default arg for feature_dims 102 | 103 | get_hiddens, h_shape = get_input(layer) 104 | hiddens = get_hiddens() 105 | 106 | labels_rank = len(labels.shape.as_list()) 107 | hiddens_rank = len(h_shape) 108 | 109 | if is_one_hot: 110 | labels_rank -= 1 111 | 112 | # ensure label dims come first, feature dims come later 113 | assert (all(labels_rank <= i and i < hiddens_rank for i in feature_dims)) 114 | 115 | # initial score 116 | score = tf.zeros([1]) 117 | denom = tf.zeros([1]) 118 | 119 | # all non-feature dims enumerate the feature instances 120 | enum_dims = list(set(range(len(h_shape))) - set(feature_dims)) 121 | 122 | # compute the total number of features 123 | n_features = 1 124 | for i in feature_dims: 125 | n_features *= h_shape[i] 126 | 127 | # make sure there was no -1 in the product 128 | assert (n_features > 0) 129 | 130 | for i in range(n_classes): 131 | # make boolean mask indicating membership to class i 132 | if is_one_hot: 133 | class_i_mask = tf.equal(labels[:, i], 1) 134 | else: 135 | class_i_mask = tf.equal(labels, i) 136 | # determine if class i is empty 137 | empty = tf.equal(tf.reduce_sum(tf.to_float(class_i_mask)), 0) 138 | 139 | # add _covar_l1norm to score if not empty 140 | l1norm, num = tf.cond(empty, lambda: (tf.zeros([1]), tf.zeros([1])), lambda: __covar_l1norm( 141 | tf.boolean_mask(hiddens, class_i_mask), enum_dims, feature_dims, n_features)) 142 | 143 | score += l1norm 144 | denom += num 145 | 146 | score /= denom 147 | return tf.reduce_sum((score / tf.to_float(n_classes)) * weight) 148 | 149 | 150 | def dropout_selu(x, rate, alpha=-1.7580993408473766, fixedPointMean=0.0, fixedPointVar=1.0, 151 | noise_shape=None, seed=None, name=None, training=False): 152 | """Dropout to a value with rescaling.""" 153 | 154 | def dropout_selu_impl(x, rate, alpha, noise_shape, seed, name): 155 | keep_prob = 1.0 - rate 156 | x = ops.convert_to_tensor(x, name="x") 157 | if isinstance(keep_prob, numbers.Real) and not 0 < keep_prob <= 1: 158 | raise ValueError("keep_prob must be a scalar tensor or a float in the " 159 | "range (0, 1], got %g" % keep_prob) 160 | keep_prob = ops.convert_to_tensor(keep_prob, dtype=x.dtype, name="keep_prob") 161 | keep_prob.get_shape().assert_is_compatible_with(tensor_shape.scalar()) 162 | 163 | alpha = ops.convert_to_tensor(alpha, dtype=x.dtype, name="alpha") 164 | keep_prob.get_shape().assert_is_compatible_with(tensor_shape.scalar()) 165 | 166 | if tensor_util.constant_value(keep_prob) == 1: 167 | return x 168 | 169 | noise_shape = noise_shape if noise_shape is not None else array_ops.shape(x) 170 | random_tensor = keep_prob 171 | random_tensor += random_ops.random_uniform(noise_shape, seed=seed, dtype=x.dtype) 172 | binary_tensor = math_ops.floor(random_tensor) 173 | ret = x * binary_tensor + alpha * (1 - binary_tensor) 174 | 175 | a = tf.sqrt(fixedPointVar / (keep_prob * ((1 - keep_prob) * tf.pow(alpha - fixedPointMean, 2) + fixedPointVar))) 176 | 177 | b = fixedPointMean - a * (keep_prob * fixedPointMean + (1 - keep_prob) * alpha) 178 | ret = a * ret + b 179 | ret.set_shape(x.get_shape()) 180 | return ret 181 | 182 | with ops.name_scope(name, "dropout", [x]) as name: 183 | return utils.smart_cond(training, 184 | lambda: dropout_selu_impl(x, rate, alpha, noise_shape, seed, name), 185 | lambda: array_ops.identity(x)) 186 | -------------------------------------------------------------------------------- /TeLL/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-jku/tensorflow-layer-library/ae2bf342e174e8ad34bb96e4058a18f61f03b13f/TeLL/scripts/__init__.py -------------------------------------------------------------------------------- /TeLL/scripts/dropoutmask.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Functions for dropout masks 6 | 7 | """ 8 | 9 | import tensorflow as tf 10 | import numpy as np 11 | import os 12 | import argparse 13 | from PIL import Image 14 | from TeLL.utility.timer import Timer 15 | import logging 16 | 17 | 18 | def make_ising_mask(shape, keep_prob, num_steps, beta, beta_step=1.01): 19 | """ 20 | Create x ising patterns, return 4 x by flipping the patterns 21 | """ 22 | 23 | # start off with random multinomial samples in range {-1,1} 24 | samples = 2 * tf.multinomial(tf.log([[1 - keep_prob, keep_prob]]), np.prod(shape)) - 1 25 | samples = tf.to_float(tf.reshape(samples, shape)) 26 | ising_filter = tf.constant([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=tf.float32) 27 | ising_filter = tf.reshape(ising_filter, [3, 3, 1, 1]) 28 | 29 | i = tf.constant(0) 30 | beta = tf.constant(beta) 31 | beta_step = tf.constant(beta_step) 32 | 33 | condition = lambda i_, beta_, samples_: tf.less(i_, num_steps) 34 | 35 | def body(i_, beta_, samples_): 36 | # only consider a small subset of bits to flip 37 | 38 | # We've got to find the average of the 4 nearest pixels 39 | # Ideas on how to do this: 40 | # - hand written convolutional kernel 41 | # - shift the matrix 42 | conv = tf.nn.conv2d(samples_, ising_filter, [1, 1, 1, 1], 'SAME') 43 | 44 | # Calculate the energy difference if we flip this pixel 45 | # energy = -1 * mul(conv, samples) 46 | # ed = -1 * mul(conv, -1 * samples) + mul(conv, samples) = 2 * mul(conv, samples) 47 | flip_bit = 2 * tf.multiply(conv, samples_) 48 | 49 | # ok, so here if everything is the same [low energy] this guy is really small. 50 | flip_bit = tf.exp(-beta_ * flip_bit) 51 | flip_bit = tf.to_float(tf.greater(flip_bit, tf.random_uniform(shape))) 52 | bits_to_flip = tf.multinomial(tf.log([[9., 1.]]), np.prod(shape)) 53 | bits_to_flip = tf.to_float(tf.reshape(bits_to_flip, shape)) 54 | flip_bit = tf.to_float(-2 * tf.multiply(flip_bit, bits_to_flip) + 1) 55 | samples_ = tf.multiply(flip_bit, samples_) 56 | if 0: 57 | beta_ = tf.Print(beta_, [tf.reduce_sum(samples_[0, :, :, 0])], message="This is the sum: ") 58 | i_ = tf.add(i_, 1) 59 | beta_ = tf.multiply(beta_, beta_step) 60 | return [i_, beta_, samples_] 61 | 62 | _, _, samples_out = tf.while_loop(condition, body, [i, beta, samples]) 63 | samples_out = (samples_out + 1) / 2 64 | return samples_out 65 | 66 | 67 | def boosted_ising_mask(shape, keep_prob, num_steps, beta, beta_step=1.01): 68 | """ 69 | Create x ising patterns, return 4 x by flipping the patterns 70 | """ 71 | 72 | assert len(shape) == 4 73 | assert shape[0] % 4 == 0 74 | c = shape[3] 75 | shape[3] = 1 76 | if keep_prob == 1: 77 | return tf.constant(1, dtype=tf.float32, shape=shape) 78 | 79 | shape[0] = int(shape[0] / 4) 80 | img_shape = shape[1:] 81 | samples = make_ising_mask(shape, keep_prob, num_steps, beta, beta_step=beta_step) 82 | my_image_list = [] 83 | 84 | for s in tf.split(axis=0, num_or_size_splits=shape[0], value=samples): 85 | s = tf.reshape(s, img_shape) 86 | my_image_list.append(s) 87 | my_image_list.append(tf.image.flip_up_down(s)) 88 | my_image_list.append(tf.image.flip_left_right(s)) 89 | my_image_list.append(tf.image.flip_up_down(my_image_list[-1])) 90 | 91 | for i in range(len(my_image_list)): 92 | my_image_list[i] = tf.reshape(my_image_list[i], [1] + img_shape) 93 | # Create multiple color channels, each with the same values 94 | my_image_list[i] = tf.concat(axis=3, values=c * [my_image_list[i]]) 95 | 96 | return tf.concat(axis=0, values=my_image_list) 97 | 98 | 99 | def parse_args(): 100 | parser = argparse.ArgumentParser() 101 | # parser.add_argument("--config", type=str, default=None, help="Path to the config file") 102 | parser.add_argument("--path", type=str, default="./", help="Path to output the images") 103 | parser.add_argument("--num_images", type=int, default=4, help="Number of images (must be dividable by 4)") 104 | parser.add_argument("--keep_prob", type=float, default=.5, help="Probability for pattern") 105 | parser.add_argument("--num_steps", type=int, default=400, help="Iterations") 106 | parser.add_argument("--width", type=int, default=2000, help="Width of the picture to create") 107 | parser.add_argument("--height", type=int, default=1000, help="Height of the picture to create") 108 | parser.add_argument("--random_num", type=int, default=12345, help="Random number initialization") 109 | parser.add_argument("--gpu", type=str, default=None, help="CUDA_VISIBLE_DEVICES string. Used for resumed runs.") 110 | args = parser.parse_args() 111 | # -- 112 | logging.info("Creating images in {}; keep_prob {}; num_steps {}; gpu {}".format( 113 | args.path, args.keep_prob, args.num_steps, args.gpu)) 114 | return args 115 | 116 | 117 | def main(): 118 | logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s') 119 | args = parse_args() 120 | 121 | out_path = args.path 122 | os.makedirs(out_path, exist_ok=True) 123 | 124 | if not args.num_images % 4 == 0: 125 | raise ValueError("Number of images must be a multiple of 4 due to data augmentation") 126 | 127 | if args.num_images >= 200: 128 | print("Many images are going to be created, an overflow on the GPU could occur") 129 | 130 | if args.gpu is not None: 131 | os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu 132 | else: 133 | os.environ['CUDA_VISIBLE_DEVICES'] = '' 134 | 135 | tf.set_random_seed(args.random_num) 136 | 137 | samples = boosted_ising_mask(shape=[args.num_images, 400, int(400 * (args.width / args.height)), 3], 138 | keep_prob=args.keep_prob, num_steps=args.num_steps, beta=.5, beta_step=1.1) 139 | # samples = tf.image.resize_images(samples, (args.height, args.width), method=tf.image.ResizeMethod.NEAREST_NEIGHBOR) 140 | 141 | logging.info('Samples' + str(samples)) 142 | 143 | with Timer(verbose=True, name="Ising") as t: 144 | gpu_options = tf.GPUOptions(allow_growth=True) 145 | sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) 146 | sess.run(tf.global_variables_initializer()) 147 | samples_np = sess.run(samples) 148 | 149 | 150 | # Append parameters to log file 151 | params = "" 152 | for arg in vars(args): 153 | if arg not in ["path", "gpu"]: 154 | params += arg + ":" + str(getattr(args, arg)) + "-" 155 | 156 | params = params[:-1] 157 | 158 | logfile = os.path.join(out_path, "log.txt") 159 | if os.path.isfile(logfile): 160 | with open(logfile, "r") as f: 161 | x = f.read().split("\n") 162 | offset = int(x[-1].split("\t")[1]) 163 | else: 164 | offset = 0 165 | with open(logfile, "a") as myfile: 166 | myfile.write("\n" + params + "\t" + str(offset + getattr(args, "num_images"))) 167 | 168 | for i in range(samples_np.shape[0]): 169 | out = Image.fromarray(samples_np[i, :, :, 0] * 255) 170 | out = out.convert("1") 171 | out.save(out_path + '/image' + '_' + str(offset + i + 1) + '.png') 172 | 173 | sess.close() 174 | 175 | 176 | if __name__ == "__main__": 177 | main() 178 | -------------------------------------------------------------------------------- /TeLL/scripts/resume.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Script for resuming from saved checkpoint 6 | 7 | """ 8 | # ---------------------------------------------------------------------------------------------------------------------- 9 | # Imports 10 | # ---------------------------------------------------------------------------------------------------------------------- 11 | 12 | import os 13 | import sys 14 | import signal 15 | import subprocess 16 | import argparse 17 | import shlex 18 | 19 | from TeLL.config import Config 20 | from TeLL.utility.misc import extract_to_tmp, rmdir, extract_named_args, extract_unnamed_args 21 | 22 | # ---------------------------------------------------------------------------------------------------------------------- 23 | # Globals 24 | # ---------------------------------------------------------------------------------------------------------------------- 25 | process_handle = None 26 | working_dir = None 27 | kill_retry_max = 10 28 | kill_retry_count = 0 29 | 30 | 31 | # ---------------------------------------------------------------------------------------------------------------------- 32 | # Functions 33 | # ---------------------------------------------------------------------------------------------------------------------- 34 | 35 | def read_config(config: Config, epochs: int = None, gpu: str = None): 36 | """Get config either from file or use default config""" 37 | if os.path.isfile(config): 38 | config = Config.from_file(config) 39 | else: 40 | config = Config() 41 | 42 | config.override("n_epochs", epochs) 43 | config.override("cuda_gpu", gpu) 44 | 45 | if epochs is not None: 46 | config.n_epochs = epochs 47 | 48 | return config 49 | 50 | 51 | def parse_args(): 52 | parser = argparse.ArgumentParser() 53 | parser.add_argument("path", type=str, default=None, 54 | help="Path to previous working directory of run that should be resumed") 55 | args, unknown = parser.parse_known_args() 56 | if args.path is None: 57 | parser.print_help() 58 | sys.exit(1) 59 | # -- 60 | print("Resuming {}".format(args.path)) 61 | return args, unknown 62 | 63 | 64 | def parse_and_merge_args(command, override_args): 65 | parts = shlex.split(command) 66 | result = [parts[0]] 67 | orig_args = extract_named_args(parts[1:]) 68 | override_args = extract_named_args(override_args) 69 | merged = {**orig_args, **override_args} 70 | for k, v in merged.items(): 71 | if v is None: 72 | result.append(k) 73 | else: 74 | result.extend([k, v]) 75 | result.extend(extract_unnamed_args(parts[1:])) 76 | return " ".join(result) 77 | 78 | 79 | def resume(directory: str, unknown_args: str = None): 80 | if os.path.isdir(directory): 81 | results = os.path.join(directory, "results") 82 | archive = os.path.join(directory, "00-script.zip") 83 | if os.path.exists(archive) and os.path.exists(results): 84 | global working_dir 85 | working_dir = extract_to_tmp(archive) 86 | # parse used config 87 | with open(os.path.join(working_dir, "00-INFO")) as f: 88 | command = f.readline().strip() 89 | command = parse_and_merge_args(command, unknown_args) 90 | # start 91 | cmd_sep = " &&" if sys.platform == "win32" else "; " 92 | cmd = ["cd \"{}\"{}".format(working_dir, cmd_sep), 93 | '"{}"'.format(sys.executable), 94 | command, 95 | "--restore \"{}\"".format(directory)] 96 | cmd = " ".join(cmd) 97 | print("Resuming with command '{}' in directory '{}'".format(cmd, working_dir)) 98 | initial_working_dir = os.getcwd() 99 | os.chdir(working_dir) 100 | global process_handle 101 | process_handle = subprocess.Popen(cmd, cwd=working_dir, shell=True, start_new_session=True) 102 | process_handle.wait() 103 | # clean up 104 | print("Cleaning up temp directory...") 105 | os.chdir(initial_working_dir) 106 | rmdir(working_dir) 107 | print("Done!") 108 | else: 109 | print("Can't resume from {}".format(directory)) 110 | 111 | 112 | def sigint_handler(sig, frame): 113 | print("Killing sub-process...") 114 | if process_handle is not None: 115 | global kill_retry_count 116 | while process_handle.returncode is None and kill_retry_count < kill_retry_max: 117 | kill_retry_count += 1 118 | print("Killing sub-process ({})...".format(kill_retry_count)) 119 | try: 120 | os.killpg(os.getpgid(process_handle.pid), signal.SIGTERM) 121 | os.waitpid(process_handle.pid, os.WNOHANG) 122 | except ProcessLookupError: 123 | break 124 | 125 | try: 126 | process_handle.wait(1) 127 | except subprocess.TimeoutExpired: 128 | pass 129 | 130 | if working_dir is not None: 131 | rmdir(working_dir) 132 | 133 | sys.exit(0) 134 | 135 | 136 | def main(): 137 | signal.signal(signal.SIGINT, sigint_handler) 138 | args, unknown_args = parse_args() 139 | 140 | # If resume option specified resume from snapshot and exit here 141 | if args.path is not None: 142 | resume(args.path, unknown_args) 143 | 144 | 145 | if __name__ == "__main__": 146 | main() 147 | -------------------------------------------------------------------------------- /TeLL/session.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | """ 4 | import os 5 | import numpy as np 6 | import tensorflow as tf 7 | from TeLL.config import Config 8 | from TeLL.utility.workingdir import Workspace 9 | from TeLL.utility.timer import Timer 10 | 11 | 12 | def set_seed(seed: int = 12345): 13 | tf.set_random_seed(seed) 14 | 15 | 16 | class TeLLSession(object): 17 | def __init__(self, config: Config = None, summaries: list = ["training"], model_params=None): 18 | """ 19 | Take care of initializing a TeLL environment. 20 | Creates working directory, instantiates network architecture, configures tensorflow and tensorboard. 21 | Furthermore takes care of resuming runs from an existing workspace. 22 | 23 | :param config: Config 24 | config object or None; if None config will be initialized from command line parameter 25 | :param summaries: list 26 | List of names for summary writers, by default one writer named "training" is opened 27 | :param model_params: 28 | Optional dictionary of parameters unpacked and passed to model upon initialization if not None 29 | 30 | :returns: 31 | 32 | tf_session: Tensorflow session 33 | 34 | tf_saver: Tensorflow checkpoint saver 35 | 36 | tf_summaries: dictionary containing tensorflow summary writers, accessible via the names passed upon creation 37 | 38 | model: TeLL model 39 | 40 | step: current global step (0 for new runs otherwise step stored in checkpoint file) 41 | 42 | workspace: TeLL workspace instance 43 | 44 | config: TeLL config object 45 | """ 46 | if config is None: 47 | config = Config() 48 | 49 | # Setup working dir 50 | workspace = Workspace(config.working_dir, config.specs, config.restore) 51 | print("TeLL workspace: {}".format(workspace.working_dir)) 52 | # Import configured architecture 53 | architecture = config.import_architecture() 54 | # Set GPU 55 | os.environ["CUDA_VISIBLE_DEVICES"] = str(config.get_value("cuda_gpu", "0")) 56 | # Some Tensorflow configuration 57 | tf_config = tf.ConfigProto( 58 | inter_op_parallelism_threads=config.get_value("inter_op_parallelism_threads", 1), 59 | intra_op_parallelism_threads=config.get_value("intra_op_parallelism_threads", 1), 60 | log_device_placement=config.get_value("log_device_placement", False) 61 | ) 62 | tf_config.gpu_options.allow_growth = config.get_value("tf_allow_growth", True) 63 | # Start Tensorflow session 64 | print("Starting session...") 65 | tf_session = tf.Session(config=tf_config) 66 | # Set tensorflow random seed 67 | set_seed(config.get_value("random_seed", 12345)) 68 | # 69 | # Init Tensorboard 70 | # 71 | print("Initializing summaries...") 72 | summary_instances = {} 73 | for summary in summaries: 74 | summary_instances[summary] = tf.summary.FileWriter(os.path.join(workspace.get_tensorboard_dir(), summary), 75 | tf_session.graph) 76 | # Initialize Model 77 | if model_params is None: 78 | model = architecture(config=config) 79 | else: 80 | model = architecture(config=config, **model_params) 81 | 82 | # Print number of trainable parameters 83 | trainable_vars = np.sum([np.prod(t.get_shape()) for t in tf.trainable_variables()]) 84 | print("Number of trainable variables: {}".format(trainable_vars)) 85 | 86 | with tf.name_scope("TeLL") as tell_namescope: 87 | # Store global step in checkpoint 88 | tf_global_step = tf.Variable(initial_value=tf.constant(0, dtype=tf.int64), name="tell_global_step", 89 | dtype=tf.int64, trainable=False) 90 | # Define placeholder and operation to dynamically update tf_global_step with a python integer 91 | global_step_placeholder = tf.placeholder_with_default(tf_global_step, shape=tf_global_step.get_shape()) 92 | set_global_step = tf_global_step.assign(global_step_placeholder) 93 | 94 | # 95 | # Add ops to save and restore all the variables 96 | # 97 | tf_saver = tf.train.Saver(max_to_keep=config.get_value("max_checkpoints", 10), sharded=False) 98 | # Expose members 99 | self.tf_session = tf_session 100 | self.tf_saver = tf_saver 101 | self.tf_summaries = summary_instances 102 | 103 | if config.get_value('optimizer', None) is not None: 104 | if isinstance(config.optimizer, list): 105 | self.tf_optimizer = [getattr(tf.train, config.optimizer[i])(**config.optimizer_params[i]) 106 | for i in range(len(config.optimizer))] 107 | else: 108 | self.tf_optimizer = getattr(tf.train, config.optimizer)(**config.optimizer_params) 109 | 110 | self.model = model 111 | self.workspace = workspace 112 | self.config = config 113 | self.global_step = 0 114 | self.__global_step_placeholder = global_step_placeholder 115 | self.__global_step_update = set_global_step 116 | self.__tell_namescope = tell_namescope 117 | 118 | def initialize_tf_variables(self, reset_optimizer_on_restore=False): 119 | """ 120 | Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint). 121 | 122 | :param reset_optimizer_on_restore: Flag indicating whether to reset the optimizer(s) given that this 123 | function call includes a restore operation. 124 | 125 | :return: updated TeLL session 126 | """ 127 | 128 | session = self.tf_session 129 | checkpoint = self.workspace.get_checkpoint() 130 | # 131 | # Initialize or load variables 132 | # 133 | with Timer(name="Initializing variables"): 134 | session.run(tf.global_variables_initializer()) 135 | session.run(tf.local_variables_initializer()) 136 | 137 | if checkpoint is not None: 138 | # restore from checkpoint 139 | self.tf_saver.restore(session, checkpoint) 140 | # get step number from checkpoint 141 | step = session.run(self.__global_step_placeholder) + 1 142 | self.global_step = step 143 | # reopen summaries 144 | for _, summary in self.tf_summaries.items(): 145 | summary.reopen() 146 | summary.add_session_log(tf.SessionLog(status=tf.SessionLog.START), global_step=step) 147 | print("Resuming from checkpoint '{}' at iteration {}".format(checkpoint, step)) 148 | 149 | if self.config.get_value('optimizer', None) is not None: 150 | if reset_optimizer_on_restore: 151 | if isinstance(self.tf_optimizer, list): 152 | for optimizer in self.tf_optimizer: 153 | self.reset_optimizer(optimizer) 154 | else: 155 | self.reset_optimizer(self.tf_optimizer) 156 | else: 157 | for _, summary in self.tf_summaries.items(): 158 | summary.add_graph(session.graph) 159 | 160 | return self 161 | 162 | def reset_optimizer(self, optimizer, trainables=None): 163 | if trainables is None: 164 | trainables = tf.trainable_variables() 165 | 166 | slots = [optimizer.get_slot(var, name) 167 | for name in optimizer.get_slot_names() 168 | for var in trainables] 169 | self.tf_session.run(tf.initialize_variables(filter(None, slots))) 170 | 171 | def save_checkpoint(self, global_step: int): 172 | """ 173 | Store current state in checkpoint. 174 | 175 | :param global_step: current global step variable; has to be stored for resuming later on. 176 | """ 177 | self.global_step = global_step 178 | tf_session = self.tf_session 179 | # Update global step variable 180 | tf_session.run(self.__global_step_update, feed_dict={self.__global_step_placeholder: global_step}) 181 | # Store checkpoint 182 | self.tf_saver.save(tf_session, 183 | os.path.join(self.workspace.get_result_dir(), "checkpoint-{}.ckpt".format(global_step))) 184 | 185 | def close(self, save_checkpoint: bool = True, global_step: int = 0): 186 | """ 187 | Close all tensorflow related stuff and store checkpoint if requested. 188 | 189 | :param save_checkpoint: bool 190 | flag indicating whether current state should be stored in checkpoint 191 | :param global_step: int 192 | if save_checkpoint is True this value is required to store the step in the checkpoint 193 | """ 194 | tf_session = self.tf_session 195 | # Close Summarywriters 196 | for _, summary in self.tf_summaries.items(): 197 | summary.close() 198 | # Save checkpoint 199 | if save_checkpoint: 200 | self.save_checkpoint(global_step) 201 | # Close session 202 | tf_session.close() 203 | # Close and terminate plotting queue and subprocesses 204 | from TeLL.utility.plotting import terminate_plotting_daemon 205 | terminate_plotting_daemon() 206 | -------------------------------------------------------------------------------- /TeLL/utility/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-jku/tensorflow-layer-library/ae2bf342e174e8ad34bb96e4058a18f61f03b13f/TeLL/utility/__init__.py -------------------------------------------------------------------------------- /TeLL/utility/gputools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | """ 6 | from tensorflow.python.client import device_lib 7 | import itertools as it 8 | 9 | 10 | class ResourceManager(object): 11 | def __init__(self): 12 | self.devices = device_lib.list_local_devices() 13 | self.cpus = [x.name for x in self.devices if x.device_type == 'CPU'] 14 | self.gpus = [x.name for x in self.devices if x.device_type == 'GPU'] 15 | self.iterate_cpus = it.cycle(self.cpus) 16 | self.iterate_gpus = it.cycle(self.gpus) 17 | 18 | def next_device(self): 19 | """ 20 | Returns the id of the next available device. If GPUs are present will 21 | cycle through GPUs, otherwise returns CPU ids. 22 | 23 | :return: next available device id 24 | """ 25 | try: 26 | return self.get_next_gpu() 27 | except StopIteration: 28 | return self.get_next_cpu() 29 | 30 | def get_available_cpus(self): 31 | """ 32 | :return: indices of available CPUs 33 | """ 34 | return self.cpus 35 | 36 | def get_available_gpus(self): 37 | """ 38 | :return: indices of available GPUs 39 | """ 40 | return self.gpus 41 | 42 | def get_next_gpu(self): 43 | """ 44 | :return: next available gpu id 45 | """ 46 | return self.iterate_gpus.__next__() 47 | 48 | def get_next_cpu(self): 49 | """ 50 | :return: next available cpu id 51 | """ 52 | return self.iterate_cpus.__next__() 53 | -------------------------------------------------------------------------------- /TeLL/utility/misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Misc. objects that do not import tensorflow 6 | """ 7 | import argparse 8 | import errno 9 | import importlib 10 | import os 11 | import tempfile 12 | import zipfile 13 | from shutil import copyfile 14 | 15 | 16 | # ---------------------------------------------------------------------------------------------------------------------- 17 | # Exceptions 18 | # ---------------------------------------------------------------------------------------------------------------------- 19 | 20 | class AbortRun(Exception): 21 | pass 22 | 23 | 24 | # ---------------------------------------------------------------------------------------------------------------------- 25 | # Functions 26 | # ---------------------------------------------------------------------------------------------------------------------- 27 | 28 | def check_kill_file(workspace): 29 | """raise an AbortRun error if the kill file exists""" 30 | if os.path.isfile(workspace.get_kill_file()): 31 | print("Detected kill file, aborting...") 32 | raise AbortRun 33 | 34 | 35 | def make_sure_path_exists(path): 36 | try: 37 | os.makedirs(path) 38 | except OSError as exception: 39 | if exception.errno != errno.EEXIST: 40 | raise 41 | 42 | 43 | def parse_args(): 44 | parser = argparse.ArgumentParser() 45 | parser.add_argument("--config", type=str, default="config.json", help="JSON file with the model params") 46 | parser.add_argument("--restore", type=str, default=None, help=argparse.SUPPRESS) 47 | args, override_args = parser.parse_known_args() 48 | if len(override_args) == 0: 49 | override_args = None 50 | return args, override_args 51 | 52 | 53 | def touch(path): 54 | with open(path, 'a'): 55 | os.utime(path, None) 56 | 57 | 58 | def chmod(path: str, permissions=0o775, recursive=False): 59 | if recursive: 60 | for root, dirs, files in os.walk(path): 61 | for d in dirs: 62 | try: 63 | os.chmod(os.path.join(root, d), permissions) 64 | except PermissionError: 65 | continue 66 | for f in files: 67 | try: 68 | os.chmod(os.path.join(root, f), permissions) 69 | except PermissionError: 70 | continue 71 | else: 72 | os.chmod(path, permissions) 73 | 74 | 75 | def copydir(src: str, dst: str, exclude: list = None): 76 | if os.path.isdir(dst): 77 | rmdir(dst) 78 | for root, dirs, files in os.walk(src): 79 | for file in files: 80 | f = os.path.realpath(os.path.join(root, file)) 81 | # don't add files / folders in exclude 82 | exclude_file = False 83 | if exclude: 84 | for entry in exclude: 85 | if os.path.realpath(entry) in f: 86 | exclude_file = True 87 | break 88 | 89 | if not exclude_file: 90 | d = f.replace(os.path.realpath(src), os.path.realpath(dst)) 91 | if not os.path.exists(os.path.dirname(d)): 92 | os.makedirs(os.path.dirname(d)) 93 | copyfile(f, d) 94 | 95 | 96 | def rmdir(path: str): 97 | if os.path.exists(path): 98 | for root, dirs, files in os.walk(path): 99 | for d in dirs: 100 | current = os.path.join(root, d) 101 | try: 102 | rmdir(current) 103 | except PermissionError: 104 | continue 105 | for f in files: 106 | try: 107 | os.remove(os.path.join(root, f)) 108 | except PermissionError: 109 | continue 110 | os.rmdir(path) 111 | 112 | 113 | def zipdir(dir, zip, info=None, exclude=None): 114 | # canonicalize paths 115 | dir = os.path.realpath(dir) 116 | zip = os.path.realpath(zip) 117 | # open zipfile 118 | zipf = zipfile.ZipFile(zip, 'w', zipfile.ZIP_DEFLATED) 119 | 120 | if info: 121 | zipf.writestr("00-INFO", info) 122 | 123 | # add dir 124 | for root, dirs, files in os.walk(dir): 125 | for file in files: 126 | f = os.path.realpath(os.path.join(root, file)) 127 | # don't add zip archive to itself 128 | if zip == os.path.join(root, file) or "__pycache__" in f: 129 | continue 130 | # don't add files / folders in exclude 131 | exclude_file = False 132 | if exclude: 133 | for entry in exclude: 134 | if os.path.realpath(entry) in f: 135 | exclude_file = True 136 | break 137 | 138 | if not exclude_file: 139 | zipf.write(filename=f, arcname=f[len(dir):]) 140 | zipf.close() 141 | 142 | 143 | def import_object(objname): 144 | objmodule = importlib.import_module(objname.split('.', maxsplit=1)[0]) 145 | return get_rec_attr(objmodule, objname.split('.', maxsplit=1)[-1]) 146 | 147 | 148 | def get_rec_attr(module, attrstr): 149 | """Get attributes and do so recursively if needed""" 150 | if attrstr is None: 151 | return None 152 | attrs = attrstr.split('.') 153 | for attr in attrs: 154 | module = getattr(module, attr) 155 | return module 156 | 157 | 158 | def load_architecture(arch_name: str = None): 159 | """Import an architecture defined as a class in a file in the current namespace. 160 | 161 | :param arch_name 162 | name of architecture to load; format: . 163 | 164 | :returns architecture handle or none if not found 165 | """ 166 | architecture = importlib.import_module(arch_name.split('.', maxsplit=1)[0]) 167 | return get_rec_attr(architecture, arch_name.split('.', maxsplit=1)[-1]) 168 | 169 | 170 | def extract_to_tmp(file: str): 171 | tempdir = tempfile.mkdtemp("tell") 172 | ziphandle = zipfile.ZipFile(file, "r") 173 | ziphandle.extractall(tempdir) 174 | ziphandle.close() 175 | return tempdir 176 | 177 | 178 | def get_tensor_shape_list(tensor): 179 | """get shape of a tf tensor as list of integers usable as conventional shape""" 180 | return [d if isinstance(d, int) else -1 for d in tensor.shape.as_list()] 181 | 182 | 183 | def load_files_in_dir(directory: str, suffix: str = ''): 184 | """Search for all files in sample_directory (optionally) with suffix sample_suffix an return them as pandas 185 | dataframe 186 | 187 | Parameters 188 | ------- 189 | directory : str 190 | Directory to search for files in 191 | suffix : str 192 | If a string is provided as sample_suffix, the file names without this suffix will be ignored 193 | 194 | Returns 195 | ------- 196 | : pd.DataFrame 197 | Pandas dataframe with base filenames (=filenames without path or suffix) as keys and full filenames as values; 198 | Dataframe is sorted by full filenames; 199 | """ 200 | from os import path 201 | import glob.glob 202 | import pandas as pd 203 | 204 | sample_pattern = "**/*{}".format(suffix) 205 | 206 | # Collect files in path, sort them by name, and store them into dictionary 207 | samples = glob.glob(path.join(directory, sample_pattern)) 208 | samples.sort() 209 | 210 | # Extract base filenames without path or suffix and store them as keys for the pandas dataframe 211 | keys = [path.basename(file)[:-len(suffix)] for file in samples] 212 | 213 | # Store in data frame for easy indexing and fast key->value access 214 | samples = pd.DataFrame(index=keys, data=samples) 215 | 216 | return samples 217 | 218 | 219 | def custom_tensorflow_histogram(values, bins=100): 220 | import numpy as np 221 | import tensorflow as tf 222 | 223 | # Create histogram using numpy 224 | counts, bin_edges = np.histogram(values, bins=bins) 225 | 226 | # Fill fields of histogram proto 227 | hist = tf.HistogramProto() 228 | if len(values): 229 | hist.min = float(np.min(values)) 230 | hist.max = float(np.max(values)) 231 | hist.num = int(np.prod(values.shape)) 232 | hist.sum = float(np.sum(values)) 233 | hist.sum_squares = float(np.sum(values ** 2)) 234 | else: 235 | hist.min = 0 236 | hist.max = 0 237 | hist.num = 0 238 | hist.sum = 0 239 | hist.sum_squares = 0 240 | bin_edges = bin_edges[1:] 241 | 242 | # Add bin edges and counts 243 | for edge in bin_edges: 244 | hist.bucket_limit.append(edge) 245 | for c in counts: 246 | hist.bucket.append(int(c)) 247 | 248 | return hist 249 | 250 | 251 | def extract_named_args(arglist): 252 | result = {} 253 | for i in range(0, len(arglist)): 254 | a = arglist[i] 255 | if a.startswith("--"): 256 | if i + 1 < len(arglist) and not arglist[i + 1].startswith("--"): 257 | result[a] = arglist[i + 1] 258 | else: 259 | result[a] = None 260 | return result 261 | 262 | 263 | def extract_unnamed_args(arglist): 264 | result = [] 265 | for i in range(1, len(arglist)): 266 | a = arglist[i] 267 | p = arglist[i - 1] 268 | if not a.startswith("--") and not p.startswith("--"): 269 | result.append(a) 270 | return result 271 | 272 | 273 | def try_to_number(value): 274 | try: 275 | value = int(value) 276 | except ValueError: 277 | try: 278 | value = float(value) 279 | except ValueError: 280 | pass 281 | return value 282 | 283 | 284 | # ---------------------------------------------------------------------------------------------------------------------- 285 | # Classes 286 | # ---------------------------------------------------------------------------------------------------------------------- 287 | 288 | class Tee(object): 289 | """Created from snippets on stackoverflow""" 290 | def __init__(self, original_stdout, *files): 291 | self.files = files 292 | self.original_stdout = original_stdout 293 | 294 | def write(self, obj): 295 | for f in self.files: 296 | f.write(obj) 297 | 298 | def flush(self): 299 | try: 300 | self.original_stdout.flush() 301 | except AttributeError: 302 | # if original_stdout does not support flush() 303 | pass 304 | -------------------------------------------------------------------------------- /TeLL/utility/misc_tensorflow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2018 4 | 5 | Misc. objects that import tensorflow 6 | """ 7 | import tensorflow as tf 8 | import TeLL.layers 9 | from TeLL.utility.misc import get_rec_attr, import_object 10 | 11 | 12 | # ---------------------------------------------------------------------------------------------------------------------- 13 | # Functions 14 | # ---------------------------------------------------------------------------------------------------------------------- 15 | 16 | def layers_from_specs(incoming, layerspecs, verbose=True): 17 | """Create a single-branch-network from a list of layer specifications; beta-state convenience function; 18 | 19 | Create a network from a list of layer specifications (dictionaries); does only work for simple 20 | single-branch-networks, for more flexible designs, please create your network directly; layer in list will be 21 | created one-by-one, each with previous layer as input; 22 | If weight initializers ('W' or 'weight_initializer') are iterables with length>1, the first element is treated as 23 | function and the others as arguments for the function; otherwise, weight initializers is treated as function; 24 | This function has not been tested for all layers, use carefully/adapt to your needs; 25 | 26 | 27 | Parameters 28 | ---------- 29 | incoming : layer, tensorflow tensor, or placeholder 30 | Incoming layer 31 | layerspecs : list of dicts or dict-likes 32 | Network design as list of dictionaries, where each dict represents the layer parameters as kwargs and requires 33 | the additional key "type" with a string value that is the TeLL layer-class name. 34 | 35 | Returns 36 | ---------- 37 | list of TeLL Layer objects 38 | Network as list of connected TeLL layers 39 | 40 | Example 41 | ------- 42 | >>> # Creating a network containing a convolutional layer, followed by maxpooling and another convolutional layer 43 | >>> batchsize, x_dim, y_dim, channels = (5, 28, 28, 3) 44 | >>> network_input = tf.placeholder(shape=(batchsize, x_dim, y_dim, channels), dtype=tf.float32) 45 | >>> layerspecs = [{"type": "ConvLayer", "name": "c1", "num_outputs": 32, "ksize": 3, "a": "tensorflow.nn.relu", 46 | >>> "weight_initializer": "0.1:tensorflow.orthogonal_initializer"}, 47 | >>> {"type": "MaxPoolingLayer", "name": "mp1", "ksize": [1, 2, 2, 1], "strides": [1, 2, 2, 1]}, 48 | >>> {"type": "ConvLayer", "name": "c2", "num_outputs": 64, "ksize": 3, "a": "tensorflow.nn.relu", 49 | >>> "weight_initializer": "tensorflow.orthogonal_initializer"}] 50 | >>> tell_network = layers_from_specs(incoming=network_input, layerspecs=layerspecs) 51 | >>> output_tensor = tell_network[-1].get_output() 52 | """ 53 | layers = [incoming] 54 | for l_i, layerspec in enumerate(layerspecs): 55 | layertype = layerspec['type'] 56 | if verbose: 57 | print("\t\tbuilding {}...".format(layertype), end='') 58 | layer = get_rec_attr(TeLL.layers, layertype) 59 | 60 | # Replace strings with corresponding functions and remove the "type" field 61 | layerspec = layerspec.copy() 62 | if 'a' in layerspec.keys(): 63 | layerspec['a'] = import_object(layerspec['a']) 64 | if 'W' in layerspec.keys(): 65 | W = layerspec['W'].split(':') 66 | if len(W) == 1: 67 | layerspec['W'] = import_object(W[0])() 68 | else: 69 | winit_fct = import_object(W[-1]) 70 | winit_args = [float(a) for a in W[:-1]] 71 | layerspec['W'] = winit_fct(*winit_args) 72 | 73 | if 'weight_initializer' in layerspec.keys(): 74 | weight_initializer = layerspec['weight_initializer'].split(':') 75 | if len(weight_initializer) == 1: 76 | layerspec['weight_initializer'] = import_object(weight_initializer[0])() 77 | else: 78 | winit_fct = import_object(weight_initializer[-1]) 79 | winit_args = [float(a) for a in weight_initializer[:-1]] 80 | layerspec['weight_initializer'] = winit_fct(*winit_args) 81 | 82 | if layerspec.get('name', None) is None: 83 | layerspec['name'] = "{}_{}".format(l_i, layerspec['type']) 84 | del layerspec['type'] 85 | 86 | layers.append(layer(layers[-1], **layerspec)) 87 | if verbose: 88 | print(" in {} / out {}".format(layers[-2].get_output_shape(), layers[-1].get_output_shape())) 89 | return layers[1:] 90 | 91 | 92 | def tensor_shape_with_flexible_dim(tensor, dim): 93 | """Return shape of tensor with dimension dim as a flexible dimension 94 | 95 | Parameters 96 | ---------- 97 | tensor : tensor 98 | Tensor of which to return shape with a flexible dimension 99 | 100 | dim : int 101 | Index of dimension to replace with a flexible dimension 102 | """ 103 | shape_list = tensor.shape.as_list() 104 | shape_list = [s if s_i != dim else None for s_i, s in enumerate(shape_list)] 105 | return tf.TensorShape(shape_list) 106 | 107 | 108 | # ---------------------------------------------------------------------------------------------------------------------- 109 | # Classes 110 | # ---------------------------------------------------------------------------------------------------------------------- 111 | 112 | class TriangularValueEncoding(object): 113 | def __init__(self, max_value: int, triangle_span: int): 114 | """Encodes an integer value with range [0, max_value] as multiple activations between 0 and 1 via triangles of 115 | width triangle_span; 116 | 117 | LSTM profits from having an integer input with large range split into multiple input nodes; This class encodes 118 | an integer as multiple nodes with activations of range [0,1]; Each node represents a triangle of width 119 | triangle_span; These triangles are distributed equidistantly over the integer range such that 2 triangles 120 | overlap by 1/2 width and the whole integer range is covered; For each integer to encode, the high of the 121 | triangle at this integer position is taken as node activation, i.e. max. 2 nodes have an activation > 0 for each 122 | integer value; 123 | 124 | Values are encoded via encode_value(value) and returned as float32 tensorflow tensor of length self.n_nodes; 125 | 126 | Parameters 127 | ---------- 128 | max_value : int 129 | Maximum value to encode 130 | triangle_span : int 131 | Width of each triangle 132 | """ 133 | # round max_value up to a multiple of triangle_span 134 | if max_value % triangle_span != 0: 135 | max_value = ((max_value // triangle_span) + 1) * triangle_span 136 | 137 | # Calculate number of overlapping triangle nodes 138 | n_nodes_half = int(max_value / triangle_span) 139 | n_nodes = n_nodes_half * 2 + 1 140 | 141 | # Template for tensor 142 | coding = tf.zeros((n_nodes,), dtype=tf.float32, name='ingametime') 143 | 144 | self.n_nodes_python = n_nodes 145 | self.n_nodes = tf.constant(n_nodes, dtype=tf.int32) 146 | self.n_nodes_half = tf.constant(n_nodes_half, dtype=tf.int32) 147 | self.max_value = tf.constant(max_value, dtype=tf.int32) 148 | self.triangle_span = tf.constant(triangle_span, dtype=tf.int32) 149 | self.triangle_span_float = tf.constant(triangle_span, dtype=tf.float32) 150 | self.half_triangle_span = tf.cast(self.triangle_span / 2, dtype=tf.int32) 151 | self.half_triangle_span_float = tf.cast(self.triangle_span / 2, dtype=tf.float32) 152 | self.coding = coding 153 | 154 | def encode_value(self, value): 155 | """Encode value as multiple triangle node activations 156 | 157 | Parameters 158 | ---------- 159 | value : int tensor 160 | Value to encode as integer tensorflow tensor 161 | 162 | Returns 163 | ---------- 164 | float32 tensor 165 | Encoded value as float32 tensor of length self.n_nodes 166 | """ 167 | value_float = tf.cast(value, dtype=tf.float32) 168 | 169 | index = tf.cast(value / self.triangle_span, dtype=tf.int32) 170 | act = (tf.constant(0.5, dtype=tf.float32) 171 | - (tf.mod(tf.abs(value_float - self.half_triangle_span_float), self.triangle_span_float) 172 | / self.triangle_span_float)) * tf.constant(2, dtype=tf.float32) 173 | coding1 = tf.one_hot(index, on_value=act, depth=self.n_nodes, dtype=tf.float32) 174 | 175 | index = tf.cast((value + self.half_triangle_span) / self.triangle_span, dtype=tf.int32) + self.n_nodes_half 176 | act = (tf.mod(tf.abs(value_float - self.half_triangle_span_float), self.triangle_span_float) 177 | / self.triangle_span_float) * tf.constant(2, dtype=tf.float32) 178 | coding2 = tf.one_hot(index, on_value=act, depth=self.n_nodes, dtype=tf.float32) 179 | 180 | return coding1 + coding2 181 | -------------------------------------------------------------------------------- /TeLL/utility/plotting_daemons.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Handling of worker subprocesses and threads for plotting 6 | 7 | """ 8 | 9 | from multiprocess import Pool 10 | 11 | 12 | def stop_plotting_daemon(plotting_queue, plotting_proc): 13 | """End plotting daemon process properly""" 14 | # tell process to finish 15 | plotting_queue.put(0) 16 | # reap process 17 | plotting_proc.join() 18 | 19 | 20 | def launch_proc(target, arguments, wait=False, daemon=True): 21 | import multiprocessing as mp 22 | proc = mp.Process(target=target, args=arguments) 23 | proc.daemon = daemon 24 | proc.start() 25 | if wait: 26 | proc.wait() 27 | return proc 28 | 29 | 30 | def plotting_demon(plotting_queue, multicore): 31 | print("Starting plotting daemon...", end=" ") 32 | pool = Pool(processes=multicore) 33 | print("Done!") 34 | while True: 35 | rec = plotting_queue.get() 36 | if rec == 0: 37 | break 38 | func, arguments = rec 39 | if isinstance(arguments, tuple): 40 | pool.apply_async(func, *arguments) 41 | else: 42 | pool.apply_async(func, arguments) 43 | 44 | pool.close() 45 | pool.join() 46 | del pool 47 | print("Plotting daemon terminated.") 48 | exit(0) 49 | 50 | 51 | def start_plotting_daemon(wait=False, multicore=3): 52 | """ Launch programms with plotting_queue.put(function, (args, kwargs))""" 53 | import multiprocessing as mp 54 | plotting_queue = mp.Queue() 55 | proc = launch_proc(target=plotting_demon, arguments=[plotting_queue, multicore], daemon=False, wait=wait) 56 | return (plotting_queue, proc) -------------------------------------------------------------------------------- /TeLL/utility/timer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | """ 6 | import time 7 | 8 | 9 | class Timer(object): 10 | def __init__(self, name="", verbose=True, precision='msec'): 11 | self.verbose = verbose 12 | self.name = name 13 | self.precision = precision 14 | self.start = time.time() 15 | self.end = self.start 16 | self.secs = 0 17 | self.msecs = 0 18 | 19 | def __enter__(self): 20 | self.start = time.time() 21 | return self 22 | 23 | def __exit__(self, *args): 24 | if self.verbose: 25 | self.print() 26 | 27 | def print(self): 28 | self.end = time.time() 29 | self.secs = self.end - self.start 30 | self.msecs = self.secs * 1000 # millisecs 31 | if self.precision == 'msec': 32 | print('Timer ({0}): {1:.2f} ms'.format(self.name, self.msecs)) 33 | else: 34 | print('Timer ({0}): {1:.3f} s'.format(self.name, self.secs)) 35 | -------------------------------------------------------------------------------- /TeLL/utility/workingdir.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | """ 6 | import os 7 | import sys 8 | import datetime as dt 9 | import glob 10 | import tempfile 11 | import TeLL 12 | from natsort import natsorted 13 | from TeLL.utility.misc import make_sure_path_exists, touch, zipdir, chmod, copydir, rmdir 14 | import __main__ 15 | 16 | 17 | class Workspace(object): 18 | def __init__(self, workspace: str, specs: str, restore: str = None): 19 | """ 20 | 21 | :param workspace: str 22 | path to general workspace directory 23 | :param specs: str 24 | short description of specs for a specific test run; 25 | will be part of the run specific working directory so don't use spaces or special chars 26 | """ 27 | self.workspace = os.path.realpath(workspace) 28 | self.specs = specs 29 | 30 | if restore is None: 31 | self.timestamp = dt.datetime.now().strftime("%Y-%m-%dT%H-%M-%S") 32 | self.working_dir, self.result_dir, self.tensorboard_dir, self.kill_file, self.plot_file, self.checkpoint = self.__setup_working_dir__() 33 | else: 34 | self.working_dir, self.result_dir, self.tensorboard_dir, self.kill_file, self.plot_file, self.checkpoint = self.__resume_from_dir__( 35 | restore) 36 | 37 | def get_result_dir(self): 38 | return self.result_dir 39 | 40 | def get_tensorboard_dir(self): 41 | return self.tensorboard_dir 42 | 43 | def get_kill_file(self): 44 | return self.kill_file 45 | 46 | def get_plot_file(self): 47 | return self.plot_file 48 | 49 | def get_timestamp(self): 50 | return self.timestamp 51 | 52 | def get_checkpoint(self): 53 | return self.checkpoint 54 | 55 | def __setup_working_dir__(self): 56 | # fix permissions of workspace root 57 | make_sure_path_exists(self.workspace) 58 | try: 59 | chmod(self.workspace, 0o775) 60 | except PermissionError: 61 | print("PermissionError when trying to change permissions of workspace to 775") 62 | 63 | # setup working directory 64 | specs_dir = os.path.realpath("{}/{}".format(self.workspace, self.specs)) 65 | working_dir = os.path.realpath("{}/{}".format(specs_dir, self.timestamp)) 66 | # Set up result folder structure 67 | results_path = "{}/results".format(working_dir, self.timestamp) 68 | make_sure_path_exists(results_path) 69 | 70 | # Set up tensorboard directory 71 | tensorboard = "{}/tensorboard".format(working_dir, self.timestamp) 72 | make_sure_path_exists(tensorboard) 73 | 74 | # set path to kill file (if this file exists abort run) 75 | kill_file_name = "ABORT_RUN" 76 | kill_file = os.path.join(working_dir, kill_file_name) 77 | 78 | # create plot file to plot by default 79 | plot_file_name = "PLOT_ON" 80 | plot_file = os.path.join(working_dir, plot_file_name) 81 | touch(plot_file) 82 | 83 | # remove kill file before starting the run (should not exist anyway) 84 | if os.path.isfile(kill_file): 85 | os.remove(kill_file) 86 | 87 | # fix permissions to grant group write access (to allow kill_file creation and plot control) 88 | try: 89 | chmod(self.workspace, 0o775, recursive=False) 90 | chmod(specs_dir, 0o775, recursive=False) 91 | chmod(working_dir, 0o775, recursive=True) 92 | chmod(plot_file, 0o664) 93 | except PermissionError: 94 | print("PermissionError when trying to change permissions of workspace to 775") 95 | 96 | # compress and copy current script and dependencies to results dir 97 | command = " ".join(sys.argv) 98 | # copy current code to temp dir 99 | script_dir = os.path.dirname(os.path.realpath(__main__.__file__)) 100 | tempdir = tempfile.mkdtemp("tell") 101 | copydir(script_dir, tempdir, 102 | exclude=[self.workspace, os.path.join(script_dir, ".git"), os.path.join(script_dir, ".idea"), 103 | os.path.join(script_dir, "__pycache__")]) 104 | # also copy currently used TeLL library so it can be used for resuming runs 105 | copydir(TeLL.__path__[0], os.path.join(tempdir, os.path.basename(TeLL.__path__[0]))) 106 | rmdir(os.path.join(os.path.join(tempdir, os.path.basename(TeLL.__path__[0])), "__pycache__")) 107 | zipdir(dir=tempdir, zip=os.path.join(working_dir, '00-script.zip'), info=command, 108 | exclude=[self.workspace, '.git']) 109 | rmdir(tempdir) 110 | return [working_dir, results_path, tensorboard, kill_file, plot_file, None] 111 | 112 | def __resume_from_dir__(self, dir): 113 | # setup working directory 114 | working_dir = os.path.realpath(dir) 115 | self.timestamp = os.path.basename(working_dir) 116 | 117 | # Set up result folder structure 118 | results_path = "{}/results".format(working_dir, self.timestamp) 119 | 120 | # Set up tensorboard directory 121 | tensorboard = "{}/tensorboard".format(working_dir, self.timestamp) 122 | 123 | # set path to kill file (if this file exists abort run) 124 | kill_file_name = "ABORT_RUN" 125 | kill_file = os.path.join(working_dir, kill_file_name) 126 | if os.path.exists(kill_file): 127 | os.remove(kill_file) 128 | 129 | # create plot file to plot by default 130 | plot_file_name = "PLOT_ON" 131 | plot_file = os.path.join(working_dir, plot_file_name) 132 | 133 | if not (os.path.exists(results_path) or not os.path.exists(tensorboard)): 134 | raise Exception("can not resume from given directory") 135 | 136 | checkpoints = glob.glob1(results_path, "*.ckpt*") 137 | checkpoints = [checkpoint for checkpoint in checkpoints if 138 | not (".meta" in checkpoint or ".index" in checkpoint)] 139 | checkpoints = natsorted(checkpoints) 140 | checkpoint = os.path.join(results_path, checkpoints[-1]) 141 | 142 | if not os.path.exists(checkpoint): 143 | raise Exception("could not find checkpoint in given directory") 144 | 145 | if not checkpoint.endswith("ckpt"): 146 | checkpoint = checkpoint[:checkpoint.index(".ckpt.") + 5] 147 | 148 | return [working_dir, results_path, tensorboard, kill_file, plot_file, checkpoint] 149 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-jku/tensorflow-layer-library/ae2bf342e174e8ad34bb96e4058a18f61f03b13f/__init__.py -------------------------------------------------------------------------------- /samples/config_convlstm.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "ArchitectureConvLSTM", 3 | "cuda_gpu": "0", 4 | "architecture": "sample_architectures.ArchitectureConvLSTM", 5 | "dataset": { 6 | "reader": "TeLL.datareaders.MovingDots", 7 | "train": { 8 | "n_timesteps": 5, 9 | "n_samples": 50, 10 | "random_seed": 12345 11 | }, 12 | "val": { 13 | "n_timesteps": 5, 14 | "n_samples": 25, 15 | "random_seed": 54321 16 | } 17 | }, 18 | "n_epochs": 100, 19 | "score_at": 1000, 20 | "plot_at": 50, 21 | "batchsize": 10, 22 | "optimizer_params": { 23 | "learning_rate": 1e-2 24 | }, 25 | "optimizer": "AdamOptimizer", 26 | "l1": 1e-6, 27 | "l2": 1e-5, 28 | "n_lstm": 3, 29 | "kernel_lstm_fwd": 5, 30 | "kernel_lstm_bwd": 5, 31 | "reduced_rec_lstm": false, 32 | "tickersteps": 3, 33 | "lstm_act": "nn.elu", 34 | "store_states": true, 35 | "kernel_conv": 3, 36 | "working_dir": "working_dir" 37 | } -------------------------------------------------------------------------------- /samples/config_convlstm_mnist.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "ArchitectureConvLSTM", 3 | "cuda_gpu": "0", 4 | "architecture": "sample_architectures.ArchitectureConvLSTMMNIST", 5 | "dataset": { 6 | "reader": "TeLL.datareaders.MovingMNIST", 7 | "scaling_factor": [ 8 | 1.0, 9 | 1.1 10 | ], 11 | "scaling_velocity": [ 12 | 0, 13 | 0.1 14 | ], 15 | "velocity": [ 16 | 5.6, 17 | 14 18 | ], 19 | "rotation_angle": [ 20 | 0, 21 | 360 22 | ], 23 | "rotation_velocity": [ 24 | 0, 25 | 5 26 | ], 27 | "n_objects": 2, 28 | "train": { 29 | "dset": "train", 30 | "n_timesteps": 20, 31 | "n_samples": 5000, 32 | "random_seed": 12345 33 | }, 34 | "val": { 35 | "dset": "validation", 36 | "n_timesteps": 20, 37 | "n_samples": 250, 38 | "random_seed": 54321 39 | } 40 | }, 41 | "n_epochs": 100, 42 | "score_at": 1000, 43 | "plot_at": 50, 44 | "batchsize": 5, 45 | "optimizer_params": { 46 | "learning_rate": 1e-4 47 | }, 48 | "optimizer": "AdamOptimizer", 49 | "l1": 1e-6, 50 | "l2": 1e-5, 51 | "enc_dec_depth": 2, 52 | "n_lstm": 64, 53 | "kernel_lstm_fwd": 3, 54 | "kernel_lstm_bwd": 3, 55 | "forgetgate": true, 56 | "lstm_output_dropout": false, 57 | "reduced_rec_lstm": false, 58 | "tickersteps": 0, 59 | "lstm_act": "nn.elu", 60 | "store_states": true, 61 | "kernel_conv": 3, 62 | "kernel_conv_out": 1, 63 | "working_dir": "working_dir" 64 | } -------------------------------------------------------------------------------- /samples/config_dense.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "ArchitectureDense", 3 | "cuda_gpu": "0", 4 | "architecture": "sample_architectures.ArchitectureDense", 5 | "dataset": { 6 | "reader": "TeLL.datareaders.ShortLongDataset", 7 | "train": { 8 | "n_timesteps": 250, 9 | "n_samples": 3000, 10 | "random_seed": 12345 11 | }, 12 | "val": { 13 | "n_timesteps": 250, 14 | "n_samples": 300, 15 | "random_seed": 54321 16 | } 17 | }, 18 | "n_epochs": 100, 19 | "score_at": 1000, 20 | "batchsize": 15, 21 | "optimizer_params": { 22 | "learning_rate": 1e-3 23 | }, 24 | "optimizer": "AdamOptimizer", 25 | "l1": 1e-6, 26 | "l2": 1e-5, 27 | "n_dense": 25, 28 | "working_dir": "working_dir" 29 | } -------------------------------------------------------------------------------- /samples/config_lstm.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "ArchitectureLSTM", 3 | "cuda_gpu": "0", 4 | "architecture": "sample_architectures.ArchitectureLSTM", 5 | "dataset": { 6 | "reader": "TeLL.datareaders.ShortLongDataset", 7 | "train": { 8 | "n_timesteps": 250, 9 | "n_samples": 3000, 10 | "random_seed": 12345 11 | }, 12 | "val": { 13 | "n_timesteps": 250, 14 | "n_samples": 300, 15 | "random_seed": 54321 16 | } 17 | }, 18 | "n_epochs": 100, 19 | "score_at": 1000, 20 | "batchsize": 15, 21 | "optimizer_params": { 22 | "learning_rate": 1e-3 23 | }, 24 | "optimizer": "AdamOptimizer", 25 | "l1": 1e-6, 26 | "l2": 1e-5, 27 | "n_lstm": 5, 28 | "tickersteps": 0, 29 | "working_dir": "working_dir" 30 | } -------------------------------------------------------------------------------- /samples/config_lstm3.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "ArchitectureLSTM3", 3 | "cuda_gpu": "0", 4 | "architecture": "sample_architectures.ArchitectureLSTM3", 5 | "n_epochs": 100, 6 | "dataset": { 7 | "reader": "TeLL.datareaders.ShortLongDataset", 8 | "train": { 9 | "n_timesteps": 250, 10 | "n_samples": 3000, 11 | "random_seed": 12345 12 | }, 13 | "val": { 14 | "n_timesteps": 250, 15 | "n_samples": 300, 16 | "random_seed": 54321 17 | } 18 | }, 19 | "score_at": 1000, 20 | "batchsize": 15, 21 | "optimizer_params": { 22 | "learning_rate": 1e-3 23 | }, 24 | "optimizer": "AdamOptimizer", 25 | "l1": 1e-6, 26 | "l2": 1e-5, 27 | "n_lstm": 5, 28 | "tickersteps": 0, 29 | "n_dense_units": [ 30 | 20, 31 | 20 32 | ], 33 | "working_dir": "working_dir" 34 | } -------------------------------------------------------------------------------- /samples/main_convlstm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Main file for simple convLSTM example 6 | 7 | Main file for simple convLSTM example to be used with convLSTM architecture in sample_architectures and config file 8 | config_convlstm.json; Plots input, output, weights, ConvLSTM output (of 2 ConvLSTM units), and cell states in 9 | working_dir; 10 | 11 | Goal: Given a video sequence with moving dots, predict 1 frame into the future after the sequence end 12 | 13 | """ 14 | # ---------------------------------------------------------------------------------------------------------------------- 15 | # Imports 16 | # ---------------------------------------------------------------------------------------------------------------------- 17 | 18 | # 19 | # Imports before spawning workers (do NOT import tensorflow or matplotlib here) 20 | # 21 | import os 22 | import sys 23 | from collections import OrderedDict 24 | 25 | import numpy as np 26 | import progressbar 27 | 28 | from TeLL.config import Config 29 | from TeLL.dataprocessing import Normalize 30 | from TeLL.datareaders import initialize_datareaders, DataLoader 31 | from TeLL.utility.misc import AbortRun, check_kill_file 32 | from TeLL.utility.plotting import launch_plotting_daemon, save_subplots 33 | from TeLL.utility.timer import Timer 34 | from TeLL.utility.workingdir import Workspace 35 | 36 | if __name__ == "__main__": 37 | # 38 | # Start subprocess for plotting workers 39 | # Due to a garbage-collector bug with matplotlib/GPU, launch_plotting_daemon needs so be called before tensorflow 40 | # import 41 | # 42 | launch_plotting_daemon(num_workers=3) 43 | from TeLL.session import TeLLSession 44 | 45 | import tensorflow as tf 46 | from TeLL.regularization import regularize 47 | 48 | 49 | # ---------------------------------------------------------------------------------------------------------------------- 50 | # Functions 51 | # ---------------------------------------------------------------------------------------------------------------------- 52 | 53 | def update_step(loss, config, clip_gradient=1., scope='optimizer'): 54 | """Computation of gradients and application of weight updates 55 | 56 | Optimizer can be supplied via config file, e.g. as 57 | "optimizer_params": {"learning_rate": 1e-3}, 58 | "optimizer": "'AdamOptimizer'" 59 | 60 | Parameters 61 | ------- 62 | loss : tensor 63 | Tensor representing the 64 | config : config file 65 | Configuration file 66 | clip_gradient : (positive) float or False 67 | Clip gradient at +/- clip_gradient or don't clip gradient if clip_gradient=False 68 | 69 | Returns 70 | ------- 71 | : tensor 72 | Application of gradients via optimizer 73 | """ 74 | # Define weight update 75 | with tf.variable_scope(scope): 76 | trainables = tf.trainable_variables() 77 | # Set optimizer (one learning rate for all layers) 78 | optimizer = getattr(tf.train, config.optimizer)(**config.optimizer_params) 79 | 80 | # Calculate gradients 81 | gradients = tf.gradients(loss, trainables) 82 | # Clip all gradients 83 | if clip_gradient: 84 | gradients = [tf.clip_by_value(grad, -clip_gradient, clip_gradient) for grad in gradients] 85 | # Set and return weight update 86 | return optimizer.apply_gradients(zip(gradients, trainables)) 87 | 88 | 89 | def evaluate_on_validation_set(validationset, step: int, session, model, summary_writer, validation_summary, 90 | val_loss, workspace: Workspace): 91 | """Convenience function for evaluating network on a validation set 92 | 93 | Parameters 94 | ------- 95 | validationset : dataset reader 96 | Dataset reader for the validation set 97 | step : int 98 | Current step in training 99 | session : tf.session 100 | Tensorflow session to use 101 | model : network model 102 | Network model 103 | val_loss : tensor 104 | Tensor representing the validation loss computation 105 | 106 | Returns 107 | ------- 108 | : float 109 | Loss averaged over validation set 110 | """ 111 | loss = 0 112 | 113 | _pbw = ['Evaluating on validation set: ', progressbar.ETA()] 114 | progress = progressbar.ProgressBar(widgets=_pbw, maxval=validationset.n_mbs - 1, redirect_stdout=True).start() 115 | 116 | mb_validation = validationset.batch_loader() 117 | 118 | with Timer(verbose=True, name="Evaluate on Validation Set"): 119 | for mb_i, mb in enumerate(mb_validation): 120 | # Abort if indicated by file 121 | check_kill_file(workspace) 122 | 123 | val_summary, cur_loss = session.run([validation_summary, val_loss], 124 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 125 | 126 | loss += cur_loss 127 | progress.update(mb_i) 128 | 129 | mb.clear() 130 | del mb 131 | 132 | progress.finish() 133 | 134 | avg_loss = loss / validationset.n_mbs 135 | 136 | summary_writer.add_summary(tf.Summary(value=[tf.Summary.Value(tag="Validation Loss", simple_value=avg_loss)]), 137 | step) 138 | 139 | print("Validation scores:\n\tstep {} validation loss {}".format(step, avg_loss)) 140 | sys.stdout.flush() 141 | 142 | return avg_loss 143 | 144 | 145 | def main(_): 146 | # ------------------------------------------------------------------------------------------------------------------ 147 | # Setup training 148 | # ------------------------------------------------------------------------------------------------------------------ 149 | 150 | # Initialize config, parses command line and reads specified file; also supports overriding of values from cmd 151 | config = Config() 152 | 153 | # 154 | # Prepare input data 155 | # 156 | 157 | # Make sure datareader is reproducible 158 | random_seed = config.get_value('random_seed', 12345) 159 | np.random.seed(random_seed) # not threadsafe, use rnd_gen object where possible 160 | rnd_gen = np.random.RandomState(seed=random_seed) 161 | 162 | # Set datareaders 163 | readers = initialize_datareaders(config, required=("train", "val")) 164 | 165 | # Set Preprocessing 166 | trainingset = Normalize(readers["train"], apply_to=['X']) 167 | validationset = Normalize(readers["val"], apply_to=['X']) 168 | 169 | # Set minibatch loaders 170 | trainingset = DataLoader(trainingset, batchsize=50, batchsize_method='zeropad', verbose=False) 171 | validationset = DataLoader(validationset, batchsize=50, batchsize_method='zeropad', verbose=False) 172 | 173 | # 174 | # Initialize TeLL session 175 | # 176 | tell = TeLLSession(config=config, summaries=["train", "validation"], model_params={"dataset": trainingset}) 177 | 178 | # Get some members from the session for easier usage 179 | sess = tell.tf_session 180 | summary_writer_train, summary_writer_validation = tell.tf_summaries["train"], tell.tf_summaries["validation"] 181 | model = tell.model 182 | workspace, config = tell.workspace, tell.config 183 | 184 | # 185 | # Define loss functions and update steps 186 | # 187 | print("Initializing loss calculation...") 188 | y_shape = trainingset.get_input_shapes()["y"].shape 189 | pos_target_weight = np.prod(y_shape[2:]) - 1 # only 1 pixel per sample is of positive class -> up-weight! 190 | loss = tf.reduce_mean(tf.nn.weighted_cross_entropy_with_logits(targets=model.y_, logits=model.output, 191 | pos_weight=pos_target_weight)) 192 | train_summary = tf.summary.scalar("Training Loss", loss) # create summary to add to tensorboard 193 | 194 | # Loss function for validationset 195 | val_loss = tf.reduce_mean(tf.nn.weighted_cross_entropy_with_logits(targets=model.y_, logits=model.output, 196 | pos_weight=pos_target_weight)) 197 | val_loss_summary = tf.summary.scalar("Validation Loss", val_loss) # create summary to add to tensorboard 198 | 199 | # Regularization 200 | reg_penalty = regularize(layers=model.get_layers(), l1=config.l1, l2=config.l2, 201 | regularize_weights=True, regularize_biases=True) 202 | regpen_summary = tf.summary.scalar("Regularization Penalty", reg_penalty) # create summary to add to tensorboard 203 | 204 | # Update step for weights 205 | update = update_step(loss + reg_penalty, config) 206 | 207 | # 208 | # Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint) 209 | # 210 | global_step = tell.initialize_tf_variables().global_step 211 | 212 | # 213 | # Set up plotting 214 | # (store tensors we want to plot in a dictionary for easier tensor-evaluation) 215 | # 216 | # We want to plot input, output and target for the 1st sample, last frame, and 1st channel in subplot 1 217 | tensors_subplot1 = OrderedDict() 218 | tensors_subplot1['input'] = model.X[0, -1, :, :, 0] 219 | tensors_subplot1['target'] = model.y_[0, -1, :, :, 0] 220 | tensors_subplot1['network_output'] = model.output[0, -1, :, :, 0] 221 | # We also want to plot the cell states and hidden states for each frame (again of the 1st sample and 1st lstm unit) 222 | # in subplot 2 and 3 223 | tensors_subplot2 = OrderedDict() 224 | tensors_subplot3 = OrderedDict() 225 | for frame in range(len(model.lstm_layer.c)): 226 | tensors_subplot2['hiddenstate_{}'.format(frame)] = model.lstm_layer.h[frame][0, :, :, 0] 227 | tensors_subplot3['cellstate_{}'.format(frame)] = model.lstm_layer.c[frame][0, :, :, 0] 228 | # Create a list to store all symbolic tensors for plotting 229 | plotting_tensors = list(tensors_subplot1.values()) + list(tensors_subplot2.values()) + \ 230 | list(tensors_subplot3.values()) 231 | 232 | # 233 | # Finalize graph 234 | # This makes our tensorflow graph read-only and prevents further additions to the graph 235 | # 236 | sess.graph.finalize() 237 | if sess.graph.finalized: 238 | print("Graph is finalized!") 239 | else: 240 | raise ValueError("Could not finalize graph!") 241 | 242 | sys.stdout.flush() 243 | 244 | # ------------------------------------------------------------------------------------------------------------------ 245 | # Start training 246 | # ------------------------------------------------------------------------------------------------------------------ 247 | 248 | try: 249 | epoch = int(global_step / trainingset.n_mbs) 250 | epochs = range(epoch, config.n_epochs) 251 | 252 | # Loop through epochs 253 | print("Starting training") 254 | 255 | for ep in epochs: 256 | epoch = ep 257 | print("Starting training epoch: {}".format(ep)) 258 | # Initialize variables for over-all loss per epoch 259 | train_loss = 0 260 | 261 | # Load one minibatch at a time and perform a training step 262 | t_mb = Timer(verbose=True, name="Load Minibatch") 263 | mb_training = trainingset.batch_loader(rnd_gen=rnd_gen) 264 | 265 | # 266 | # Loop through minibatches 267 | # 268 | for mb_i, mb in enumerate(mb_training): 269 | sys.stdout.flush() 270 | # Print minibatch load time 271 | t_mb.print() 272 | 273 | # Abort if indicated by file 274 | check_kill_file(workspace) 275 | 276 | # 277 | # Calculate scores on validation set 278 | # 279 | if global_step % config.score_at == 0: 280 | print("Starting scoring on validation set...") 281 | evaluate_on_validation_set(validationset, global_step, sess, model, summary_writer_validation, 282 | val_loss_summary, val_loss, workspace) 283 | 284 | # 285 | # Perform weight updates and do plotting 286 | # 287 | if (mb_i % config.plot_at) == 0 and os.path.isfile(workspace.get_plot_file()): 288 | # Perform weight update, return summary values and values for plotting 289 | with Timer(verbose=True, name="Weight Update"): 290 | plotting_values = [] 291 | train_summ, regpen_summ, _, cur_loss, *plotting_values = sess.run( 292 | [train_summary, regpen_summary, update, loss, *plotting_tensors], 293 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 294 | 295 | # Add current summary values to tensorboard 296 | summary_writer_train.add_summary(train_summ, global_step=global_step) 297 | summary_writer_train.add_summary(regpen_summ, global_step=global_step) 298 | 299 | # Create and save subplot 1 (input, target, output) 300 | save_subplots(images=plotting_values[:len(tensors_subplot1)], 301 | subfigtitles=list(tensors_subplot1.keys()), 302 | subplotranges=[None, (0, 1), (0, 1)], colorbar=True, automatic_positioning=True, 303 | filename=os.path.join(workspace.get_result_dir(), 304 | "output_ep{}_mb{}.png".format(ep, mb_i))) 305 | del plotting_values[:len(tensors_subplot1)] 306 | 307 | # Create and save subplot 2 (hidden states, i.e. ConvLSTM outputs) 308 | save_subplots(images=plotting_values[:len(tensors_subplot2)], 309 | subfigtitles=list(tensors_subplot2.keys()), 310 | title='ConvLSTM hidden states (outputs)', colorbar=True, automatic_positioning=True, 311 | filename=os.path.join(workspace.get_result_dir(), 312 | "hidden_ep{}_mb{}.png".format(ep, mb_i))) 313 | del plotting_values[:len(tensors_subplot2)] 314 | 315 | # Create and save subplot 3 (cell states) 316 | save_subplots(images=plotting_values[:len(tensors_subplot3)], 317 | subfigtitles=list(tensors_subplot3.keys()), 318 | title='ConvLSTM cell states', colorbar=True, automatic_positioning=True, 319 | filename=os.path.join(workspace.get_result_dir(), 320 | "cell_ep{}_mb{}.png".format(ep, mb_i))) 321 | del plotting_values[:len(tensors_subplot3)] 322 | 323 | else: 324 | # 325 | # Perform weight update without plotting 326 | # 327 | with Timer(verbose=True, name="Weight Update"): 328 | train_summ, regpen_summ, _, cur_loss = sess.run([train_summary, regpen_summary, update, loss], 329 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 330 | 331 | # Add current summary values to tensorboard 332 | summary_writer_train.add_summary(train_summ, global_step=global_step) 333 | summary_writer_train.add_summary(regpen_summ, global_step=global_step) 334 | 335 | # Add current loss to running average loss 336 | train_loss += cur_loss 337 | 338 | # Print some status info 339 | print("ep {} mb {} loss {} (avg. loss {})".format(ep, mb_i, cur_loss, train_loss / (mb_i + 1))) 340 | 341 | # Reset timer 342 | t_mb = Timer(name="Load Minibatch") 343 | 344 | # Free the memory allocated for the minibatch data 345 | mb.clear() 346 | del mb 347 | 348 | global_step += 1 349 | 350 | # 351 | # Calculate scores on validation set 352 | # 353 | 354 | # Perform scoring on validation set 355 | print("Starting scoring on validation set...") 356 | evaluate_on_validation_set(validationset, global_step, sess, model, summary_writer_validation, 357 | val_loss_summary, val_loss, workspace) 358 | 359 | # Save the model 360 | tell.save_checkpoint(global_step=global_step) 361 | 362 | # Abort if indicated by file 363 | check_kill_file(workspace) 364 | 365 | except AbortRun: 366 | print("Detected kill file, aborting...") 367 | 368 | finally: 369 | # 370 | # If the program executed correctly or an error was raised, close the data readers and save the model and exit 371 | # 372 | trainingset.close() 373 | validationset.close() 374 | tell.close(save_checkpoint=True, global_step=global_step) 375 | 376 | 377 | if __name__ == "__main__": 378 | tf.app.run() 379 | -------------------------------------------------------------------------------- /samples/main_convlstm_mnist.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Main file for simple convLSTM example 6 | 7 | Main file for simple convLSTM example to be used with convLSTM architecture in sample_architectures and config file 8 | config_convlstm.json; Plots input, output, weights, ConvLSTM output (of 2 ConvLSTM units), and cell states in 9 | working_dir; 10 | 11 | """ 12 | # ---------------------------------------------------------------------------------------------------------------------- 13 | # Imports 14 | # ---------------------------------------------------------------------------------------------------------------------- 15 | 16 | # 17 | # Imports before spawning workers (do NOT import tensorflow or matplotlib here) 18 | # 19 | import os 20 | import sys 21 | from collections import OrderedDict 22 | 23 | import numpy as np 24 | import progressbar 25 | 26 | from TeLL.config import Config 27 | from TeLL.dataprocessing import Normalize 28 | from TeLL.datareaders import initialize_datareaders, DataLoader 29 | from TeLL.utility.misc import AbortRun, check_kill_file 30 | from TeLL.utility.plotting import launch_plotting_daemon, save_subplots 31 | from TeLL.utility.timer import Timer 32 | from TeLL.utility.workingdir import Workspace 33 | 34 | if __name__ == "__main__": 35 | # 36 | # Start subprocess for plotting workers 37 | # Due to a garbage-collector bug with matplotlib/GPU, launch_plotting_daemon needs so be called before tensorflow 38 | # import 39 | # 40 | launch_plotting_daemon(num_workers=3) 41 | 42 | from TeLL.session import TeLLSession 43 | 44 | import tensorflow as tf 45 | from TeLL.regularization import regularize 46 | from TeLL.loss import image_crossentropy 47 | 48 | 49 | # ---------------------------------------------------------------------------------------------------------------------- 50 | # Functions 51 | # ---------------------------------------------------------------------------------------------------------------------- 52 | 53 | def update_step(loss, config, clip_gradient=1., scope='optimizer'): 54 | """Computation of gradients and application of weight updates 55 | 56 | Optimizer can be supplied via config file, e.g. as 57 | "optimizer_params": {"learning_rate": 1e-3}, 58 | "optimizer": "'AdamOptimizer'" 59 | 60 | Parameters 61 | ------- 62 | loss : tensor 63 | Tensor representing the 64 | config : config file 65 | Configuration file 66 | clip_gradient : (positive) float or False 67 | Clip gradient at +/- clip_gradient or don't clip gradient if clip_gradient=False 68 | 69 | Returns 70 | ------- 71 | : tensor 72 | Application of gradients via optimizer 73 | """ 74 | # Define weight update 75 | with tf.variable_scope(scope): 76 | trainables = tf.trainable_variables() 77 | # Set optimizer (one learning rate for all layers) 78 | optimizer = getattr(tf.train, config.optimizer)(**config.optimizer_params) 79 | 80 | # Calculate gradients 81 | gradients = tf.gradients(loss, trainables) 82 | # Clip all gradients 83 | if clip_gradient: 84 | gradients = [tf.clip_by_value(grad, -clip_gradient, clip_gradient) for grad in gradients] 85 | # Set and return weight update 86 | return optimizer.apply_gradients(zip(gradients, trainables)) 87 | 88 | 89 | def evaluate_on_validation_set(validationset, step: int, session, model, summary_writer, validation_summary, 90 | val_loss, workspace: Workspace): 91 | """Convenience function for evaluating network on a validation set 92 | 93 | Parameters 94 | ------- 95 | validationset : dataset reader 96 | Dataset reader for the validation set 97 | step : int 98 | Current step in training 99 | session : tf.session 100 | Tensorflow session to use 101 | model : network model 102 | Network model 103 | val_loss : tensor 104 | Tensor representing the validation loss computation 105 | 106 | Returns 107 | ------- 108 | : float 109 | Loss averaged over validation set 110 | """ 111 | loss = 0 112 | 113 | _pbw = ['Evaluating on validation set: ', progressbar.ETA()] 114 | progress = progressbar.ProgressBar(widgets=_pbw, maxval=validationset.n_mbs - 1, redirect_stdout=True).start() 115 | 116 | mb_validation = validationset.batch_loader() 117 | 118 | with Timer(verbose=True, name="Evaluate on Validation Set"): 119 | for mb_i, mb in enumerate(mb_validation): 120 | # Abort if indicated by file 121 | check_kill_file(workspace) 122 | 123 | val_summary, cur_loss = session.run([validation_summary, val_loss], 124 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 125 | 126 | loss += cur_loss 127 | progress.update(mb_i) 128 | 129 | mb.clear() 130 | del mb 131 | 132 | progress.finish() 133 | 134 | avg_loss = loss / validationset.n_mbs 135 | 136 | summary_writer.add_summary(tf.Summary(value=[tf.Summary.Value(tag="Validation Loss", simple_value=avg_loss)]), 137 | step) 138 | 139 | print("Validation scores:\n\tstep {} validation loss {}".format(step, avg_loss)) 140 | sys.stdout.flush() 141 | 142 | return avg_loss 143 | 144 | 145 | def main(_): 146 | # ------------------------------------------------------------------------------------------------------------------ 147 | # Setup training 148 | # ------------------------------------------------------------------------------------------------------------------ 149 | 150 | # Initialize config, parses command line and reads specified file; also supports overriding of values from cmd 151 | config = Config() 152 | 153 | # 154 | # Prepare input data 155 | # 156 | 157 | # Make sure datareader is reproducible 158 | random_seed = config.get_value('random_seed', 12345) 159 | np.random.seed(random_seed) # not threadsafe, use rnd_gen object where possible 160 | rnd_gen = np.random.RandomState(seed=random_seed) 161 | 162 | # Set datareaders 163 | n_timesteps = config.get_value('mnist_n_timesteps', 20) 164 | 165 | # Load datasets for trainingset 166 | with Timer(name="Loading Data"): 167 | readers = initialize_datareaders(config, required=("train", "val")) 168 | 169 | # Set Preprocessing 170 | trainingset = Normalize(readers["train"], apply_to=['X', 'y']) 171 | validationset = Normalize(readers["val"], apply_to=['X', 'y']) 172 | 173 | # Set minibatch loaders 174 | trainingset = DataLoader(trainingset, batchsize=2, batchsize_method='zeropad', verbose=False) 175 | validationset = DataLoader(validationset, batchsize=2, batchsize_method='zeropad', verbose=False) 176 | 177 | # 178 | # Initialize TeLL session 179 | # 180 | tell = TeLLSession(config=config, summaries=["train", "validation"], model_params={"dataset": trainingset}) 181 | 182 | # Get some members from the session for easier usage 183 | sess = tell.tf_session 184 | summary_writer_train, summary_writer_validation = tell.tf_summaries["train"], tell.tf_summaries["validation"] 185 | model = tell.model 186 | workspace, config = tell.workspace, tell.config 187 | 188 | # 189 | # Define loss functions and update steps 190 | # 191 | print("Initializing loss calculation...") 192 | loss, _ = image_crossentropy(target=model.y_[:, 10:, :, :], pred=model.output[:, 10:, :, :, :], 193 | pixel_weights=model.pixel_weights[:, 10:, :, :], reduce_by='mean') 194 | train_summary = tf.summary.scalar("Training Loss", loss) # create summary to add to tensorboard 195 | 196 | # Loss function for validationset 197 | val_loss = loss 198 | val_loss_summary = tf.summary.scalar("Validation Loss", val_loss) # create summary to add to tensorboard 199 | 200 | # Regularization 201 | reg_penalty = regularize(layers=model.get_layers(), l1=config.l1, l2=config.l2, 202 | regularize_weights=True, regularize_biases=True) 203 | regpen_summary = tf.summary.scalar("Regularization Penalty", reg_penalty) # create summary to add to tensorboard 204 | 205 | # Update step for weights 206 | update = update_step(loss + reg_penalty, config) 207 | 208 | # 209 | # Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint) 210 | # 211 | global_step = tell.initialize_tf_variables().global_step 212 | 213 | # 214 | # Set up plotting 215 | # (store tensors we want to plot in a dictionary for easier tensor-evaluation) 216 | # 217 | # We want to plot input, output and target for the 1st sample, 1st frame, and 1st channel in subplot 1 218 | tensors_subplot1 = OrderedDict() 219 | tensors_subplot2 = OrderedDict() 220 | tensors_subplot3 = OrderedDict() 221 | for frame in range(n_timesteps): 222 | tensors_subplot1['input_{}'.format(frame)] = model.X[0, frame, :, :] 223 | tensors_subplot2['target_{}'.format(frame)] = model.y_[0, frame, :, :] - 1 224 | tensors_subplot3['network_output_{}'.format(frame)] = tf.argmax(model.output[0, frame, :, :, :], axis=-1) - 1 225 | # We also want to plot the cell states and hidden states for each frame (again of the 1st sample and 1st lstm unit) 226 | # in subplot 2 and 3 227 | tensors_subplot4 = OrderedDict() 228 | tensors_subplot5 = OrderedDict() 229 | for frame in range(len(model.lstm_layer.c)): 230 | tensors_subplot4['hiddenstate_{}'.format(frame)] = model.lstm_layer.h[frame][0, :, :, 0] 231 | tensors_subplot5['cellstate_{}'.format(frame)] = model.lstm_layer.c[frame][0, :, :, 0] 232 | # Create a list to store all symbolic tensors for plotting 233 | plotting_tensors = list(tensors_subplot1.values()) + list(tensors_subplot2.values()) + \ 234 | list(tensors_subplot3.values()) + list(tensors_subplot4.values()) + \ 235 | list(tensors_subplot5.values()) 236 | 237 | # 238 | # Finalize graph 239 | # This makes our tensorflow graph read-only and prevents further additions to the graph 240 | # 241 | sess.graph.finalize() 242 | if sess.graph.finalized: 243 | print("Graph is finalized!") 244 | else: 245 | raise ValueError("Could not finalize graph!") 246 | 247 | sys.stdout.flush() 248 | 249 | # ------------------------------------------------------------------------------------------------------------------ 250 | # Start training 251 | # ------------------------------------------------------------------------------------------------------------------ 252 | 253 | try: 254 | epoch = int(global_step / trainingset.n_mbs) 255 | epochs = range(epoch, config.n_epochs) 256 | 257 | # Loop through epochs 258 | print("Starting training") 259 | 260 | for ep in epochs: 261 | epoch = ep 262 | print("Starting training epoch: {}".format(ep)) 263 | # Initialize variables for over-all loss per epoch 264 | train_loss = 0 265 | 266 | # Load one minibatch at a time and perform a training step 267 | t_mb = Timer(verbose=True, name="Load Minibatch") 268 | mb_training = trainingset.batch_loader(rnd_gen=rnd_gen) 269 | 270 | # 271 | # Loop through minibatches 272 | # 273 | for mb_i, mb in enumerate(mb_training): 274 | sys.stdout.flush() 275 | # Print minibatch load time 276 | t_mb.print() 277 | 278 | # Abort if indicated by file 279 | check_kill_file(workspace) 280 | 281 | # 282 | # Calculate scores on validation set 283 | # 284 | if global_step % config.score_at == 0: 285 | print("Starting scoring on validation set...") 286 | evaluate_on_validation_set(validationset, global_step, sess, model, summary_writer_validation, 287 | val_loss_summary, val_loss, workspace) 288 | 289 | # 290 | # Perform weight updates and do plotting 291 | # 292 | if (mb_i % config.plot_at) == 0 and os.path.isfile(workspace.get_plot_file()): 293 | # Perform weight update, return summary values and values for plotting 294 | with Timer(verbose=True, name="Weight Update"): 295 | plotting_values = [] 296 | train_summ, regpen_summ, _, cur_loss, *plotting_values = sess.run( 297 | [train_summary, regpen_summary, update, loss, *plotting_tensors], 298 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 299 | 300 | # Add current summary values to tensorboard 301 | summary_writer_train.add_summary(train_summ, global_step=global_step) 302 | summary_writer_train.add_summary(regpen_summ, global_step=global_step) 303 | 304 | # Create and save subplot 1 (input) 305 | save_subplots(images=plotting_values[:len(tensors_subplot1)], 306 | subfigtitles=list(tensors_subplot1.keys()), 307 | subplotranges=[(0, 1)] * n_timesteps, colorbar=True, automatic_positioning=True, 308 | tight_layout=True, 309 | filename=os.path.join(workspace.get_result_dir(), 310 | "input_ep{}_mb{}.png".format(ep, mb_i))) 311 | del plotting_values[:len(tensors_subplot1)] 312 | 313 | # Create and save subplot 2 (target) 314 | save_subplots(images=plotting_values[:len(tensors_subplot2)], 315 | subfigtitles=list(tensors_subplot2.keys()), 316 | subplotranges=[(0, 10) * n_timesteps], colorbar=True, automatic_positioning=True, 317 | tight_layout=True, 318 | filename=os.path.join(workspace.get_result_dir(), 319 | "target_ep{}_mb{}.png".format(ep, mb_i))) 320 | del plotting_values[:len(tensors_subplot2)] 321 | 322 | # Create and save subplot 3 (output) 323 | save_subplots(images=plotting_values[:len(tensors_subplot3)], 324 | subfigtitles=list(tensors_subplot3.keys()), 325 | # subplotranges=[(0, 10)] * n_timesteps, 326 | colorbar=True, automatic_positioning=True, 327 | tight_layout=True, 328 | filename=os.path.join(workspace.get_result_dir(), 329 | "output_ep{}_mb{}.png".format(ep, mb_i))) 330 | del plotting_values[:len(tensors_subplot3)] 331 | 332 | # Create and save subplot 2 (hidden states, i.e. ConvLSTM outputs) 333 | save_subplots(images=plotting_values[:len(tensors_subplot4)], 334 | subfigtitles=list(tensors_subplot4.keys()), 335 | title='ConvLSTM hidden states (outputs)', colorbar=True, automatic_positioning=True, 336 | tight_layout=True, 337 | filename=os.path.join(workspace.get_result_dir(), 338 | "hidden_ep{}_mb{}.png".format(ep, mb_i))) 339 | del plotting_values[:len(tensors_subplot4)] 340 | 341 | # Create and save subplot 3 (cell states) 342 | save_subplots(images=plotting_values[:len(tensors_subplot5)], 343 | subfigtitles=list(tensors_subplot5.keys()), 344 | title='ConvLSTM cell states', colorbar=True, automatic_positioning=True, 345 | tight_layout=True, 346 | filename=os.path.join(workspace.get_result_dir(), 347 | "cell_ep{}_mb{}.png".format(ep, mb_i))) 348 | del plotting_values[:len(tensors_subplot5)] 349 | 350 | else: 351 | # 352 | # Perform weight update without plotting 353 | # 354 | with Timer(verbose=True, name="Weight Update"): 355 | train_summ, regpen_summ, _, cur_loss = sess.run([ 356 | train_summary, regpen_summary, update, loss], 357 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 358 | 359 | # Add current summary values to tensorboard 360 | summary_writer_train.add_summary(train_summ, global_step=global_step) 361 | summary_writer_train.add_summary(regpen_summ, global_step=global_step) 362 | 363 | # Add current loss to running average loss 364 | train_loss += cur_loss 365 | 366 | # Print some status info 367 | print("ep {} mb {} loss {} (avg. loss {})".format(ep, mb_i, cur_loss, train_loss / (mb_i + 1))) 368 | 369 | # Reset timer 370 | t_mb = Timer(name="Load Minibatch") 371 | 372 | # Free the memory allocated for the minibatch data 373 | mb.clear() 374 | del mb 375 | 376 | global_step += 1 377 | 378 | # 379 | # Calculate scores on validation set 380 | # 381 | 382 | # Perform scoring on validation set 383 | print("Starting scoring on validation set...") 384 | evaluate_on_validation_set(validationset, global_step, sess, model, summary_writer_validation, 385 | val_loss_summary, val_loss, workspace) 386 | 387 | # Save the model 388 | tell.save_checkpoint(global_step=global_step) 389 | 390 | # Abort if indicated by file 391 | check_kill_file(workspace) 392 | 393 | except AbortRun: 394 | print("Detected kill file, aborting...") 395 | 396 | finally: 397 | # 398 | # If the program executed correctly or an error was raised, close the data readers and save the model and exit 399 | # 400 | trainingset.close() 401 | validationset.close() 402 | tell.close(save_checkpoint=True, global_step=global_step) 403 | 404 | 405 | if __name__ == "__main__": 406 | tf.app.run() 407 | -------------------------------------------------------------------------------- /samples/main_lstm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | © Michael Widrich, Markus Hofmarcher, 2017 4 | 5 | Main file for LSTM and dense layer example 6 | 7 | Main file for LSTM example to be used with LSTM architecture in sample_architectures and config file config_lstm.json; 8 | Also to be used with other LSTM example architectures and a dense layer architecture (see sample_architectures.py for 9 | the different examples and descriptions); 10 | 11 | """ 12 | # ---------------------------------------------------------------------------------------------------------------------- 13 | # Imports 14 | # ---------------------------------------------------------------------------------------------------------------------- 15 | 16 | # 17 | # Imports before spawning workers (do NOT import tensorflow or matplotlib here) 18 | # 19 | import sys 20 | 21 | import numpy as np 22 | import progressbar 23 | 24 | # Import TeLL 25 | from TeLL.config import Config 26 | from TeLL.datareaders import initialize_datareaders, DataLoader 27 | from TeLL.utility.misc import AbortRun, check_kill_file 28 | from TeLL.utility.timer import Timer 29 | from TeLL.utility.workingdir import Workspace 30 | 31 | if __name__ == "__main__": 32 | from TeLL.session import TeLLSession 33 | 34 | import tensorflow as tf 35 | from TeLL.regularization import regularize 36 | 37 | 38 | # ---------------------------------------------------------------------------------------------------------------------- 39 | # Functions 40 | # ---------------------------------------------------------------------------------------------------------------------- 41 | 42 | def update_step(loss, config, clip_gradient=1., scope='optimizer'): 43 | """Computation of gradients and application of weight updates 44 | 45 | Optimizer can be supplied via config file, e.g. as 46 | "optimizer_params": {"learning_rate": 1e-3}, 47 | "optimizer": "'AdamOptimizer'" 48 | 49 | Parameters 50 | ------- 51 | loss : tensor 52 | Tensor representing the 53 | config : config file 54 | Configuration file 55 | clip_gradient : (positive) float or False 56 | Clip gradient at +/- clip_gradient or don't clip gradient if clip_gradient=False 57 | 58 | Returns 59 | ------- 60 | : tensor 61 | Application of gradients via optimizer 62 | """ 63 | # Define weight update 64 | with tf.variable_scope(scope): 65 | trainables = tf.trainable_variables() 66 | # Set optimizer (one learning rate for all layers) 67 | optimizer = getattr(tf.train, config.optimizer)(**config.optimizer_params) 68 | 69 | # Calculate gradients 70 | gradients = tf.gradients(loss, trainables) 71 | # Clip all gradients 72 | if clip_gradient: 73 | gradients = [tf.clip_by_value(grad, -clip_gradient, clip_gradient) for grad in gradients] 74 | # Set and return weight update 75 | return optimizer.apply_gradients(zip(gradients, trainables)) 76 | 77 | 78 | def evaluate_on_validation_set(validationset, step: int, session, model, summary_writer, validation_summary, 79 | val_loss, workspace: Workspace): 80 | """Convenience function for evaluating network on a validation set 81 | 82 | Parameters 83 | ------- 84 | validationset : dataset reader 85 | Dataset reader for the validation set 86 | step : int 87 | Current step in training 88 | session : tf.session 89 | Tensorflow session to use 90 | model : network model 91 | Network model 92 | val_loss : tensor 93 | Tensor representing the validation loss computation 94 | 95 | Returns 96 | ------- 97 | : float 98 | Loss averaged over validation set 99 | """ 100 | loss = 0 101 | 102 | _pbw = ['Evaluating on validation set: ', progressbar.ETA()] 103 | progress = progressbar.ProgressBar(widgets=_pbw, maxval=validationset.n_mbs - 1, redirect_stdout=True).start() 104 | 105 | mb_validation = validationset.batch_loader() 106 | 107 | with Timer(verbose=True, name="Evaluate on Validation Set"): 108 | for mb_i, mb in enumerate(mb_validation): 109 | # Abort if indicated by file 110 | check_kill_file(workspace) 111 | 112 | val_summary, cur_loss = session.run([validation_summary, val_loss], 113 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 114 | 115 | loss += cur_loss 116 | progress.update(mb_i) 117 | 118 | mb.clear() 119 | del mb 120 | 121 | progress.finish() 122 | 123 | avg_loss = loss / validationset.n_mbs 124 | 125 | summary_writer.add_summary(tf.Summary(value=[tf.Summary.Value(tag="Validation Loss", simple_value=avg_loss)]), 126 | step) 127 | 128 | print("Validation scores:\n\tstep {} validation loss {}".format(step, avg_loss)) 129 | sys.stdout.flush() 130 | 131 | return avg_loss 132 | 133 | 134 | def main(_): 135 | # ------------------------------------------------------------------------------------------------------------------ 136 | # Setup training 137 | # ------------------------------------------------------------------------------------------------------------------ 138 | 139 | # Initialize config, parses command line and reads specified file; also supports overriding of values from cmd 140 | config = Config() 141 | 142 | random_seed = config.get_value('random_seed', 12345) 143 | np.random.seed(random_seed) # not threadsafe, use rnd_gen object where possible 144 | rnd_gen = np.random.RandomState(seed=random_seed) 145 | 146 | # Load datasets for trainingset 147 | with Timer(name="Loading Data"): 148 | readers = initialize_datareaders(config, required=("train", "val")) 149 | trainingset = DataLoader(readers["train"], batchsize=config.batchsize) 150 | validationset = DataLoader(readers["val"], batchsize=config.batchsize) 151 | 152 | # Initialize TeLL session 153 | tell = TeLLSession(config=config, summaries=["train"], model_params={"dataset": trainingset}) 154 | 155 | # Get some members from the session for easier usage 156 | session = tell.tf_session 157 | summary_writer = tell.tf_summaries["train"] 158 | model = tell.model 159 | workspace, config = tell.workspace, tell.config 160 | 161 | # Loss function for trainingset 162 | print("Initializing loss calculation...") 163 | loss = tf.reduce_mean(tf.square(model.y_ - model.output)) 164 | train_summary = tf.summary.scalar("Training Loss", loss) # add loss to tensorboard 165 | 166 | # Loss function for validationset 167 | val_loss = tf.reduce_mean(tf.square(model.y_ - model.output)) 168 | val_loss_summary = tf.summary.scalar("Validation Loss", val_loss) # add val_loss to tensorboard 169 | 170 | # Regularization 171 | reg_penalty = regularize(layers=model.get_layers(), l1=config.l1, l2=config.l2, 172 | regularize_weights=True, regularize_biases=True) 173 | regpen_summary = tf.summary.scalar("Regularization Penalty", reg_penalty) # add reg_penalty to tensorboard 174 | 175 | # Update step for weights 176 | update = update_step(loss + reg_penalty, config) 177 | 178 | # Initialize Tensorflow variables 179 | global_step = tell.initialize_tf_variables().global_step 180 | 181 | sys.stdout.flush() 182 | 183 | # ------------------------------------------------------------------------------------------------------------------ 184 | # Start training 185 | # ------------------------------------------------------------------------------------------------------------------ 186 | 187 | try: 188 | epoch = int(global_step / trainingset.n_mbs) 189 | epochs = range(epoch, config.n_epochs) 190 | 191 | # 192 | # Loop through epochs 193 | # 194 | print("Starting training") 195 | 196 | for ep in epochs: 197 | print("Starting training epoch: {}".format(ep)) 198 | # Initialize variables for over-all loss per epoch 199 | train_loss = 0 200 | 201 | # Load one minibatch at a time and perform a training step 202 | t_mb = Timer(name="Load Minibatch") 203 | mb_training = trainingset.batch_loader(rnd_gen=rnd_gen) 204 | 205 | # 206 | # Loop through minibatches 207 | # 208 | for mb_i, mb in enumerate(mb_training): 209 | sys.stdout.flush() 210 | # Print minibatch load time 211 | t_mb.print() 212 | 213 | # Abort if indicated by file 214 | check_kill_file(workspace) 215 | 216 | # 217 | # Calculate scores on validation set 218 | # 219 | if global_step % config.score_at == 0: 220 | print("Starting scoring on validation set...") 221 | evaluate_on_validation_set(validationset, global_step, session, model, summary_writer, 222 | val_loss_summary, val_loss, workspace) 223 | 224 | # 225 | # Perform weight update 226 | # 227 | with Timer(name="Weight Update"): 228 | train_summ, regpen_summ, _, cur_loss = session.run( 229 | [train_summary, regpen_summary, update, loss], 230 | feed_dict={model.X: mb['X'], model.y_: mb['y']}) 231 | 232 | # Add current summary values to tensorboard 233 | summary_writer.add_summary(train_summ, global_step=global_step) 234 | summary_writer.add_summary(regpen_summ, global_step=global_step) 235 | 236 | # Add current loss to running average loss 237 | train_loss += cur_loss 238 | 239 | # Print some status info 240 | print("ep {} mb {} loss {} (avg. loss {})".format(ep, mb_i, cur_loss, train_loss / (mb_i + 1))) 241 | 242 | # Reset timer 243 | t_mb = Timer(name="Load Minibatch") 244 | 245 | # Free the memory allocated for the minibatch data 246 | mb.clear() 247 | del mb 248 | 249 | global_step += 1 250 | 251 | # 252 | # Calculate scores on validation set after training is done 253 | # 254 | 255 | # Perform scoring on validation set 256 | print("Starting scoring on validation set...") 257 | evaluate_on_validation_set(validationset, global_step, session, model, summary_writer, val_loss_summary, 258 | val_loss, workspace) 259 | 260 | tell.save_checkpoint(global_step=global_step) 261 | 262 | # Abort if indicated by file 263 | check_kill_file(workspace) 264 | 265 | except AbortRun: 266 | print("Detected kill file, aborting...") 267 | 268 | finally: 269 | tell.close(save_checkpoint=True, global_step=global_step) 270 | 271 | 272 | if __name__ == "__main__": 273 | tf.app.run() 274 | -------------------------------------------------------------------------------- /samples/mnist/architectures.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | 4 | """ 5 | import tensorflow as tf 6 | from TeLL.layers import DenseLayer, DropoutLayer, ConvLayer, MaxPoolingLayer 7 | from TeLL.initializations import weight_truncated_normal, weight_gauss_conv2d 8 | from TeLL.config import Config 9 | 10 | 11 | class DenseNet(object): 12 | def __init__(self, config: Config): 13 | # Network Parameters 14 | n_input = 784 # MNIST data input (img shape: 28*28) 15 | n_classes = 10 # MNIST total classes (0-9 digits) 16 | n_hidden_1 = config.n_hidden_1 17 | n_hidden_2 = config.n_hidden_2 18 | 19 | # tf Graph input 20 | X = tf.placeholder(tf.float32, [None, n_input], name="Features") 21 | y_ = tf.placeholder(tf.float32, [None, n_classes], name="Labels") 22 | d = tf.placeholder(tf.float32) 23 | 24 | #X_2d = tf.reshape(X, [-1, 28, 28, 1]) 25 | 26 | #hidden1 = ConvLayer(X_2d, W=weight_gauss_conv2d([3, 3, 1, n_hidden_1]), name="ConvLayer1") 27 | #maxpool1 = MaxPoolingLayer(hidden1, name="MaxPoolingLayer1") 28 | #hidden2 = ConvLayer(maxpool1, W=weight_gauss_conv2d([3, 3, n_hidden_1, n_hidden_2]), name="ConvLayer2") 29 | #maxpool2 = MaxPoolingLayer(hidden2, name="MaxPoolingLayer2") 30 | #flat = tf.contrib.layers.flatten(maxpool2.get_output()) 31 | 32 | # Hidden 1 33 | hidden1 = DenseLayer(X, n_hidden_1, name="Hidden_Layer_1", 34 | a=tf.nn.sigmoid, W=weight_truncated_normal, b=tf.zeros) 35 | # Hidden 2 36 | hidden2 = DenseLayer(hidden1, n_hidden_2, name="Hidden_Layer_2", 37 | a=tf.nn.sigmoid, W=weight_truncated_normal, b=tf.zeros) 38 | 39 | # Output 40 | out = DenseLayer(hidden2, n_classes, name="Output_Layer", 41 | a=tf.identity, W=weight_truncated_normal, b=tf.zeros) 42 | 43 | self.X = X 44 | self.y_ = y_ 45 | self.dropout = d 46 | self.hidden1 = hidden1 47 | self.hidden2 = hidden2 48 | self.output = out.get_output() 49 | -------------------------------------------------------------------------------- /samples/mnist/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "mnist_dense_w0.125", 3 | "entropy_w": 0.125, 4 | "cuda_gpu": "0", 5 | "architecture": "architectures.DenseNet", 6 | "optimizer": "AdamOptimizer", 7 | "optimizer_params": { 8 | "learning_rate": 1e-3 9 | }, 10 | "iterations": 10000, 11 | "batchsize": 256, 12 | "display_step": 100, 13 | "dropout": 0.0, 14 | "n_hidden_1": 800, 15 | "n_hidden_2": 800, 16 | "score_at": 1000, 17 | "plot_at": 20, 18 | "tf_allow_growth": true, 19 | "working_dir": "working_dir" 20 | } 21 | -------------------------------------------------------------------------------- /samples/mnist/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | 4 | Example for mnist predictions via dense network 5 | 6 | Command-line usage: 7 | >>> python3 samples/mnist/main_convlstm.py --config=samples/mnist/config.json 8 | """ 9 | # Import MNIST data 10 | from tensorflow.examples.tutorials.mnist import input_data 11 | 12 | # Import TeLL 13 | from TeLL.config import Config 14 | from TeLL.session import TeLLSession 15 | from TeLL.utility.timer import Timer 16 | from TeLL.utility.misc import AbortRun, check_kill_file 17 | from TeLL.regularization import decor_penalty 18 | 19 | # Import Tensorflow 20 | if __name__ == "__main__": 21 | import tensorflow as tf 22 | 23 | 24 | # ---------------------------------------------------------------------------------------------------------------------- 25 | # Functions 26 | # ---------------------------------------------------------------------------------------------------------------------- 27 | 28 | def main(_): 29 | config = Config() 30 | # Create new TeLL session with two summary writers 31 | tell = TeLLSession(config=config, summaries=["train", "validation"]) 32 | 33 | # Get some members from the session for easier usage 34 | session = tell.tf_session 35 | summary_writer_train, summary_writer_validation = tell.tf_summaries["train"], tell.tf_summaries["validation"] 36 | model = tell.model 37 | workspace, config = tell.workspace, tell.config 38 | 39 | # Parameters 40 | learning_rate = config.get_value("learning_rate", 1e-3) 41 | iterations = config.get_value("iterations", 1000) 42 | batchsize = config.get_value("batchsize", 250) 43 | display_step = config.get_value("display_step", 10) 44 | dropout = config.get_value("dropout_prob", 0.25) 45 | 46 | # 47 | # Load Data 48 | # 49 | with Timer(name="Load data"): 50 | mnist = input_data.read_data_sets("../MNIST_data", one_hot=True) 51 | 52 | # Define loss and optimizer 53 | with tf.name_scope("Cost"): 54 | cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=model.output, labels=model.y_)) 55 | 56 | ##entropy = tf.reduce_mean(tf.contrib.bayesflow.entropy.entropy_shannon( 57 | ## tf.contrib.distributions.Categorical(p=tf.nn.softmax(logits=model.output)))) 58 | 59 | probs = tf.nn.softmax(logits=model.output) 60 | entropy = tf.reduce_mean(-tf.reduce_sum(tf.log(tf.maximum(probs, 1e-15)) * probs, 1)) 61 | 62 | # test decor regularization 63 | #decor_penalty(model.hidden1, model.y_, 10, [1], 0.) 64 | #decor_penalty(model.hidden2, model.y_, 10, [1], 0.) 65 | 66 | optimizer = tell.tf_optimizer.minimize(cost - config.get_value("entropy_w", 0.) * entropy) 67 | 68 | tf.summary.scalar("Loss", cost) 69 | #tf.summary.scalar("Decor", decor1 + decor2) 70 | #tf.summary.scalar("Entropy", entropy) 71 | tf.summary.scalar("O-Prob", tf.reduce_mean(tf.reduce_sum(tf.nn.softmax(logits=model.output) * model.y_, 1))) 72 | 73 | # Evaluate model 74 | with tf.name_scope("Accuracy"): 75 | correct_pred = tf.equal(tf.argmax(model.output, 1), tf.argmax(model.y_, 1)) 76 | accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) 77 | tf.summary.scalar("Accuracy", accuracy) 78 | 79 | merged_summaries = tf.summary.merge_all() 80 | 81 | # Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint) 82 | step = tell.initialize_tf_variables(reset_optimizer_on_restore=True).global_step 83 | 84 | # ------------------------------------------------------------------------- 85 | # Start training 86 | # ------------------------------------------------------------------------- 87 | acc_train = 0. 88 | val_acc_best = 0. 89 | try: 90 | while step < iterations: 91 | check_kill_file(workspace=workspace) 92 | batch_x, batch_y = mnist.train.next_batch(batchsize) 93 | 94 | i = step * batchsize 95 | if step % display_step == 0: 96 | summary, acc = session.run([merged_summaries, accuracy], 97 | feed_dict={model.X: mnist.validation.images[:2048], 98 | model.y_: mnist.validation.labels[:2048], 99 | model.dropout: 0}) 100 | summary_writer_validation.add_summary(summary, i) 101 | print('step {}: train acc {}, valid acc {}'.format(i, acc_train, acc)) 102 | 103 | if acc > val_acc_best: 104 | val_acc_best = acc 105 | else: 106 | summary, acc_train, _ = session.run([merged_summaries, accuracy, optimizer], 107 | feed_dict={model.X: batch_x, model.y_: batch_y, 108 | model.dropout: dropout}) 109 | summary_writer_train.add_summary(summary, i) 110 | 111 | step += 1 112 | 113 | print("Training Finished! best valid acc {}".format(val_acc_best)) 114 | 115 | # Final Eval 116 | print("Test Accuracy:", 117 | session.run(accuracy, feed_dict={model.X: mnist.test.images[:2048], 118 | model.y_: mnist.test.labels[:2048], 119 | model.dropout: 0})) 120 | except AbortRun: 121 | print("Aborting...") 122 | finally: 123 | tell.close(global_step=step) 124 | 125 | 126 | if __name__ == "__main__": 127 | tf.app.run() 128 | -------------------------------------------------------------------------------- /samples/mnist/main_datapreprocessing.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | 4 | """ 5 | 6 | # Import TeLL 7 | from TeLL.config import Config 8 | from TeLL.session import TeLLSession 9 | from TeLL.datareaders import MNISTReader, DataLoader 10 | from TeLL.dataprocessing import DataProcessing, Normalize, Zoom 11 | from TeLL.utility.misc import AbortRun, check_kill_file 12 | from TeLL.regularization import decor_penalty 13 | 14 | # Import Tensorflow 15 | if __name__ == "__main__": 16 | import tensorflow as tf 17 | 18 | 19 | # ---------------------------------------------------------------------------------------------------------------------- 20 | # Functions 21 | # ---------------------------------------------------------------------------------------------------------------------- 22 | 23 | def main(_): 24 | config = Config() 25 | # Create new TeLL session with two summary writers 26 | tell = TeLLSession(config=config, summaries=["train", "validation"]) 27 | 28 | # Get some members from the session for easier usage 29 | session = tell.tf_session 30 | summary_writer_train, summary_writer_validation = tell.tf_summaries["train"], tell.tf_summaries["validation"] 31 | model = tell.model 32 | workspace, config = tell.workspace, tell.config 33 | 34 | # Parameters 35 | learning_rate = config.get_value("learning_rate", 1e-3) 36 | iterations = config.get_value("iterations", 1000) 37 | batchsize = config.get_value("batchsize", 250) 38 | display_step = config.get_value("display_step", 10) 39 | dropout = config.get_value("dropout_prob", 0.25) 40 | 41 | # 42 | # Prepare input data 43 | # 44 | 45 | # Set datareaders 46 | training_reader = MNISTReader(dset='train') 47 | validation_reader = MNISTReader(dset='validation') 48 | test_reader = MNISTReader(dset='test') 49 | 50 | # Set Preprocessing 51 | training_data_preprocessed = DataProcessing(training_reader, apply_to='X') 52 | training_data_preprocessed = Normalize(training_data_preprocessed, apply_to='X') 53 | training_data_preprocessed = Normalize(training_data_preprocessed, apply_to=['X', 'Y']) 54 | 55 | # Set minibatch loaders 56 | training_loader = DataLoader(training_data_preprocessed, batchsize=50, batchsize_method='zeropad') 57 | validation_loader = DataLoader(validation_reader, batchsize=50, batchsize_method='zeropad') 58 | test_loader = DataLoader(test_reader, batchsize=50, batchsize_method='zeropad') 59 | 60 | # 61 | # Define loss and optimizer 62 | # 63 | with tf.name_scope("Cost"): 64 | cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=model.output, labels=model.y_)) 65 | decor1 = decor_penalty(model.hidden1, model.y_, 10, [1], 0.) 66 | decor2 = decor_penalty(model.hidden2, model.y_, 10, [1], 6e-5) 67 | optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost + decor1 + decor2) 68 | tf.summary.scalar("Loss", cost) 69 | tf.summary.scalar("Decor", decor1 + decor2) 70 | 71 | # Evaluate model 72 | with tf.name_scope("Accuracy"): 73 | correct_pred = tf.equal(tf.argmax(model.output, 1), tf.argmax(model.y_, 1)) 74 | accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) 75 | tf.summary.scalar("Accuracy", accuracy) 76 | 77 | merged_summaries = tf.summary.merge_all() 78 | 79 | # Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint) 80 | step = tell.initialize_tf_variables().global_step 81 | 82 | # ------------------------------------------------------------------------- 83 | # Start training 84 | # ------------------------------------------------------------------------- 85 | acc_train = 0. 86 | try: 87 | while step < iterations: 88 | # Loop through training set 89 | for mb_i, mb in enumerate(training_loader.batch_loader(num_cached=5, num_threads=3)): 90 | check_kill_file(workspace=workspace) 91 | 92 | # Perform weight update 93 | summary, acc_train, _ = session.run([merged_summaries, accuracy, optimizer], 94 | feed_dict={model.X: mb['X'], model.y_: mb['y'], 95 | model.dropout: dropout}) 96 | summary_writer_train.add_summary(summary, mb_i + step * batchsize) 97 | 98 | if step % display_step == 0: 99 | # Loop through validation set 100 | cos_sum, acc_sum, cor_sum = (0, 0, 0) 101 | for vmb_i, vmb in enumerate(validation_loader.batch_loader(num_cached=5, num_threads=3)): 102 | cos, acc, cor = session.run([cost, accuracy, correct_pred], 103 | feed_dict={model.X: vmb['X'], model.y_: vmb['y'], 104 | model.dropout: 0}) 105 | cos_sum += cos 106 | acc_sum += acc 107 | cor_sum += cor 108 | print('step {}: train acc {}, valid acc {}'.format(mb_i + step * batchsize, cos_sum/vmb_i, 109 | acc_sum/vmb_i, cor_sum/vmb_i)) 110 | 111 | step += 1 112 | if step >= iterations: 113 | break 114 | 115 | print("Training Finished!") 116 | 117 | # Final Eval 118 | for tmb_i, tmb in enumerate(test_loader.batch_loader(num_cached=len(test_reader.get_sample_keys()), 119 | num_threads=1)): 120 | print("Test Accuracy:", 121 | session.run(accuracy, feed_dict={model.X: tmb['X'], 122 | model.y_: tmb['y'], 123 | model.dropout: 0})) 124 | except AbortRun: 125 | print("Aborting...") 126 | finally: 127 | tell.close(global_step=step) 128 | 129 | 130 | if __name__ == "__main__": 131 | tf.app.run() 132 | -------------------------------------------------------------------------------- /samples/moving_mnist/architectures.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | 4 | """ 5 | import tensorflow as tf 6 | import TeLL 7 | from TeLL.layers import DenseLayer, DropoutLayer, ConvLayer, RNNInputLayer, MaxPoolingLayer, DeConvLayer, ConvLSTMLayer, ScalingLayer, ConcatLayer 8 | from TeLL.initializations import weight_truncated_normal, constant 9 | from TeLL.config import Config 10 | from TeLL.utility.misc import get_rec_attr 11 | 12 | from collections import OrderedDict 13 | 14 | 15 | class ConvLSTMSemsegEfor(object): 16 | def __init__(self, config: Config, dataset): 17 | """Architecture for semantic segmentation as described in presentation using standard for loop.""" 18 | depth = config.get_value("enc_dec_depth", 2) 19 | basenr_convs = config.get_value("enc_dec_conv_maps_base", 16) 20 | include_org_label = config.get_value("include_org_label", False) 21 | init_name = config.get_value("conv_W_initializer", "weight_xavier_conv2d") 22 | conv_W_initializer = getattr(TeLL.initializations, init_name) 23 | 24 | # 25 | # Layer list 26 | # 27 | layers = list() 28 | 29 | # 30 | # Create placeholders for feeding an input frame and a label at the first timestep 31 | # 32 | n_seq_pos = dataset.X_shape[1] # dataset.X_shape is [sample, seq_pos, x, y, features) 33 | X = tf.placeholder(tf.float32, shape=dataset.X_shape) 34 | y_ = tf.placeholder(tf.int32, shape=dataset.y_shape) 35 | 36 | if include_org_label: 37 | y_org = tf.placeholder(tf.int32, shape=dataset.y_org_shape) 38 | 39 | # ---------------------------------------------------------------------------------------------------------- 40 | # Define network architecture 41 | # ---------------------------------------------------------------------------------------------------------- 42 | # initializer for weight values of kernels 43 | # conv_W_initializer = weight_xavier_conv2d 44 | 45 | # 46 | # Initialize input to network of shape [sample, 1, x, y, features] with zero tensor of size of a frame 47 | # 48 | input_shape = dataset.X_shape[:1] + (1,) + dataset.X_shape[2:] 49 | layers.append(RNNInputLayer(tf.zeros(input_shape, dtype=tf.float32))) 50 | rnn_input_layer = layers[-1] 51 | 52 | # 53 | # Encoder and maxpooling layers 54 | # 55 | encoders = list() 56 | for d in range(1, depth + 1): 57 | print("\tConvLayerEncoder{}...".format(d)) 58 | layers.append(ConvLayer(incoming=layers[-1], 59 | W=conv_W_initializer([config.kernel_conv, config.kernel_conv, 60 | layers[-1].get_output_shape()[-1], basenr_convs * (2 ** d)]), 61 | padding='SAME', name='ConvLayerEncoder{}'.format(d), a=tf.nn.elu)) 62 | encoders.append(layers[-1]) 63 | print("\tMaxpoolingLayer{}...".format(d)) 64 | layers.append(MaxPoolingLayer(incoming=layers[-1], ksize=(1, 3, 3, 1), strides=(1, 2, 2, 1), padding='SAME', 65 | name='MaxpoolingLayer{}'.format(d))) 66 | 67 | # 68 | # ConvLSTM Layer 69 | # 70 | if config.n_lstm: 71 | n_lstm = config.n_lstm 72 | lstm_x_fwd = config.kernel_lstm_fwd 73 | lstm_y_fwd = config.kernel_lstm_fwd 74 | lstm_x_bwd = config.kernel_lstm_bwd 75 | lstm_y_bwd = config.kernel_lstm_bwd 76 | 77 | lstm_input_channels_fwd = layers[-1].get_output_shape()[-1] 78 | if config.reduced_rec_lstm: 79 | lstm_input_channels_bwd = config.reduced_rec_lstm 80 | else: 81 | lstm_input_channels_bwd = n_lstm 82 | 83 | lstm_init = dict(W_ci=[conv_W_initializer([lstm_x_fwd, lstm_y_fwd, lstm_input_channels_fwd, n_lstm]), 84 | conv_W_initializer([lstm_x_bwd, lstm_y_bwd, lstm_input_channels_bwd, n_lstm])], 85 | W_ig=[conv_W_initializer([lstm_x_fwd, lstm_y_fwd, lstm_input_channels_fwd, n_lstm]), 86 | conv_W_initializer([lstm_x_bwd, lstm_y_bwd, lstm_input_channels_bwd, n_lstm])], 87 | W_og=[conv_W_initializer([lstm_x_fwd, lstm_y_fwd, lstm_input_channels_fwd, n_lstm]), 88 | conv_W_initializer([lstm_x_bwd, lstm_y_bwd, lstm_input_channels_bwd, n_lstm])], 89 | W_fg=[conv_W_initializer([lstm_x_fwd, lstm_y_fwd, lstm_input_channels_fwd, n_lstm]), 90 | conv_W_initializer([lstm_x_bwd, lstm_y_bwd, lstm_input_channels_bwd, n_lstm])], 91 | b_ci=constant([n_lstm]), 92 | b_ig=constant([n_lstm]), 93 | b_og=constant([n_lstm]), 94 | b_fg=constant([n_lstm], 1)) 95 | 96 | print("\tConvLSTM...") 97 | layers.append(ConvLSTMLayer(incoming=layers[-1], n_units=n_lstm, **lstm_init, 98 | a_out=get_rec_attr(tf, config.lstm_act), forgetgate=config.forgetgate, 99 | comb=config.lstm_comb, store_states=config.store_states, 100 | tickerstep_biases=tf.zeros, output_dropout=config.lstm_output_dropout, 101 | precomp_fwds=False)) 102 | lstm_layer = layers[-1] 103 | 104 | # 105 | # Optional maxpooling and upscaling of rec LSTM connections combined with/or optional feature squashing 106 | # 107 | ext_lstm_recurrence = None 108 | if config.lstm_rec_maxpooling: 109 | print("\tMaxpoolingDeconv...") 110 | layers.append( 111 | MaxPoolingLayer(incoming=layers[-1], ksize=(1, 3, 3, 1), strides=(1, 2, 2, 1), padding='SAME', 112 | name='MaxPoolingLayer')) 113 | layers.append(DeConvLayer(incoming=layers[-1], a=tf.nn.elu, 114 | W=conv_W_initializer([3, 3, layers[-1].get_output_shape()[-1], 115 | layers[-1].get_output_shape()[-1]]), 116 | strides=(1, 2, 2, 1), 117 | padding='SAME', name='DeConvLayer')) 118 | print("\tConvLSTMRecurrence...") 119 | ext_lstm_recurrence = layers[-1] 120 | 121 | if config.reduced_rec_lstm: 122 | print("\tFeatureSquashing...") 123 | layers.append(ConvLayer(incoming=layers[-1], 124 | W=conv_W_initializer([config.kernel_conv_out, config.kernel_conv_out, 125 | layers[-1].get_output_shape()[-1], 126 | config.reduced_rec_lstm]), 127 | padding='SAME', name='ConvLayerFeatureSquashing', a=tf.nn.elu)) 128 | print("\tConvLSTMRecurrence...") 129 | ext_lstm_recurrence = layers[-1] 130 | 131 | if ext_lstm_recurrence is not None: 132 | lstm_layer.add_external_recurrence(ext_lstm_recurrence) 133 | else: 134 | print("\tSubstituteConvLayer...") 135 | n_lstm = basenr_convs * (2 ** depth) * 4 136 | layers.append(ConvLayer(incoming=layers[-1], 137 | W=conv_W_initializer([config.kernel_conv, config.kernel_conv, 138 | layers[-1].get_output_shape()[-1], 139 | int(basenr_convs * (2 ** depth) * 4.5)]), 140 | padding='SAME', name='SubstituteConvLayer', a=tf.nn.elu)) 141 | lstm_layer = layers[-1] 142 | 143 | # 144 | # Decoder and upscaling layers 145 | # 146 | for d in list(range(1, depth + 1))[::-1]: 147 | print("\tUpscalingLayer{}...".format(d)) 148 | layers[-1] = ScalingLayer(incoming=layers[-1], size=encoders[d - 1].get_output_shape()[-3:-1], 149 | name='UpscalingLayergLayer{}'.format(d)) 150 | 151 | print("\tConcatLayer{}...".format(d)) 152 | layers.append(ConcatLayer([encoders[d - 1], layers[-1]], name='ConcatLayer{}'.format(d))) 153 | 154 | print("\tConvLayerDecoder{}...".format(d)) 155 | layers.append(ConvLayer(incoming=layers[-1], 156 | W=conv_W_initializer([config.kernel_conv, config.kernel_conv, 157 | layers[-1].get_output_shape()[-1], basenr_convs * (2 ** d)]), 158 | padding='SAME', name='ConvLayerDecoder{}'.format(d), a=tf.nn.elu)) 159 | 160 | # 161 | # ConvLayer for semantic segmentation 162 | # 163 | print("\tConvLayerSemanticSegmentation...") 164 | layers.append(ConvLayer(incoming=layers[-1], 165 | W=conv_W_initializer([config.kernel_conv_out, config.kernel_conv_out, 166 | layers[-1].get_output_shape()[-1], 11]), 167 | padding='SAME', name='ConvLayerSemanticSegmentation', a=tf.identity)) 168 | sem_seg_layer = layers[-1] 169 | 170 | # ---------------------------------------------------------------------------------------------------------- 171 | # Loop through sequence positions and create graph 172 | # ---------------------------------------------------------------------------------------------------------- 173 | 174 | # 175 | # Loop through sequence positions 176 | # 177 | print("\tRNN Loop...") 178 | sem_seg_out = list() 179 | for seq_pos in range(n_seq_pos): 180 | with tf.name_scope("Sequence_pos_{}".format(seq_pos)): 181 | print("\t seq. pos. {}...".format(seq_pos)) 182 | # Set input layer to X at frame (t) and outputs of upper layers at (t-1) 183 | layers[0].update(X[:, seq_pos:seq_pos + 1, :]) 184 | 185 | # Calculate new network output at (t), including new hidden states 186 | _ = lstm_layer.get_output() 187 | sem_seg_out.append(sem_seg_layer.get_output(prev_layers=encoders + [lstm_layer])) 188 | 189 | # 190 | # Loop through tickersteps 191 | # 192 | # # Use empty frame as X during ticker steps (did not work so good) 193 | # tickerstep_input = tf.zeros(dataset.X_shape[:1] + (1,) + dataset.X_shape[2:], dtype=tf.float32, 194 | # name="tickerframe") 195 | 196 | # Use last frame as X during ticker steps 197 | #tickerstep_input = X[:, -1:, :] 198 | #layers[0].update(tickerstep_input) 199 | 200 | #for tickerstep in range(config.tickersteps): 201 | # with tf.name_scope("Tickerstep_{}".format(tickerstep)): 202 | # print("\t tickerstep {}...".format(tickerstep)) 203 | # 204 | # # Calculate new network output at (t), including new hidden states 205 | # _ = lstm_layer.get_output(tickerstep_nodes=True) 206 | 207 | 208 | #sem_seg_out = sem_seg_layer.get_output(prev_layers=encoders + [lstm_layer]) 209 | 210 | print("\tDone!") 211 | 212 | # 213 | # Publish 214 | # 215 | self.X = X 216 | self.y_feed = y_ 217 | self.y_ = y_[:, 10:] 218 | self.output = tf.concat(sem_seg_out[10:], 1) 219 | self.__layers = layers 220 | self.__n_lstm = n_lstm 221 | self.__lstm_layer = lstm_layer 222 | self.lstm_layer = lstm_layer 223 | self.__plot_dict, self.__plot_range_dict, self.__plotsink = self.__setup_plotting(config) 224 | if include_org_label: 225 | self.y_org = y_org 226 | 227 | def get_layers(self): 228 | return self.__layers 229 | 230 | def get_plotsink(self): 231 | return self.__plotsink 232 | 233 | def get_plot_dict(self): 234 | return self.__plot_dict 235 | 236 | def get_plot_range_dict(self): 237 | return self.__plot_range_dict 238 | 239 | def __setup_plotting(self, config): 240 | # Prepare for plotting 241 | # Create a list of lists with keys to plot in a subplot 242 | plotsink = [] 243 | plot_dict = OrderedDict() 244 | plot_range_dict = OrderedDict() 245 | plot_sample = 0 246 | # only plot first, middle, and end frame when plotting LSTM outputs 247 | plot_frames = slice(-1, None) # slice(0, sample_len, int(sample_len/2)) 248 | 249 | # 250 | # init plot sink 251 | # 252 | plot_dict['X'] = self.X[plot_sample, plot_frames, :, :, :] 253 | plot_range_dict['X'] = [0, 1] 254 | plotsink.append(['X']) 255 | 256 | plot_dict['y_'] = self.y_[plot_sample, None, :, :] 257 | plot_range_dict['y_'] = [0, 20] 258 | plotsink[0].append('y_') 259 | 260 | # 261 | # Plot LSTM layer 262 | # 263 | 264 | # Output for first sample in mb 265 | if config.n_lstm: 266 | try: 267 | plot_dict_new, plotsink_new, plot_range_dict_new = self.__lstm_layer.get_plots_out(sample=plot_sample) 268 | 269 | # add LSTM output plot to first subfigure 270 | plotsink[0] += plotsink_new[0] 271 | plot_dict.update(plot_dict_new) 272 | plot_range_dict.update(plot_range_dict_new) 273 | 274 | # Weights from first LSTM unit 275 | plot_dict_new, plotsink_new, _ = self.__lstm_layer.get_plots_w(max_num_inp=6, max_num_out=1) 276 | 277 | plotsink += plotsink_new 278 | plot_dict.update(plot_dict_new) 279 | 280 | # States, if possible 281 | plot_dict_new, plotsink_new, _ = self.__lstm_layer.get_plots_state() 282 | plotsink += plotsink_new 283 | plot_dict.update(plot_dict_new) 284 | 285 | # 286 | # Plot activations in outputs from first 4 units 287 | # 288 | for unit in range(4): 289 | plot_dict['ConvLSTM_f{}'.format(unit)] = self.__lstm_layer.out[plot_sample, plot_frames, :, :, unit] 290 | plotsink.append(['ConvLSTM_f{}'.format(unit)]) 291 | 292 | except AttributeError: 293 | pass 294 | # 295 | # Plot outputs 296 | # 297 | plot_dict['out'] = tf.arg_max(self.output[plot_sample, plot_frames, :, :, :], 3) 298 | plot_range_dict['out'] = [0, 20] 299 | plotsink[0].append('out') 300 | 301 | # 302 | # Publish sink 303 | # 304 | return [plot_dict, plot_range_dict, plotsink] 305 | 306 | 307 | class Scaler(object): 308 | def __init__(self, config: Config, dataset): 309 | """ 310 | 311 | """ 312 | 313 | depth = config.get_value("enc_dec_depth", 2) 314 | basenr_convs = config.get_value("enc_dec_conv_maps_base", 32) 315 | include_org_label = config.get_value("include_org_label", False) 316 | init_name = config.get_value("conv_W_initializer", "weight_xavier_conv2d") 317 | conv_W_initializer = getattr(TeLL.initializations, init_name) 318 | shared = False 319 | 320 | # 321 | # Layer list 322 | # 323 | layers = list() 324 | 325 | # 326 | # Create placeholders for feeding an input frame and a label at the first timestep 327 | # 328 | n_seq_pos = dataset.X_shape[1] # dataset.X_shape is [sample, seq_pos, x, y, features) 329 | X = tf.placeholder(tf.float32, shape=dataset.X_shape) 330 | y_ = tf.placeholder(tf.int32, shape=dataset.y_shape) 331 | 332 | if include_org_label: 333 | y_org = tf.placeholder(tf.int32, shape=dataset.y_org_shape) 334 | 335 | # 336 | # Input Layer 337 | # 338 | input_shape = dataset.X_shape[:1] + (1,) + dataset.X_shape[2:] 339 | layers.append(RNNInputLayer(tf.zeros(input_shape, dtype=tf.float32))) 340 | 341 | # 342 | # Scaler Structure 343 | # 344 | conv_weights_shape = [config.kernel_conv, 345 | config.kernel_conv, 346 | layers[-1].get_output_shape()[-1], 347 | basenr_convs] 348 | 349 | if shared: 350 | shared_input_conv_weights = conv_W_initializer(conv_weights_shape) 351 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 352 | a=tf.nn.elu, dilation_rate=[11, 11])) 353 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 354 | a=tf.nn.elu, dilation_rate=[9, 9])) 355 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 356 | a=tf.nn.elu, dilation_rate=[7, 7])) 357 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 358 | a=tf.nn.elu, dilation_rate=[5, 5])) 359 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 360 | a=tf.nn.elu, dilation_rate=[3, 3])) 361 | layers.append(ConvLayer(incoming=layers[0], W=shared_input_conv_weights, 362 | a=tf.nn.elu, dilation_rate=[1, 1])) 363 | else: 364 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 365 | a=tf.nn.elu, dilation_rate=[11, 11])) 366 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 367 | a=tf.nn.elu, dilation_rate=[9, 9])) 368 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 369 | a=tf.nn.elu, dilation_rate=[7, 7])) 370 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 371 | a=tf.nn.elu, dilation_rate=[5, 5])) 372 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 373 | a=tf.nn.elu, dilation_rate=[3, 3])) 374 | layers.append(ConvLayer(incoming=layers[0], W=conv_W_initializer(conv_weights_shape), 375 | a=tf.nn.elu, dilation_rate=[1, 1])) 376 | 377 | # concat feature maps of all scale levels and reduce the number of features with a 1x1 conv 378 | layers.append(ConcatLayer(incomings=layers[1:])) 379 | conv_weights_shape = [1, 1, layers[-1].get_output_shape()[-1], basenr_convs] 380 | layers.append(ConvLayer(incoming=layers[-1], W=conv_W_initializer(conv_weights_shape))) 381 | 382 | # add 3 more conv layers to have some depth 383 | conv_weights_shape = [config.kernel_conv, 384 | config.kernel_conv, 385 | layers[-1].get_output_shape()[-1], 386 | basenr_convs] 387 | layers.append(ConvLayer(incoming=layers[-1], W=conv_W_initializer(conv_weights_shape))) 388 | layers.append(ConvLayer(incoming=layers[-1], W=conv_W_initializer(conv_weights_shape))) 389 | layers.append(ConvLayer(incoming=layers[-1], W=conv_W_initializer(conv_weights_shape))) 390 | 391 | # 392 | # Output Layer 393 | # 394 | layers.append(ConvLayer(incoming=layers[-1], 395 | W=conv_W_initializer([config.kernel_conv_out, config.kernel_conv_out, 396 | layers[-1].get_output_shape()[-1], 11]), 397 | padding='SAME', name='ConvLayerSemanticSegmentation', a=tf.identity)) 398 | sem_seg_layer = layers[-1] 399 | 400 | self.X = X 401 | self.y_ = y_ 402 | self.output = sem_seg_layer.get_output() 403 | -------------------------------------------------------------------------------- /samples/moving_mnist/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "baseline", 3 | "cuda_gpu": "0", 4 | "architecture": "architectures.ConvLSTMSemsegEfor", 5 | "iterations": 160000, 6 | "display_step": 10, 7 | "learning_rate": 1e-3, 8 | "enc_dec_depth": 2, 9 | "n_lstm": 0, 10 | "score_at": 1000, 11 | "plot_at": 20, 12 | "tf_allow_growth": true, 13 | "working_dir": "working_dir", 14 | "mnist_train_images": "../MNIST_data/train-images-idx3-ubyte.gz", 15 | "mnist_train_labels": "../MNIST_data/train-labels-idx1-ubyte.gz", 16 | "mnist_test_images": "../MNIST_data/t10k-images-idx3-ubyte.gz", 17 | "mnist_test_labels": "../MNIST_data/t10k-labels-idx1-ubyte.gz", 18 | "higher_num_on_top": true, 19 | "num_frames": 20, 20 | "batch_size": 16, 21 | "image_size": 64, 22 | "num_digits": 2, 23 | "step_length": 0.1, 24 | "label_threshold": 127, 25 | "kernel_lstm_fwd": 3, 26 | "kernel_lstm_bwd": 3, 27 | "kernel_conv": 3, 28 | "kernel_conv_out": 1, 29 | "reduced_rec_lstm": false, 30 | "lstm_rec_maxpooling": false, 31 | "lstm_comb": "add", 32 | "forgetgate": true, 33 | "store_states": false, 34 | "lstm_act": "nn.elu", 35 | "lstm_output_dropout": false, 36 | "tickersteps": 0 37 | } 38 | -------------------------------------------------------------------------------- /samples/moving_mnist/config_gauss.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "gauss", 3 | "cuda_gpu": "0", 4 | "architecture": "architectures.ConvLSTMSemsegEfor", 5 | "iterations": 160000, 6 | "display_step": 10, 7 | "learning_rate": 1e-3, 8 | "blur_filter_size": 11, 9 | "n_lstm": 0, 10 | "score_at": 1000, 11 | "plot_at": 20, 12 | "tf_allow_growth": true, 13 | "working_dir": "working_dir", 14 | "mnist_train_images": "../MNIST_data/train-images-idx3-ubyte.gz", 15 | "mnist_train_labels": "../MNIST_data/train-labels-idx1-ubyte.gz", 16 | "mnist_test_images": "../MNIST_data/t10k-images-idx3-ubyte.gz", 17 | "mnist_test_labels": "../MNIST_data/t10k-labels-idx1-ubyte.gz", 18 | "higher_num_on_top": true, 19 | "num_frames": 20, 20 | "batch_size": 16, 21 | "image_size": 64, 22 | "num_digits": 2, 23 | "step_length": 0.1, 24 | "label_threshold": 127, 25 | "kernel_lstm_fwd": 3, 26 | "kernel_lstm_bwd": 3, 27 | "kernel_conv": 3, 28 | "kernel_conv_out": 1, 29 | "reduced_rec_lstm": false, 30 | "lstm_rec_maxpooling": false, 31 | "lstm_comb": "add", 32 | "forgetgate": true, 33 | "store_states": false, 34 | "lstm_act": "nn.elu", 35 | "lstm_output_dropout": false, 36 | "tickersteps": 0 37 | } 38 | -------------------------------------------------------------------------------- /samples/moving_mnist/config_lstm.json: -------------------------------------------------------------------------------- 1 | { 2 | "specs": "lstm", 3 | "cuda_gpu": "0", 4 | "architecture": "architectures.ConvLSTMSemsegEfor", 5 | "iterations": 160000, 6 | "display_step": 10, 7 | "learning_rate": 1e-3, 8 | "enc_dec_depth": 2, 9 | "n_lstm": 64, 10 | "score_at": 1000, 11 | "plot_at": 20, 12 | "tf_allow_growth": true, 13 | "working_dir": "working_dir", 14 | "mnist_train_images": "../MNIST_data/train-images-idx3-ubyte.gz", 15 | "mnist_train_labels": "../MNIST_data/train-labels-idx1-ubyte.gz", 16 | "mnist_test_images": "../MNIST_data/t10k-images-idx3-ubyte.gz", 17 | "mnist_test_labels": "../MNIST_data/t10k-labels-idx1-ubyte.gz", 18 | "higher_num_on_top": true, 19 | "num_frames": 20, 20 | "batch_size": 16, 21 | "image_size": 64, 22 | "num_digits": 2, 23 | "step_length": 0.1, 24 | "label_threshold": 127, 25 | "kernel_lstm_fwd": 3, 26 | "kernel_lstm_bwd": 3, 27 | "kernel_conv": 3, 28 | "kernel_conv_out": 1, 29 | "reduced_rec_lstm": false, 30 | "lstm_rec_maxpooling": false, 31 | "lstm_comb": "add", 32 | "forgetgate": true, 33 | "store_states": true, 34 | "lstm_act": "nn.elu", 35 | "lstm_output_dropout": false, 36 | "tickersteps": 0 37 | } 38 | -------------------------------------------------------------------------------- /samples/moving_mnist/dataset.py: -------------------------------------------------------------------------------- 1 | """ 2 | Essence downloaded from http://www.cs.toronto.edu/~nitish/unsupervised_video/ 3 | """ 4 | 5 | import numpy as np 6 | import gzip 7 | import sys 8 | 9 | from TeLL.config import Config 10 | 11 | 12 | def load_mnist(file, labels=False): 13 | print('open ' + file) 14 | with gzip.open(file, 'rb') as f: 15 | # skip header 16 | f.read(8 if labels else 16) 17 | a = np.array([float(i) for i in f.read()]) 18 | 19 | if not labels: 20 | a = np.reshape(a, [-1, 28, 28]) 21 | 22 | return a 23 | 24 | 25 | def load_mnist_images(file): 26 | return load_mnist(file, labels=False) 27 | 28 | 29 | def load_mnist_labels(file): 30 | return load_mnist(file, labels=True) 31 | 32 | 33 | class BouncingMNISTDataHandler(object): 34 | def __init__(self, config: Config, images_file, labels_file, rng): 35 | self.rng = rng 36 | self.seq_length_ = config.num_frames 37 | self.batch_size_ = config.batch_size 38 | self.image_size_ = config.image_size 39 | self.num_digits_ = config.num_digits 40 | self.step_length_ = config.step_length 41 | self.label_threshold_ = config.label_threshold 42 | self.higher_num_on_top_ = config.higher_num_on_top 43 | self.dataset_size_ = 10000 # The dataset is really infinite. This is just for validation. 44 | self.digit_size_ = 28 45 | self.frame_size_ = self.image_size_ ** 2 46 | self.data_ = load_mnist_images(images_file) 47 | self.labels_ = load_mnist_labels(labels_file) 48 | self.indices_ = np.arange(self.data_.shape[0]) 49 | self.row_ = 0 50 | self.rng.shuffle(self.indices_) 51 | 52 | def GetBatchSize(self): 53 | return self.batch_size_ 54 | 55 | def GetDims(self): 56 | return self.frame_size_ 57 | 58 | def GetDatasetSize(self): 59 | return self.dataset_size_ 60 | 61 | def GetSeqLength(self): 62 | return self.seq_length_ 63 | 64 | def Reset(self): 65 | self.row_ = 0 66 | 67 | def GetRandomTrajectory(self, batch_size): 68 | length = self.seq_length_ 69 | canvas_size = self.image_size_ - self.digit_size_ 70 | 71 | # Initial position uniform random inside the box. 72 | y = self.rng.rand(batch_size) 73 | x = self.rng.rand(batch_size) 74 | 75 | # Choose a random velocity. 76 | theta = self.rng.rand(batch_size) * 2 * np.pi 77 | v_y = np.sin(theta) 78 | v_x = np.cos(theta) 79 | 80 | start_y = np.zeros((length, batch_size)) 81 | start_x = np.zeros((length, batch_size)) 82 | for i in range(length): 83 | # Take a step along velocity. 84 | y += v_y * self.step_length_ 85 | x += v_x * self.step_length_ 86 | 87 | # Bounce off edges. 88 | for j in range(batch_size): 89 | if x[j] <= 0: 90 | x[j] = 0 91 | v_x[j] = -v_x[j] 92 | if x[j] >= 1.0: 93 | x[j] = 1.0 94 | v_x[j] = -v_x[j] 95 | if y[j] <= 0: 96 | y[j] = 0 97 | v_y[j] = -v_y[j] 98 | if y[j] >= 1.0: 99 | y[j] = 1.0 100 | v_y[j] = -v_y[j] 101 | start_y[i, :] = y 102 | start_x[i, :] = x 103 | 104 | # Scale to the size of the canvas. 105 | start_y = (canvas_size * start_y).astype(np.int32) 106 | start_x = (canvas_size * start_x).astype(np.int32) 107 | return start_y, start_x 108 | 109 | def Overlap(self, a, b): 110 | """ Put b on top of a.""" 111 | return np.maximum(a, b) 112 | # return b 113 | 114 | def GetBatch(self, batch_size=None): 115 | if batch_size is None: 116 | batch_size = self.batch_size_ 117 | 118 | start_y, start_x = self.GetRandomTrajectory(batch_size * self.num_digits_) 119 | data = np.zeros((self.seq_length_, batch_size, self.image_size_, self.image_size_), dtype=np.float32) 120 | labels = np.zeros((self.seq_length_, batch_size, self.image_size_, self.image_size_, self.num_digits_), 121 | dtype=np.float32) 122 | for j in range(batch_size): 123 | for n in range(self.num_digits_): 124 | ind = self.indices_[self.row_] 125 | self.row_ += 1 126 | if self.row_ == self.data_.shape[0]: 127 | self.row_ = 0 128 | self.rng.shuffle(self.indices_) 129 | 130 | digit_image = self.data_[ind, :, :] 131 | digit_label = self.labels_[ind] 132 | 133 | for i in range(self.seq_length_): 134 | # draw digit into data 135 | top = start_y[i, j * self.num_digits_ + n] 136 | left = start_x[i, j * self.num_digits_ + n] 137 | bottom = top + self.digit_size_ 138 | right = left + self.digit_size_ 139 | data[i, j, top:bottom, left:right] = self.Overlap( 140 | data[i, j, top:bottom, left:right], digit_image) 141 | 142 | # draw digit into labels 143 | labels[i, j, top:bottom, left:right, n] = \ 144 | np.asarray(digit_image > self.label_threshold_, np.int) * (digit_label + 1) 145 | 146 | if self.higher_num_on_top_: 147 | labels = np.amax(labels, 4) 148 | 149 | return np.swapaxes(np.reshape(data, list(data.shape) + [1]), 0, 1), \ 150 | np.swapaxes(labels, 0, 1) 151 | 152 | 153 | #def main(): 154 | # data_pb = ReadDataProto(sys.argv[1]) 155 | # 156 | # print(data_pb.data_file) 157 | # print(data_pb.labels_file) 158 | # 159 | # dh = BouncingMNISTDataHandler(data_pb) 160 | # data, labels = dh.GetBatch() 161 | # np.save(data_pb.dataset_name + '.npy', data) 162 | # np.save(data_pb.dataset_name + '_labels.npy', labels) 163 | 164 | 165 | #if __name__ == '__main__': 166 | # main() 167 | -------------------------------------------------------------------------------- /samples/moving_mnist/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | © Michael Widrich, Markus Hofmarcher, 2017 3 | 4 | """ 5 | # Import MNIST data 6 | from tensorflow.examples.tutorials.mnist import input_data 7 | 8 | from dataset import BouncingMNISTDataHandler 9 | import numpy as np 10 | 11 | # Import TeLL 12 | from TeLL.config import Config 13 | from TeLL.session import TeLLSession 14 | from TeLL.utility.timer import Timer 15 | from TeLL.utility.misc import AbortRun, check_kill_file 16 | from TeLL.loss import image_crossentropy, iou_loss, blurred_cross_entropy 17 | from TeLL.evaluation import Evaluation 18 | from TeLL.utility.plotting import Plotter, save_subplots 19 | from TeLL.utility.plotting_daemons import start_plotting_daemon, stop_plotting_daemon 20 | from collections import OrderedDict 21 | import os 22 | 23 | # Import Tensorflow 24 | if __name__ == "__main__": 25 | plotter = Plotter(num_workers=5, plot_function=save_subplots) 26 | 27 | import tensorflow as tf 28 | 29 | from scipy.misc import imsave 30 | 31 | # ---------------------------------------------------------------------------------------------------------------------- 32 | # Functions 33 | # ---------------------------------------------------------------------------------------------------------------------- 34 | 35 | class DataSet(object): 36 | def __init__(self, x_shape, y_shape): 37 | self.X_shape = x_shape 38 | self.y_shape = y_shape 39 | 40 | def to_color(labels): 41 | image = np.zeros(labels.shape + (3,)) 42 | print(labels.shape) 43 | 44 | for i in range(labels.shape[0]): 45 | for j in range(labels.shape[1]): 46 | for k in range(labels.shape[2]): 47 | for l in range(labels.shape[3]): 48 | image[i, j, k, l] = { 49 | 0: [ 0, 0, 0], 50 | 1: [255, 0, 0], 51 | 2: [ 0, 255, 0], 52 | 3: [ 0, 0, 255], 53 | 4: [255, 255, 0], 54 | 5: [ 0, 255, 255], 55 | 6: [255, 0, 255], 56 | 7: [255, 255, 255], 57 | 8: [128, 255, 0], 58 | 9: [ 0, 128, 255], 59 | 10: [255, 0, 128], 60 | 11: [255, 128, 0] 61 | }[labels[i, j, k, l]] 62 | 63 | return image 64 | 65 | 66 | def to_image(pred, true): 67 | # in shape is (20, batch_size, 64, 64, 3) 68 | # out shape is (batch_size, 64 * 10, 64 * 4, 3) 69 | 70 | assert(pred.shape == true.shape) 71 | shape = pred.shape 72 | out = np.zeros((shape[1], 256, 640, 3)) 73 | 74 | for i in range(shape[0]): 75 | for t in range(shape[1]): 76 | h_from = (t % 10) * 64 77 | h_to = h_from + 64 78 | v_from = (0 if t < 10 else 2) * 64 79 | v_to = v_from + 64 80 | out[i, v_from:v_to, h_from:h_to] = true[i, t] 81 | out[i, v_from+64:v_to+64, h_from:h_to] = pred[i, t] 82 | 83 | return out 84 | 85 | 86 | def main(_): 87 | np.random.seed(0) 88 | rng = np.random.RandomState(seed=0) 89 | 90 | config = Config() 91 | 92 | # 93 | # Load Data 94 | # 95 | with Timer(name="Load data"): 96 | training_data = BouncingMNISTDataHandler( 97 | config, config.mnist_train_images, config.mnist_train_labels, rng) 98 | test_data = BouncingMNISTDataHandler( 99 | config, config.mnist_test_images, config.mnist_test_labels, rng) 100 | 101 | dataset = DataSet((config.batch_size, config.num_frames, config.image_size, config.image_size, 1), 102 | (config.batch_size, config.num_frames, config.image_size, config.image_size)) 103 | 104 | # Create new TeLL session with two summary writers 105 | tell = TeLLSession(config=config, summaries=["train", "validation"], model_params={"dataset": dataset}) 106 | 107 | # Get some members from the session for easier usage 108 | session = tell.tf_session 109 | summary_writer_train, summary_writer_validation = tell.tf_summaries["train"], tell.tf_summaries["validation"] 110 | model = tell.model 111 | workspace, config = tell.workspace, tell.config 112 | 113 | # Parameters 114 | learning_rate = config.get_value("learning_rate", 1e-3) 115 | iterations = config.get_value("iterations", 1000) 116 | batch_size = config.get_value("batch_size", 256) 117 | display_step = config.get_value("display_step", 10) 118 | calc_statistics = config.get_value("calc_statistics", False) 119 | blur_filter_size = config.get_value("blur_filter_size", None) 120 | 121 | training_summary_tensors = OrderedDict() 122 | 123 | # Define loss and optimizer 124 | #with tf.name_scope("Cost"): 125 | # sem_seg_loss, _ = image_crossentropy(pred=model.output, target=model.y_, 126 | # calc_statistics=calc_statistics, reduce_by="sum") 127 | # optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(sem_seg_loss) 128 | # tf.summary.scalar("Loss", sem_seg_loss) 129 | 130 | # Evaluate model 131 | validation_summary_tensors = OrderedDict() 132 | 133 | # validationset always uses class weights for loss calculation 134 | with tf.name_scope('Cost'): 135 | blur_sampling_range = tf.placeholder(tf.float32) 136 | 137 | if blur_filter_size is not None: 138 | sem_seg_loss = blurred_cross_entropy(output=model.output, target=model.y_, 139 | filter_size=blur_filter_size, 140 | sampling_range=blur_sampling_range) 141 | else: 142 | sem_seg_loss, _ = image_crossentropy(pred=model.output, target=model.y_, 143 | reduce_by="mean", calc_statistics=calc_statistics) 144 | optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(sem_seg_loss) 145 | iou, iou_op = tf.contrib.metrics.streaming_mean_iou( 146 | predictions=tf.squeeze(tf.arg_max(model.output, 4)), 147 | labels=tf.squeeze(model.y_), 148 | num_classes=model.output.get_shape()[-1]) 149 | loss_prot = tf.summary.scalar("Loss", sem_seg_loss) 150 | iou_prot = tf.summary.scalar("IoU", iou) 151 | 152 | train_summaries = tf.summary.merge([loss_prot]) 153 | valid_summaries = tf.summary.merge([loss_prot, iou_prot]) 154 | 155 | # Initialize tensorflow variables (either initializes them from scratch or restores from checkpoint) 156 | step = tell.initialize_tf_variables().global_step 157 | 158 | # ------------------------------------------------------------------------- 159 | # Start training 160 | # ------------------------------------------------------------------------- 161 | 162 | plot_elements_sym = list(model.get_plot_dict().values()) 163 | plot_elements = list() 164 | plot_ranges = model.get_plot_range_dict() 165 | 166 | try: 167 | while step < iterations: 168 | check_kill_file(workspace=workspace) 169 | batch_x, batch_y = training_data.GetBatch() 170 | 171 | i = step * batch_size 172 | if step % display_step == 0: 173 | mean_loss = 0. 174 | for j in range(10): 175 | test_x, test_y = test_data.GetBatch() 176 | 177 | summary, loss, _, *plot_elements = session.run([valid_summaries, sem_seg_loss, iou_op, *plot_elements_sym], 178 | feed_dict={model.X: test_x, 179 | model.y_feed: test_y, 180 | blur_sampling_range: 3.5}) 181 | 182 | summary_writer_validation.add_summary(summary, i) 183 | mean_loss += loss 184 | 185 | # Re-associate returned tensorflow values to plotting keys 186 | plot_dict = OrderedDict(zip(list(model.get_plot_dict().keys()), plot_elements)) 187 | 188 | # Plot outputs and cell states over frames if specified 189 | if config.store_states and 'ConvLSTMLayer_h' in plot_dict and step % config.plot_at == 0: 190 | convh = plot_dict['ConvLSTMLayer_h'] 191 | convrh = [c[0, :, :, 0] for c in convh] 192 | convrh = [convrh[:6], convrh[6:12], convrh[12:18], convrh[18:24], convrh[24:]] 193 | plot_args = dict(images=convrh, 194 | filename=os.path.join(workspace.get_result_dir(), 195 | "step{}_h.png".format(step))) 196 | plotter.set_plot_kwargs(plot_args) 197 | plotter.plot() 198 | 199 | if config.store_states and 'ConvLSTMLayer_c' in plot_dict and step % config.plot_at == 0: 200 | convc = plot_dict['ConvLSTMLayer_c'] 201 | convrc = [c[0, :, :, 0] for c in convc] 202 | convrc = [convrc[:6], convrc[6:12], convrc[12:18], convrc[18:24], convrc[24:]] 203 | plot_args = dict(images=convrc, 204 | filename=os.path.join(workspace.get_result_dir(), 205 | "step{}_c.png".format(step))) 206 | plotter.set_plot_kwargs(plot_args) 207 | plotter.plot() 208 | print('Validation Loss at step {}: {}'.format(i, mean_loss / 10)) 209 | 210 | summary, loss, _ = session.run([train_summaries, sem_seg_loss, optimizer], 211 | feed_dict={model.X: batch_x, 212 | model.y_feed: batch_y, 213 | blur_sampling_range: 3.5}) 214 | summary_writer_train.add_summary(summary, i) 215 | 216 | step += 1 217 | 218 | print("Training Finished!") 219 | 220 | # Final Eval 221 | mean_loss = 0. 222 | 223 | for j in range(100): 224 | test_x, test_y = test_data.GetBatch() 225 | summary, loss, _ = session.run([valid_summaries, sem_seg_loss, iou_op], 226 | feed_dict={model.X: test_x, 227 | model.y_feed: test_y, 228 | blur_sampling_range: 3.5}) 229 | mean_loss += loss 230 | 231 | test_x, test_y = test_data.GetBatch() 232 | pred = session.run(tf.argmax(model.output, 4), feed_dict={model.X: test_x}) 233 | 234 | pred = to_color(pred) 235 | true = to_color(test_y) 236 | out = to_image(pred, true) 237 | 238 | for i in range(pred.shape[0]): 239 | imsave(tell.workspace.get_result_dir() + '/sample_{:02d}.png'.format(i), out[i,]) 240 | 241 | print("Validation Loss {}".format(mean_loss / 100)) 242 | except AbortRun: 243 | print("Aborting...") 244 | finally: 245 | tell.close(global_step=step) 246 | plotter.close() 247 | 248 | 249 | if __name__ == "__main__": 250 | tf.app.run() 251 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=0 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Tensorflow Layer Library (TeLL) 2 | Provides a variety of tensorflow-based network layers, flexible (recurrent) network designs, convenience routines for saving and resuming networks, and more! 3 | Copyright (c) 2016-2017 Michael Widrich and Markus Hofmarcher, Institute of Bioinformatics, Johannes Kepler University Linz, Austria 4 | """ 5 | 6 | # Always prefer setuptools over distutils 7 | from setuptools import setup, find_packages 8 | # To use a consistent encoding 9 | from codecs import open 10 | from os import path 11 | 12 | here = path.abspath(path.dirname(__file__)) 13 | 14 | # Get the long description from the README file 15 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 16 | long_description = f.read() 17 | 18 | setup( 19 | name='TeLL', 20 | 21 | # Versions should comply with PEP440. For a discussion on single-sourcing 22 | # the version across setup.py and the project code, see 23 | # https://packaging.python.org/en/latest/single_source_version.html 24 | version='1.0', 25 | 26 | description='Provides a variety of tensorflow-based network layers, flexible (recurrent) network designs, convenience routines for saving and resuming networks, and more!', 27 | long_description=long_description, 28 | 29 | # The project's main homepage. 30 | url='https://github.com/ml-jku/tensorflow-layer-library', 31 | 32 | # Author details 33 | author='Michael Widrich, Markus Hofmarcher', 34 | author_email='widrich@bioinf.jku.at, hofmarcher@bioinf.jku.at', 35 | 36 | # Choose your license 37 | license='MIT License', 38 | 39 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 40 | classifiers=[ 41 | # How mature is this project? Common values are 42 | # 3 - Alpha 43 | # 4 - Beta 44 | # 5 - Production/Stable 45 | 'Development Status :: 4 - Beta', 46 | 47 | # Indicate who your project is intended for 48 | 'Intended Audience :: Developers', 49 | 'Topic :: Software Development :: Deep Learning', 50 | 51 | # Pick your license as you wish (should match "license" above) 52 | 'License :: OSI Approved :: MIT License', 53 | 54 | # Specify the Python versions you support here. In particular, ensure 55 | # that you indicate whether you support Python 2, Python 3 or both. 56 | 'Programming Language :: Python :: 3.5', 57 | 'Programming Language :: Python :: 3.6', 58 | ], 59 | 60 | # What does your project relate to? 61 | keywords='Library on top of tensorflow for convenient design of deep (recurrent) networks.', 62 | 63 | # You can just specify the packages manually here if your project is 64 | # simple. Or you can use find_packages(). 65 | packages=find_packages(), 66 | 67 | # List run-time dependencies here. These will be installed by pip when 68 | # your project is installed. For an analysis of "install_requires" vs pip's 69 | # requirements files see: 70 | # https://packaging.python.org/en/latest/requirements.html 71 | install_requires=['matplotlib>=2', 72 | 'numpy>=1.12.0', 73 | 'pandas>=0.19.0', 74 | 'Pillow>=4.0.0', 75 | 'natsort>=5.0.2', 76 | 'progressbar2>=3.10.0', 77 | 'multiprocess>=0.70.5' 78 | ], 79 | 80 | extras_require={ 81 | 'tensorflow-gpu': ["tensorflow-gpu>=1.0.0"], 82 | 'tensorflow': ["tensorflow>=1.0.0"] 83 | }, 84 | 85 | # To provide executable scripts, use entry points in preference to the 86 | # "scripts" keyword. Entry points provide cross-platform support and allow 87 | # pip to create the appropriate form of executable for the target platform. 88 | entry_points={ 89 | 'console_scripts': [ 90 | 'tell-resume=TeLL.scripts.resume:main', 91 | 'tell-ising-dropout=TeLL.scripts.dropoutmask:main', 92 | ], 93 | } 94 | ) 95 | --------------------------------------------------------------------------------