From c7d0b81e9143de1b2d0b4ecd9477220ed4752af4 Mon Sep 17 00:00:00 2001 From: xanderjakeq Date: Wed, 23 Feb 2022 23:48:09 -0500 Subject: [PATCH] wip: refactor from python2 to 3 I used the tool `2to3` to make quick syntactical changes, then updated dependencies to be compatible with python3. Currently trying to refactor so the project will work with the new packages. --- .gitignore | 2 + README.md | 60 ++++---- attentive_convlstm.py | 12 +- dcn_resnet.py | 80 +++++----- dcn_vgg.py | 34 ++--- gaussian_prior.py | 8 +- hooks/hook-numpy.py | 3 + hooks/hook-theano.py | 3 + main.py | 16 +- models.py | 36 ++--- pyoxidizer.bzl | 346 ++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 46 +++++- utilities.py | 4 +- 13 files changed, 525 insertions(+), 125 deletions(-) create mode 100644 hooks/hook-numpy.py create mode 100644 hooks/hook-theano.py create mode 100644 pyoxidizer.bzl diff --git a/.gitignore b/.gitignore index 678993b..73a125a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ /inputs env/ weights/ +*.bak +models/ diff --git a/README.md b/README.md index c227624..265a5a4 100644 --- a/README.md +++ b/README.md @@ -9,30 +9,33 @@ Transactions on Image Processing, 2018_ Please cite with the following Bibtex code: -````@article{cornia2018predicting, author = {Cornia, Marcella and Baraldi, +``` +@article{cornia2018predicting, author = {Cornia, Marcella and Baraldi, Lorenzo and Serra, Giuseppe and Cucchiara, Rita}, title = {{Predicting Human Eye Fixations via an LSTM-based Saliency Attentive Model}}, journal = {IEEE Transactions on Image Processing}, volume={27}, number={10}, pages={5142--5154}, -year = {2018} } ``` +year = {2018} } +``` The PDF of the article is available at this [link](http://aimagelab.ing.unimore.it/imagelab/pubblicazioni/2018-tip.pdf). Additional experimental results are reported in the following short paper: -_Marcella Cornia, Lorenzo Baraldi, Giuseppe Serra, Rita Cucchiara_ _SAM: -Pushing the Limits of Saliency Prediction Models_ _Proceedings of the IEEE/CVF +_Marcella Cornia, Lorenzo Baraldi, Giuseppe Serra, Rita Cucchiara_ _SAM: +Pushing the Limits of Saliency Prediction Models_ _Proceedings of the IEEE/CVF International Conference on Computer Vision and Pattern Recognition Workshops, 2018_ Please cite with the following Bibtex code: -``` @inproceedings{cornia2018sam, author = {Cornia, Marcella and Baraldi, +``` +@inproceedings{cornia2018sam, author = {Cornia, Marcella and Baraldi, Lorenzo and Serra, Giuseppe and Cucchiara, Rita}, title = {{SAM: Pushing the Limits of Saliency Prediction Models}}, booktitle = {Proceedings of the IEEE/CVF International Conference on Computer Vision and Pattern Recognition Workshops}, -year = {2018} } ``` - +year = {2018} } +``` ## Abstract @@ -53,26 +56,25 @@ different scenarios. ![sam-fig](https://raw.githubusercontent.com/marcellacornia/sam/master/figs/model.jpg) ## Requirements -* Python 2.7 -* [Theano](https://github.com/Theano/Theano) 0.9.0 -* [Keras](https://github.com/fchollet/keras) 1.1.0, configured for using Theano + +- Python 2.7 +- [Theano](https://github.com/Theano/Theano) 0.9.0 +- [Keras](https://github.com/fchollet/keras) 1.1.0, configured for using Theano as backend -* OpenCV 3.0.0 +- OpenCV 3.0.0 -Note: Be sure to have ```"image_dim_ordering": "th"``` and ```"backend": -"theano"``` in your keras.json file. +Note: Be sure to have `"image_dim_ordering": "th"` and `"backend": "theano"` in your keras.json file. ## Usage We built two different versions of our model: one based on the VGG-16 + (**SAM-VGG**) and the other based on the ResNet-50 (**SAM-ResNet**). It is -possible use both versions of SAM by changing the ```version``` variable in the -[config.py](config.py) file (set ```version = 0``` for SAM-VGG or ```version = -1``` for SAM-ResNet). +possible use both versions of SAM by changing the `version` variable in the +[config.py](config.py) file (set `version = 0` for SAM-VGG or `version = 1` for SAM-ResNet). -To compute saliency maps using our pre-trained model: ``` python main.py test -path/to/images/folder/ ``` where ```"path/to/images/folder/"``` is the path of a +To compute saliency maps using our pre-trained model: `python main.py test path/to/images/folder/` where `"path/to/images/folder/"` is the path of a folder containing the images for which you want to calculate the saliency maps. -To train our model from scratch: ``` python main.py train ``` It is also +To train our model from scratch: `python main.py train` It is also necessary to set parameters and paths in the [config.py](config.py) file. Note: To train our model, both binary fixation maps and groundtruth density maps @@ -81,33 +83,37 @@ format used in SALICON (.mat files). If you want to train our model with other datasets, be sure to appropriately change the loading functions. ## Pretrained Models Download one of the following pretrained models and save it + in the code folder: -* SAM-VGG trained on SALICON (2015 release): + +- SAM-VGG trained on SALICON (2015 release): **[sam-vgg_salicon_weights.pkl](https://github.com/marcellacornia/sam/releases/download/1.0/sam-vgg_salicon_weights.pkl)** -* SAM-ResNet trained on SALICON (2015 release): +- SAM-ResNet trained on SALICON (2015 release): **[sam-resnet_salicon_weights.pkl](https://github.com/marcellacornia/sam/releases/download/1.0/sam-resnet_salicon_weights.pkl)** -* SAM-ResNet trained on SALICON (2017 release): +- SAM-ResNet trained on SALICON (2017 release): **[sam-resnet_salicon2017_weights.pkl](https://github.com/marcellacornia/sam/releases/download/1.0/sam-resnet_salicon2017_weights.pkl)** ## Precomputed Saliency Maps We provide saliency maps predicted by SAM-VGG and + SAM-ResNet for three standard datasets (SALICON, MIT1003 and CAT2000): -* **[SAM-VGG + +- **[SAM-VGG predictions](https://github.com/marcellacornia/sam/releases/download/1.0/sam-vgg_predictions.zip)** -* **[SAM-ResNet +- **[SAM-ResNet predictions](https://github.com/marcellacornia/sam/releases/download/1.0/sam-resnet_predictions.zip)** In addition, we provide saliency maps predicted by SAM-ResNet on the new release of the SALICON dataset: -* **[SAM-ResNet predictions (SALICON - 2017)](https://github.com/marcellacornia/sam/releases/download/1.0/sam-resnet_predictions_salicon2017.zip)** + +- **[SAM-ResNet predictions (SALICON 2017)](https://github.com/marcellacornia/sam/releases/download/1.0/sam-resnet_predictions_salicon2017.zip)** ## Contact For more datails about our research please visit our + [page](http://imagelab.ing.unimore.it/imagelab/researchActivity.asp?idActivity=30). If you have any general doubt about our work, please use the [public issues section](https://github.com/marcellacornia/sam/issues) on this github repo. Alternatively, drop us an e-mail at or . -```` ### [environment setup](./setup.md) diff --git a/attentive_convlstm.py b/attentive_convlstm.py index 7502c53..4981b46 100644 --- a/attentive_convlstm.py +++ b/attentive_convlstm.py @@ -1,8 +1,8 @@ -from __future__ import division + import keras.backend as K from keras.layers import Layer, InputSpec from keras.layers.convolutional import Convolution2D -from keras import initializations, activations +from keras import initializers, activations class AttentiveConvLSTM(Layer): @@ -17,9 +17,9 @@ def __init__(self, nb_filters_in, nb_filters_out, nb_filters_att, nb_rows, nb_co self.nb_filters_att = nb_filters_att self.nb_rows = nb_rows self.nb_cols = nb_cols - self.init = initializations.get(init) - self.inner_init = initializations.get(inner_init) - self.attentive_init = initializations.get(attentive_init) + self.init = initializers.get(init) + self.inner_init = initializers.get(inner_init) + self.attentive_init = initializers.get(attentive_init) self.activation = activations.get(activation) self.inner_activation = activations.get(inner_activation) self.initial_weights = weights @@ -155,4 +155,4 @@ def call(self, x, mask=None): if last_output.ndim == 3: last_output = K.expand_dims(last_output, dim=0) - return last_output \ No newline at end of file + return last_output diff --git a/dcn_resnet.py b/dcn_resnet.py index bf0460f..a63f7cf 100644 --- a/dcn_resnet.py +++ b/dcn_resnet.py @@ -1,12 +1,12 @@ ''' This code is part of the Keras ResNet-50 model ''' -from __future__ import print_function -from __future__ import absolute_import -from keras.layers import merge, Input, Activation -from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D -from keras.layers.convolutional import AtrousConvolution2D + + +from keras.layers import add, Input, Activation +from keras.layers import Conv2D, MaxPooling2D, ZeroPadding2D +from keras.layers.convolutional import Conv2D from keras.layers import BatchNormalization from keras. models import Model from keras import backend as K @@ -22,19 +22,19 @@ def identity_block(input_tensor, kernel_size, filters, stage, block): conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' - x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) + x = Conv2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter2, kernel_size, kernel_size, - border_mode='same', name=conv_name_base + '2b')(x) + x = Conv2D(nb_filter2, kernel_size, kernel_size, + padding='same', name=conv_name_base + '2b')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) - x = merge([x, input_tensor], mode='sum') + x = add([x, input_tensor]) x = Activation('relu')(x) return x @@ -46,75 +46,75 @@ def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)) conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' - x = Convolution2D(nb_filter1, 1, 1, subsample=strides, + x = Conv2D(nb_filter1, (1, 1), strides=strides, name=conv_name_base + '2a')(input_tensor) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same', + x = Conv2D(nb_filter2, kernel_size, kernel_size, padding='same', name=conv_name_base + '2b')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) - shortcut = Convolution2D(nb_filter3, 1, 1, subsample=strides, + shortcut = Conv2D(nb_filter3, (1, 1), strides=strides, name=conv_name_base + '1')(input_tensor) shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut) - x = merge([x, shortcut], mode='sum') + x = add([x, shortcut]) x = Activation('relu')(x) return x -def conv_block_atrous(input_tensor, kernel_size, filters, stage, block, atrous_rate=(2, 2)): +def conv_block_dilation(input_tensor, kernel_size, filters, stage, block, dilation_rate=(2, 2)): nb_filter1, nb_filter2, nb_filter3 = filters bn_axis = 1 conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' - x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) + x = Conv2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) x = Activation('relu')(x) - x = AtrousConvolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same', - atrous_rate=atrous_rate, name=conv_name_base + '2b')(x) + x = Conv2D(nb_filter2, kernel_size, kernel_size, padding='same', + dilation_rate=dilation_rate, name=conv_name_base + '2b')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) - shortcut = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '1')(input_tensor) + shortcut = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '1')(input_tensor) shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut) - x = merge([x, shortcut], mode='sum') + x = add([x, shortcut]) x = Activation('relu')(x) return x -def identity_block_atrous(input_tensor, kernel_size, filters, stage, block, atrous_rate=(2, 2)): +def identity_block_dilation(input_tensor, kernel_size, filters, stage, block, dilation_rate=(2, 2)): nb_filter1, nb_filter2, nb_filter3 = filters bn_axis = 1 conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' - x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) + x = Conv2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) x = Activation('relu')(x) - x = AtrousConvolution2D(nb_filter2, kernel_size, kernel_size, atrous_rate=atrous_rate, - border_mode='same', name=conv_name_base + '2b')(x) + x = Conv2D(nb_filter2, kernel_size, kernel_size, dilation_rate=dilation_rate, + padding='same', name=conv_name_base + '2b')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) x = Activation('relu')(x) - x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) - x = merge([x, input_tensor], mode='sum') + x = add([x, input_tensor]) x = Activation('relu')(x) return x @@ -134,10 +134,10 @@ def dcn_resnet(input_tensor=None): # conv_1 x = ZeroPadding2D((3, 3))(img_input) - x = Convolution2D(64, 7, 7, subsample=(2, 2), name='conv1')(x) + x = Conv2D(64, (7, 7), strides=2, name='conv1')(x) x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x) x = Activation('relu')(x) - x = MaxPooling2D((3, 3), strides=(2, 2), border_mode='same')(x) + x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) # conv_2 x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1)) @@ -151,17 +151,17 @@ def dcn_resnet(input_tensor=None): x = identity_block(x, 3, [128, 128, 512], stage=3, block='d') # conv_4 - x = conv_block_atrous(x, 3, [256, 256, 1024], stage=4, block='a', atrous_rate=(2, 2)) - x = identity_block_atrous(x, 3, [256, 256, 1024], stage=4, block='b', atrous_rate=(2, 2)) - x = identity_block_atrous(x, 3, [256, 256, 1024], stage=4, block='c', atrous_rate=(2, 2)) - x = identity_block_atrous(x, 3, [256, 256, 1024], stage=4, block='d', atrous_rate=(2, 2)) - x = identity_block_atrous(x, 3, [256, 256, 1024], stage=4, block='e', atrous_rate=(2, 2)) - x = identity_block_atrous(x, 3, [256, 256, 1024], stage=4, block='f', atrous_rate=(2, 2)) + x = conv_block_dilation(x, 3, [256, 256, 1024], stage=4, block='a', dilation_rate=(2, 2)) + x = identity_block_dilation(x, 3, [256, 256, 1024], stage=4, block='b', dilation_rate=(2, 2)) + x = identity_block_dilation(x, 3, [256, 256, 1024], stage=4, block='c', dilation_rate=(2, 2)) + x = identity_block_dilation(x, 3, [256, 256, 1024], stage=4, block='d', dilation_rate=(2, 2)) + x = identity_block_dilation(x, 3, [256, 256, 1024], stage=4, block='e', dilation_rate=(2, 2)) + x = identity_block_dilation(x, 3, [256, 256, 1024], stage=4, block='f', dilation_rate=(2, 2)) # conv_5 - x = conv_block_atrous(x, 3, [512, 512, 2048], stage=5, block='a', atrous_rate=(4, 4)) - x = identity_block_atrous(x, 3, [512, 512, 2048], stage=5, block='b', atrous_rate=(4, 4)) - x = identity_block_atrous(x, 3, [512, 512, 2048], stage=5, block='c', atrous_rate=(4, 4)) + x = conv_block_dilation(x, 3, [512, 512, 2048], stage=5, block='a', dilation_rate=(4, 4)) + x = identity_block_dilation(x, 3, [512, 512, 2048], stage=5, block='b', dilation_rate=(4, 4)) + x = identity_block_dilation(x, 3, [512, 512, 2048], stage=5, block='c', dilation_rate=(4, 4)) # Create model model = Model(img_input, x) @@ -171,4 +171,4 @@ def dcn_resnet(input_tensor=None): cache_subdir='models', md5_hash='f64f049c92468c9affcd44b0976cdafe') model.load_weights(weights_path) - return model \ No newline at end of file + return model diff --git a/dcn_vgg.py b/dcn_vgg.py index 1283e96..760319e 100644 --- a/dcn_vgg.py +++ b/dcn_vgg.py @@ -1,13 +1,13 @@ ''' This code is part of the Keras VGG-16 model ''' -from __future__ import print_function -from __future__ import absolute_import + + from keras.models import Model from keras.layers import Input -from keras.layers import Convolution2D, MaxPooling2D -from keras.layers.convolutional import AtrousConvolution2D +from keras.layers import Conv2D, MaxPooling2D +from keras.layers import Conv2D from keras.utils.data_utils import get_file from keras import backend as K @@ -26,31 +26,31 @@ def dcn_vgg(input_tensor=None): img_input = input_tensor # conv_1 - x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input) - x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x) + x = Conv2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input) + x = Conv2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x) x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x) # conv_2 - x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x) - x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x) + x = Conv2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x) + x = Conv2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x) x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x) # conv_3 - x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x) - x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x) - x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x) + x = Conv2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x) + x = Conv2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x) + x = Conv2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x) x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool', border_mode='same')(x) # conv_4 - x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x) - x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x) - x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x) x = MaxPooling2D((2, 2), strides=(1, 1), name='block4_pool', border_mode='same')(x) # conv_5 - x = AtrousConvolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1', atrous_rate=(2, 2))(x) - x = AtrousConvolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2', atrous_rate=(2, 2))(x) - x = AtrousConvolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3', atrous_rate=(2, 2))(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1', dilation_rate=(2, 2))(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2', dilation_rate=(2, 2))(x) + x = Conv2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3', dilation_rate=(2, 2))(x) # Create model model = Model(img_input, x) diff --git a/gaussian_prior.py b/gaussian_prior.py index 9fcc87a..8376f77 100644 --- a/gaussian_prior.py +++ b/gaussian_prior.py @@ -1,8 +1,8 @@ -from __future__ import division + import keras.backend as K import theano.tensor as T from keras.layers import Layer, InputSpec -from keras import initializations, regularizers, constraints +from keras import initializers, regularizers, constraints import theano import numpy as np floatX = theano.config.floatX @@ -13,7 +13,7 @@ def __init__(self, nb_gaussian, init='normal', weights=None, W_regularizer=None, activity_regularizer=None, W_constraint=None, **kwargs): self.nb_gaussian = nb_gaussian - self.init = initializations.get(init, dim_ordering='th') + self.init = initializers.get(init, dim_ordering='th') self.W_regularizer = regularizers.get(W_regularizer) self.activity_regularizer = regularizers.get(activity_regularizer) @@ -110,4 +110,4 @@ def get_config(self): 'W_constraint': self.W_constraint.get_config() if self.W_constraint else None, } base_config = super(LearningPrior, self).get_config() - return dict(list(base_config.items()) + list(config.items())) \ No newline at end of file + return dict(list(base_config.items()) + list(config.items())) diff --git a/hooks/hook-numpy.py b/hooks/hook-numpy.py new file mode 100644 index 0000000..b8584de --- /dev/null +++ b/hooks/hook-numpy.py @@ -0,0 +1,3 @@ +from PyInstaller.utils.hooks import collect_all + +datas, binaries, hiddenimports = collect_all('numpy') diff --git a/hooks/hook-theano.py b/hooks/hook-theano.py new file mode 100644 index 0000000..975a1aa --- /dev/null +++ b/hooks/hook-theano.py @@ -0,0 +1,3 @@ +from PyInstaller.utils.hooks import collect_all + +datas, binaries, hiddenimports = collect_all('theano') diff --git a/main.py b/main.py index 847bfaf..5e11ed2 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,8 @@ -from __future__ import division -from keras.optimizers import RMSprop -from keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler -from keras.layers import Input -from keras.models import Model +import tensorflow as tf +from tensorflow.keras.optimizers import RMSprop +from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler +from tensorflow.keras.layers import Input +from tensorflow.keras.models import Model import os, cv2, sys import numpy as np from config import * @@ -53,6 +53,7 @@ def generator_test(b_s, imgs_test_path): raise NotImplementedError else: phase = sys.argv[1] + x = Input((3, shape_r, shape_c)) x_maps = Input((nb_gaussian, shape_r_gt, shape_c_gt)) @@ -108,7 +109,10 @@ def generator_test(b_s, imgs_test_path): print("Loading SAM-ResNet weights") m.load_weights('weights/sam-resnet_salicon2017_weights.pkl') - print("Predicting saliency maps for " + imgs_test_path) + # save model as tensorFlow file + #m.save('./models/sam-resnet_salicon2017_weights') + + print(("Predicting saliency maps for " + imgs_test_path)) predictions = m.predict_generator(generator_test(b_s=b_s, imgs_test_path=imgs_test_path), nb_imgs_test)[0] diff --git a/models.py b/models.py index 6fdf728..3b596ac 100644 --- a/models.py +++ b/models.py @@ -1,6 +1,6 @@ -from __future__ import division -from keras.layers import Lambda, merge -from keras.layers.convolutional import Convolution2D, AtrousConvolution2D + +from tensorflow.keras.layers import Lambda, concatenate +from tensorflow.keras.layers import Conv2D, Conv2D import keras.backend as K import theano.tensor as T import numpy as np @@ -108,18 +108,18 @@ def sam_vgg(x): # Learned Prior (1) priors1 = LearningPrior(nb_gaussian=nb_gaussian, init=gaussian_priors_init)(x[1]) - concateneted = merge([att_convlstm, priors1], mode='concat', concat_axis=1) - learned_priors1 = AtrousConvolution2D(512, 5, 5, border_mode='same', activation='relu', - atrous_rate=(4, 4))(concateneted) + concateneted = concatenate([att_convlstm, priors1], mode='concat', concat_axis=1) + learned_priors1 = Conv2D(512, 5, 5, border_mode='same', activation='relu', + dilation_rate=(4, 4))(concateneted) # Learned Prior (2) priors2 = LearningPrior(nb_gaussian=nb_gaussian, init=gaussian_priors_init)(x[1]) - concateneted = merge([learned_priors1, priors2], mode='concat', concat_axis=1) - learned_priors2 = AtrousConvolution2D(512, 5, 5, border_mode='same', activation='relu', - atrous_rate=(4, 4))(concateneted) + concateneted = concatenate([learned_priors1, priors2], mode='concat', concat_axis=1) + learned_priors2 = Conv2D(512, 5, 5, border_mode='same', activation='relu', + dilation_rate=(4, 4))(concateneted) # Final Convolutional Layer - outs = Convolution2D(1, 1, 1, border_mode='same', activation='relu')(learned_priors2) + outs = Conv2D(1, 1, 1, border_mode='same', activation='relu')(learned_priors2) outs_up = Lambda(upsampling, upsampling_shape)(outs) return [outs_up, outs_up, outs_up] @@ -128,7 +128,7 @@ def sam_vgg(x): def sam_resnet(x): # Dilated Convolutional Network dcn = dcn_resnet(input_tensor=x[0]) - conv_feat = Convolution2D(512, 3, 3, border_mode='same', activation='relu')(dcn.output) + conv_feat = Conv2D(512, 3, 3, border_mode='same', activation='relu')(dcn.output) # Attentive Convolutional LSTM att_convlstm = Lambda(repeat, repeat_shape)(conv_feat) @@ -137,18 +137,18 @@ def sam_resnet(x): # Learned Prior (1) priors1 = LearningPrior(nb_gaussian=nb_gaussian, init=gaussian_priors_init)(x[1]) - concateneted = merge([att_convlstm, priors1], mode='concat', concat_axis=1) - learned_priors1 = AtrousConvolution2D(512, 5, 5, border_mode='same', activation='relu', - atrous_rate=(4, 4))(concateneted) + concateneted = concatenate([att_convlstm, priors1], mode='concat', concat_axis=1) + learned_priors1 = Conv2D(512, 5, 5, border_mode='same', activation='relu', + dilation_rate=(4, 4))(concateneted) # Learned Prior (2) priors2 = LearningPrior(nb_gaussian=nb_gaussian, init=gaussian_priors_init)(x[1]) - concateneted = merge([learned_priors1, priors2], mode='concat', concat_axis=1) - learned_priors2 = AtrousConvolution2D(512, 5, 5, border_mode='same', activation='relu', - atrous_rate=(4, 4))(concateneted) + concateneted = concatenate([learned_priors1, priors2], mode='concat', concat_axis=1) + learned_priors2 = Conv2D(512, 5, 5, border_mode='same', activation='relu', + dilation_rate=(4, 4))(concateneted) # Final Convolutional Layer - outs = Convolution2D(1, 1, 1, border_mode='same', activation='relu')(learned_priors2) + outs = Conv2D(1, 1, 1, border_mode='same', activation='relu')(learned_priors2) outs_up = Lambda(upsampling, upsampling_shape)(outs) return [outs_up, outs_up, outs_up] diff --git a/pyoxidizer.bzl b/pyoxidizer.bzl new file mode 100644 index 0000000..6142ea6 --- /dev/null +++ b/pyoxidizer.bzl @@ -0,0 +1,346 @@ +# This file defines how PyOxidizer application building and packaging is +# performed. See PyOxidizer's documentation at +# https://pyoxidizer.readthedocs.io/en/stable/ for details of this +# configuration file format. + +# Configuration files consist of functions which define build "targets." +# This function creates a Python executable and installs it in a destination +# directory. +def make_exe(): + # Obtain the default PythonDistribution for our build target. We link + # this distribution into our produced executable and extract the Python + # standard library from it. + dist = default_python_distribution() + + # This function creates a `PythonPackagingPolicy` instance, which + # influences how executables are built and how resources are added to + # the executable. You can customize the default behavior by assigning + # to attributes and calling functions. + policy = dist.make_python_packaging_policy() + + # Enable support for non-classified "file" resources to be added to + # resource collections. + # policy.allow_files = True + + # Control support for loading Python extensions and other shared libraries + # from memory. This is only supported on Windows and is ignored on other + # platforms. + # policy.allow_in_memory_shared_library_loading = True + + # Control whether to generate Python bytecode at various optimization + # levels. The default optimization level used by Python is 0. + # policy.bytecode_optimize_level_zero = True + # policy.bytecode_optimize_level_one = True + # policy.bytecode_optimize_level_two = True + + # Package all available Python extensions in the distribution. + # policy.extension_module_filter = "all" + + # Package the minimum set of Python extensions in the distribution needed + # to run a Python interpreter. Various functionality from the Python + # standard library won't work with this setting! But it can be used to + # reduce the size of generated executables by omitting unused extensions. + # policy.extension_module_filter = "minimal" + + # Package Python extensions in the distribution not having additional + # library dependencies. This will exclude working support for SSL, + # compression formats, and other functionality. + # policy.extension_module_filter = "no-libraries" + + # Package Python extensions in the distribution not having a dependency on + # copyleft licensed software like GPL. + # policy.extension_module_filter = "no-copyleft" + + # Controls whether the file scanner attempts to classify files and emit + # resource-specific values. + # policy.file_scanner_classify_files = True + + # Controls whether `File` instances are emitted by the file scanner. + # policy.file_scanner_emit_files = False + + # Controls the `add_include` attribute of "classified" resources + # (`PythonModuleSource`, `PythonPackageResource`, etc). + # policy.include_classified_resources = True + + # Toggle whether Python module source code for modules in the Python + # distribution's standard library are included. + # policy.include_distribution_sources = False + + # Toggle whether Python package resource files for the Python standard + # library are included. + # policy.include_distribution_resources = False + + # Controls the `add_include` attribute of `File` resources. + # policy.include_file_resources = False + + # Controls the `add_include` attribute of `PythonModuleSource` not in + # the standard library. + # policy.include_non_distribution_sources = True + + # Toggle whether files associated with tests are included. + # policy.include_test = False + + # Resources are loaded from "in-memory" or "filesystem-relative" paths. + # The locations to attempt to add resources to are defined by the + # `resources_location` and `resources_location_fallback` attributes. + # The former is the first/primary location to try and the latter is + # an optional fallback. + + # Use in-memory location for adding resources by default. + # policy.resources_location = "in-memory" + + # Use filesystem-relative location for adding resources by default. + # policy.resources_location = "filesystem-relative:prefix" + + # Attempt to add resources relative to the built binary when + # `resources_location` fails. + # policy.resources_location_fallback = "filesystem-relative:prefix" + + # Clear out a fallback resource location. + # policy.resources_location_fallback = None + + # Define a preferred Python extension module variant in the Python distribution + # to use. + # policy.set_preferred_extension_module_variant("foo", "bar") + + # Configure policy values to classify files as typed resources. + # (This is the default.) + # policy.set_resource_handling_mode("classify") + + # Configure policy values to handle files as files and not attempt + # to classify files as specific types. + # policy.set_resource_handling_mode("files") + + # This variable defines the configuration of the embedded Python + # interpreter. By default, the interpreter will run a Python REPL + # using settings that are appropriate for an "isolated" run-time + # environment. + # + # The configuration of the embedded Python interpreter can be modified + # by setting attributes on the instance. Some of these are + # documented below. + python_config = dist.make_python_interpreter_config() + + # Make the embedded interpreter behave like a `python` process. + # python_config.config_profile = "python" + + # Set initial value for `sys.path`. If the string `$ORIGIN` exists in + # a value, it will be expanded to the directory of the built executable. + # python_config.module_search_paths = ["$ORIGIN/lib"] + + # Use jemalloc as Python's memory allocator. + # python_config.allocator_backend = "jemalloc" + + # Use mimalloc as Python's memory allocator. + # python_config.allocator_backend = "mimalloc" + + # Use snmalloc as Python's memory allocator. + # python_config.allocator_backend = "snmalloc" + + # Let Python choose which memory allocator to use. (This will likely + # use the malloc()/free() linked into the program. + # python_config.allocator_backend = "default" + + # Enable the use of a custom allocator backend with the "raw" memory domain. + # python_config.allocator_raw = True + + # Enable the use of a custom allocator backend with the "mem" memory domain. + # python_config.allocator_mem = True + + # Enable the use of a custom allocator backend with the "obj" memory domain. + # python_config.allocator_obj = True + + # Enable the use of a custom allocator backend with pymalloc's arena + # allocator. + # python_config.allocator_pymalloc_arena = True + + # Enable Python memory allocator debug hooks. + # python_config.allocator_debug = True + + # Automatically calls `multiprocessing.set_start_method()` with an + # appropriate value when OxidizedFinder imports the `multiprocessing` + # module. + # python_config.multiprocessing_start_method = 'auto' + + # Do not call `multiprocessing.set_start_method()` automatically. (This + # is the default behavior of Python applications.) + # python_config.multiprocessing_start_method = 'none' + + # Call `multiprocessing.set_start_method()` with explicit values. + # python_config.multiprocessing_start_method = 'fork' + # python_config.multiprocessing_start_method = 'forkserver' + # python_config.multiprocessing_start_method = 'spawn' + + # Control whether `oxidized_importer` is the first importer on + # `sys.meta_path`. + # python_config.oxidized_importer = False + + # Enable the standard path-based importer which attempts to load + # modules from the filesystem. + # python_config.filesystem_importer = True + + # Set `sys.frozen = False` + # python_config.sys_frozen = False + + # Set `sys.meipass` + # python_config.sys_meipass = True + + # Write files containing loaded modules to the directory specified + # by the given environment variable. + # python_config.write_modules_directory_env = "/tmp/oxidized/loaded_modules" + + # Evaluate a string as Python code when the interpreter starts. + # python_config.run_command = "" + + # Run a Python module as __main__ when the interpreter starts. + # python_config.run_module = "" + + # Run a Python file when the interpreter starts. + python_config.run_filename = "./main.py" + + # Produce a PythonExecutable from a Python distribution, embedded + # resources, and other options. The returned object represents the + # standalone executable that will be built. + exe = dist.to_python_executable( + name="main", + + # If no argument passed, the default `PythonPackagingPolicy` for the + # distribution is used. + packaging_policy=policy, + + # If no argument passed, the default `PythonInterpreterConfig` is used. + config=python_config, + ) + + # Install tcl/tk support files to a specified directory so the `tkinter` Python + # module works. + # exe.tcl_files_path = "lib" + + # Never attempt to copy Windows runtime DLLs next to the built executable. + # exe.windows_runtime_dlls_mode = "never" + + # Copy Windows runtime DLLs next to the built executable when they can be + # located. + # exe.windows_runtime_dlls_mode = "when-present" + + # Copy Windows runtime DLLs next to the build executable and error if this + # cannot be done. + # exe.windows_runtime_dlls_mode = "always" + + # Make the executable a console application on Windows. + exe.windows_subsystem = "console" + + # Make the executable a non-console application on Windows. + # exe.windows_subsystem = "windows" + + # Invoke `pip download` to install a single package using wheel archives + # obtained via `pip download`. `pip_download()` returns objects representing + # collected files inside Python wheels. `add_python_resources()` adds these + # objects to the binary, with a load location as defined by the packaging + # policy's resource location attributes. + #exe.add_python_resources(exe.pip_download(["pyflakes==2.2.0"])) + + # Invoke `pip install` with our Python distribution to install a single package. + # `pip_install()` returns objects representing installed files. + # `add_python_resources()` adds these objects to the binary, with a load + # location as defined by the packaging policy's resource location + # attributes. + #exe.add_python_resources(exe.pip_install(["appdirs"])) + + # Invoke `pip install` using a requirements file and add the collected resources + # to our binary. + exe.add_python_resources(exe.pip_install(["-r", "requirements.txt"])) + + + # Read Python files from a local directory and add them to our embedded + # context, taking just the resources belonging to the `foo` and `bar` + # Python packages. + #exe.add_python_resources(exe.read_package_root( + # path="/src/mypackage", + # packages=["foo", "bar"], + #)) + + # Discover Python files from a virtualenv and add them to our embedded + # context. + exe.add_python_resources(exe.read_virtualenv(path="./env")) + + # Filter all resources collected so far through a filter of names + # in a file. + #exe.filter_from_files(files=["/path/to/filter-file"])) + + # Return our `PythonExecutable` instance so it can be built and + # referenced by other consumers of this target. + return exe + +def make_embedded_resources(exe): + return exe.to_embedded_resources() + +def make_install(exe): + # Create an object that represents our installed application file layout. + files = FileManifest() + + # Add the generated executable to our install layout in the root directory. + files.add_python_resource(".", exe) + + return files + +def make_msi(exe): + # See the full docs for more. But this will convert your Python executable + # into a `WiXMSIBuilder` Starlark type, which will be converted to a Windows + # .msi installer when it is built. + return exe.to_wix_msi_builder( + # Simple identifier of your app. + "myapp", + # The name of your application. + "My Application", + # The version of your application. + "1.0", + # The author/manufacturer of your application. + "Alice Jones" + ) + + +# Dynamically enable automatic code signing. +def register_code_signers(): + # You will need to run with `pyoxidizer build --var ENABLE_CODE_SIGNING 1` for + # this if block to be evaluated. + if not VARS.get("ENABLE_CODE_SIGNING"): + return + + # Use a code signing certificate in a .pfx/.p12 file, prompting the + # user for its path and password to open. + # pfx_path = prompt_input("path to code signing certificate file") + # pfx_password = prompt_password( + # "password for code signing certificate file", + # confirm = True + # ) + # signer = code_signer_from_pfx_file(pfx_path, pfx_password) + + # Use a code signing certificate in the Windows certificate store, specified + # by its SHA-1 thumbprint. (This allows you to use YubiKeys and other + # hardware tokens if they speak to the Windows certificate APIs.) + # sha1_thumbprint = prompt_input( + # "SHA-1 thumbprint of code signing certificate in Windows store" + # ) + # signer = code_signer_from_windows_store_sha1_thumbprint(sha1_thumbprint) + + # Choose a code signing certificate automatically from the Windows + # certificate store. + # signer = code_signer_from_windows_store_auto() + + # Activate your signer so it gets called automatically. + # signer.activate() + + +# Call our function to set up automatic code signers. +register_code_signers() + +# Tell PyOxidizer about the build targets defined above. +register_target("exe", make_exe) +register_target("resources", make_embedded_resources, depends=["exe"], default_build_script=True) +register_target("install", make_install, depends=["exe"], default=True) +register_target("msi_installer", make_msi, depends=["exe"]) + +# Resolve whatever targets the invoker of this configuration file is requesting +# be resolved. +resolve_targets() diff --git a/requirements.txt b/requirements.txt index 09c1b2b..487cf38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,44 @@ +absl-py==1.0.0 +astunparse==1.6.3 +cachetools==5.0.0 +certifi==2021.10.8 +charset-normalizer==2.0.12 +flatbuffers==2.0 +gast==0.5.3 +google-auth==2.6.0 +google-auth-oauthlib==0.4.6 +google-pasta==0.2.0 +grpcio==1.44.0 h5py==2.10.0 -Keras==1.1.0 -numpy==1.16.6 -opencv-python==4.2.0.32 -PyYAML==5.4.1 -scipy==1.2.3 +idna==3.3 +importlib-metadata==4.11.1 +keras==2.8.0 +Keras-Preprocessing==1.1.2 +libclang==13.0.0 +Markdown==3.3.6 +numpy==1.20.3 +oauthlib==3.2.0 +opencv-python==4.5.5.62 +opt-einsum==3.3.0 +protobuf==3.19.4 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +PyYAML==6.0 +requests==2.27.1 +requests-oauthlib==1.3.1 +rsa==4.8 +scipy==1.8.0 six==1.16.0 +tensorboard==2.8.0 +tensorboard-data-server==0.6.1 +tensorboard-plugin-wit==1.8.1 +tensorflow==2.8.0 +tensorflow-io-gcs-filesystem==0.24.0 +termcolor==1.1.0 +tf-estimator-nightly==2.8.0.dev2021122109 Theano==1.0.5 +typing-extensions==4.1.1 +urllib3==1.26.8 +Werkzeug==2.0.3 +wrapt==1.13.3 +zipp==3.7.0 diff --git a/utilities.py b/utilities.py index a295785..147d061 100644 --- a/utilities.py +++ b/utilities.py @@ -1,4 +1,4 @@ -from __future__ import division + import cv2 import numpy as np import scipy.io @@ -128,4 +128,4 @@ def postprocess_predictions(pred, shape_r, shape_c): img = scipy.ndimage.filters.gaussian_filter(img, sigma=7) img = img / np.max(img) * 255 - return img \ No newline at end of file + return img