SandSnapModelDemo / app_files /src /sedinet_models.py
dbuscombe's picture
v1
d86998c
# Written by Dr Daniel Buscombe, Marda Science LLC
# for the SandSnap Program
#
# MIT License
#
# Copyright (c) 2020-2021, Marda Science LLC
#
# 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 Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
##> Release v1.4 (Aug 2021)
###===================================================
# import libraries
from sedinet_utils import *
###===================================================
def conv_block2(inp, filters=32, bn=True, pool=True, drop=True):
"""
This function generates a SediNet convolutional block
"""
# _ = Conv2D(filters=filters, kernel_size=3, activation='relu',
# kernel_initializer='he_uniform')(inp)
#relu creating dead neurons?
_ = SeparableConv2D(filters=filters, kernel_size=3, activation='relu')(inp) #'relu' #kernel_initializer='he_uniform'
if bn:
_ = BatchNormalization()(_)
if pool:
_ = MaxPool2D()(_)
if drop:
_ = Dropout(0.2)(_)
return _
###===================================================
def make_cat_sedinet(ID_MAP, dropout):
"""
This function creates an implementation of SediNet for estimating
sediment category
"""
base = BASE_CAT ##30
input_layer = Input(shape=(IM_HEIGHT, IM_WIDTH, 3))
_ = conv_block2(input_layer, filters=base, bn=False, pool=False, drop=False) #x #
_ = conv_block2(_, filters=base*2, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*3, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*4, bn=False, pool=True,drop=False)
bottleneck = GlobalMaxPool2D()(_)
bottleneck = Dropout(dropout)(bottleneck)
# for class prediction
_ = Dense(units=CAT_DENSE_UNITS, activation='relu')(bottleneck) ##128
output = Dense(units=len(ID_MAP), activation='softmax', name='output')(_)
model = Model(inputs=input_layer, outputs=[output])
OPT = tf.keras.optimizers.Adam(learning_rate=MAX_LR)
if CAT_LOSS == 'focal':
model.compile(optimizer=OPT,
loss={'output': tfa.losses.SigmoidFocalCrossEntropy() },
metrics={'output': 'accuracy'})
else:
model.compile(optimizer=OPT, #'adam',
loss={'output': CAT_LOSS}, #'categorical_crossentropy'
metrics={'output': 'accuracy'})
print("==========================================")
print('[INFORMATION] Model summary:')
model.summary()
return model
###===================================================
def make_sedinet_siso_simo(vars, greyscale, dropout):
"""
This function creates an implementation of SediNet for estimating
sediment metric on a continuous scale
"""
base = BASE_CONT ##30 ## suggested range = 20 -- 40
if greyscale==True:
input_layer = Input(shape=(IM_HEIGHT, IM_WIDTH, 1))
else:
input_layer = Input(shape=(IM_HEIGHT, IM_WIDTH, 3))
_ = conv_block2(input_layer, filters=base, bn=False, pool=False, drop=False) #x #
_ = conv_block2(_, filters=base*2, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*3, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*4, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*5, bn=False, pool=True,drop=False)
if not SHALLOW:
_ = conv_block2(_, filters=base*6, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*7, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*8, bn=False, pool=True,drop=False)
_ = conv_block2(_, filters=base*9, bn=False, pool=True,drop=False)
_ = BatchNormalization(axis=-1)(_)
bottleneck = GlobalMaxPool2D()(_)
bottleneck = Dropout(dropout)(bottleneck)
units = CONT_DENSE_UNITS ## suggested range 512 -- 1024
_ = Dense(units=units, activation='relu')(bottleneck) #'relu'
##would it be better to predict the full vector directly instread of one by one?
outputs = []
for var in vars:
outputs.append(Dense(units=1, activation='linear', name=var+'_output')(_) ) #relu
if CONT_LOSS == 'pinball':
loss = dict(zip([k+"_output" for k in vars], [tfa.losses.PinballLoss(tau=.5) for k in vars]))
else: ## 'mse'
loss = dict(zip([k+"_output" for k in vars], ['mse' for k in vars])) #loss = tf.keras.losses.MeanSquaredError(reduction=tf.keras.losses.Reduction.NONE) # Sum of squared error
metrics = dict(zip([k+"_output" for k in vars], ['mae' for k in vars]))
OPT = tf.keras.optimizers.Adam(learning_rate=MAX_LR)
model = Model(inputs=input_layer, outputs=outputs)
model.compile(optimizer=OPT,loss=loss, metrics=metrics)
#print("==========================================")
#print('[INFORMATION] Model summary:')
#model.summary()
return model