Commit 046521e8 authored by Marius Laska's avatar Marius Laska

cross entropy loss for grid cell classification + scalable dnn reference model of paper

parent 65154d88
......@@ -13,7 +13,7 @@ from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from tensorflow.keras.optimizers import Adam, Adamax
from base.bbox_model_definition import bbox_model_for_generator, \
cnn_deep_loc_box, ae_model, cnn_bbox_model_for_generator
cnn_deep_loc_box, ae_model, cnn_bbox_model_for_generator, scalabel_bbox_model, scalable_ae_model
from base.hier_model_definition import hier_model_for_generator
from base.custom_loss import bbox_loss, define_bbox_loss, define_circle_loss, \
define_quantile_loss, \
......@@ -72,9 +72,8 @@ class BboxModel(DnnModel):
params.update({'last_activation': sigmoid,
'losses': loss_func})
elif self.type == "GRID_OVERLAP-BBOX":
elif self.type == "GRID_OVERLAP-BBOX" or self.type == "GRID_OVERLAP-BBOX_SCALABLE-DNN":
if 'loss' in params:
#loss_func = define_yolo_loss_tanh(params['loss'])
loss_func = define_yolo_loss_tanh_no_size(params['loss'])
params.update({'last_activation': tanh,
......@@ -154,7 +153,10 @@ class BboxModel(DnnModel):
def train_autoencoder(self):
x_cols, _ = self.data_provider.get_data_dims("regression")
self.classifier, bottleneck_model = ae_model(x_cols, self.params)
if self.type == "GRID_OVERLAP-BBOX_SCALABLE-DNN":
self.classifier, bottleneck_model = scalable_ae_model(x_cols, self.params)
else:
self.classifier, bottleneck_model = ae_model(x_cols, self.params)
self._train_model(save_weights_only=False, evaluate=False, autoencoder=True)
bottleneck_model.save(self.output_dir + "AE_bottleneck_{}_f{}.hdf5".format(
self.filename, self.data_provider.current_split_idx), include_optimizer=False)
......@@ -209,7 +211,10 @@ class BboxModel(DnnModel):
dp.floorplan_height / dp.grid_size) * math.ceil(
dp.floorplan_width / dp.grid_size)
if self.type == "GRID_OVERLAP-BBOX" or self.type == "GRID_OVERLAP-BBOX_CNN" or self.type == "GRID_OVERLAP-BBOX_2D-CNN":
if self.type == "GRID_OVERLAP-BBOX" \
or self.type == "GRID_OVERLAP-BBOX_CNN" \
or self.type == "GRID_OVERLAP-BBOX_2D-CNN" \
or self.type == "GRID_OVERLAP-BBOX_SCALABLE-DNN":
num_gs = dp.get_num_grid_cells()
if num_gs is None:
y_cols = 5 * (math.ceil(
......@@ -243,6 +248,11 @@ class BboxModel(DnnModel):
self.filename, self.data_provider.current_split_idx)
self.classifier = cnn_deep_loc_box(ae_file, y_cols, params)
elif self.type == "GRID_OVERLAP-BBOX_SCALABLE-DNN":
ae_file = self.output_dir + "AE_bottleneck_{}_f{}.hdf5".format(
self.filename, self.data_provider.current_split_idx)
self.classifier = scalabel_bbox_model(x_cols, y_cols, ae_file, params)
elif self.type == "GRID_OVERLAP-BBOX_2D-CNN":
x_cols, _ = dp.get_data_dims("CNN")
classifier_template = cnn_bbox_model_for_generator()
......@@ -341,7 +351,7 @@ class BboxModel(DnnModel):
steps_per_epoch=train_steps_per_epoch,
epochs=params['epochs'],
callbacks=[earlyStopping, checkpoint],
verbose=0)
verbose=2)
# evaluate model and store results in summary file
if evaluate:
......
......@@ -118,6 +118,74 @@ def bbox_model_for_generator(metrics):
return define_classification_model_for_generator
def scalabel_bbox_model(X_cols, Y_cols, ae_base_model_file, params):
ae_model = load_model(ae_base_model_file) #, compile=False)
for layer in ae_model.layers:
layer.trainable = True
model = Sequential()
model.add(ae_model)
model.add(Dense(64, input_dim=X_cols,
activation="relu",
kernel_regularizer=regularizers.l2(
params['regularization_penalty'])
))
seed_val = None
if 'seed' in params:
seed_val = params['seed']
model.add(Dropout(params['dropout'], training=None, seed=seed_val))
model.add(Dense(128,
activation="relu",
kernel_regularizer=regularizers.l2(
params['regularization_penalty'])
))
#
model.add(Dense(Y_cols, activation=params['last_activation'],
# kernel_initializer=params['kernel_initializer'],
kernel_regularizer=regularizers.l2(
params['regularization_penalty']))) # ,
# compile the model
model.compile(loss=params['losses'],
optimizer=params['optimizer'](
lr=lr_normalizer(params['lr'], params['optimizer'])))
return model
def scalable_ae_model(X_cols, params):
input = Input((X_cols,))
encode_layer = Dense(256, activation=params['activation'], name='en1')(
input)
encode_layer = Dense(128, activation=params['activation'], name='en2')(
encode_layer)
decode_layer = Dense(256, activation=params['activation'], name='de2')(
encode_layer)
decode_layer = Dense(X_cols, activation=params['activation'], name='de-1')(
decode_layer)
encoder_model_256_128 = Model(inputs=input, outputs=decode_layer)
bottleneck_model_256_128 = Model(inputs=input,
outputs=encode_layer)
encoder_model = encoder_model_256_128
bottleneck_model = bottleneck_model_256_128
encoder_model.compile(
loss=MSE,
optimizer=params['optimizer'](
lr=lr_normalizer(params['lr'], params['optimizer'])) # lr=0.005)
)
return encoder_model, bottleneck_model
def ae_model(X_cols, params):
input = Input((X_cols,))
encode_layer = Dense(128, activation=params['activation'], name='en1')(input)
......
......@@ -856,6 +856,7 @@ def define_yolo_loss_tanh(params):
return yolo_loss
def define_yolo_loss_tanh_no_size(params):
def yolo_loss(y_true, y_pred):
......@@ -870,7 +871,9 @@ def define_yolo_loss_tanh_no_size(params):
# grid cell true
grid_cell_true = tf.one_hot(tf.cast(y_true[:, 2], dtype=tf.int32), depth=tf.shape(grid_cell_pred)[1])
class_loss = tf.reduce_sum(tf.squared_difference(grid_cell_pred, grid_cell_true), axis=1)
# class_loss = tf.reduce_sum(tf.squared_difference(grid_cell_pred, grid_cell_true), axis=1)
class_loss = tf.losses.softmax_cross_entropy(grid_cell_true, logits=grid_cell_pred)
if "scale" in params["grid"]:
factor = params["grid"]["scale"]
......@@ -965,7 +968,7 @@ def define_yolo_loss_tanh_no_size(params):
box_loss += outside_loss
loss += box_loss * box_loss_scale
loss += box_loss # * box_loss_scale
return loss
......
......@@ -135,8 +135,8 @@ class UJIndoorLocProviderFullGrid(UJIndoorLocProviderGrid):
decoded_preds[dp_idx, 4:] = np.array(key)
decoded_true[dp_idx, :2] = y_true_labels[dp_idx, :2]
print("Enc->DEC: {}".format(
np.array_equal(y_true_labels[dp_idx, :], decoded_labels[:, :2])))
# print("Enc->DEC: {}".format(
# np.array_equal(y_true_labels[dp_idx, :], decoded_labels[:, :2])))
return decoded_preds, decoded_true
......
data:
# The data provider which should be used
provider: UJIndoorLocFullProvider
# File name of floor plan img
floor_plan_img: <test>.jpg
# (train, val, test) test=0.2 => 5 fold # The number of temporal epochs into which the dataset is split
split_ratio: [0.7, 0.1, 0.2]
#
# are used when not locally set for pipeline
#
global_params:
# number of experiment repetitions
repetitions: 10
preprocessing:
# Whether to standardize the RSS values
standardize: True
# Whether to assign labels with no matching area to closet area
assign_closest: False
# The floor number of the Lohan dataset, which should be used
#floor: 0
# The epoch number of the split dataset
#num_epochs: 10
#epoch: 5
# How to check for area matches of labels (to label positions with matching areas)
area_assignment: convex_hull
grid_size: 40
floor_plan:
# 'segmentation' => computes floor plan segmentation,
# 'regression' => uses DBSCAN to partitions labels into train, test split
type: floor_classification
model_params:
type: GRID_OVERLAP-BBOX_CNN # (DNN, CNN, kNN, SVM) supported (require different parameters)
lr: 0.7
batch_size: 32
epochs: 200
dropout: 0.5
regularization_penalty: 0.0
pipelines:
- name: DNN-DLB
model_params:
type: GRID_OVERLAP-BBOX # (DNN, CNN, kNN, SVM) supported (require different parameters)
first_neuron: 512
hidden_layers: 1
augmentation: 0
#autoencoder: load
dropout: 0.5
loss:
grid:
scale: 20.0
outside:
scale: 1.0
delta: 7.5
- name: SCALABLE-DNN-DLB
model_params:
type: GRID_OVERLAP-BBOX_SCALABLE-DNN # (DNN, CNN, kNN, SVM) supported (require different parameters)
augmentation: 0
autoencoder: train
dropout: 0.2
loss:
grid:
scale: 20.0
outside:
scale: 1.0
delta: 7.5
# base directories for file storage
output:
model_dir: evaluation/uji/gpu/full_grid/scalable_dnn/output/
summary_dir: evaluation/uji/gpu/full_grid/scalable_dnn/summary/
img_folder: evaluation/uji/ # folder where floorplan images is located (if not present, will be downloaded)
......@@ -12,6 +12,7 @@ from base.ujiindoorloc_fullgrid_provider import test_encoding_decoding
log = getLogger(level=logging.INFO)
from base.bbox_pipeline import BboxPipeline
import numpy as np
import pandas as pd
from numpy.random import seed
from tensorflow import set_random_seed
......@@ -258,5 +259,77 @@ def calc_acc(y_true, y_pred):
print("ACC: {}".format(num_correct/len(y_true)))
def calc_vals(file, num_rep=1):
bld_acc_sum = 0
floor_acc_sum = 0
pos_error_sum = 0
for idx in range(num_rep):
p: BboxPipeline = Storable.load(file.format(idx + 1))
p.data_provider.decode_pipe_grid_labels(p)
y_pred = np.concatenate(p.summary.y_pred, axis=0)
y_true = np.concatenate(p.summary.y_true, axis=0)
# avg size
size = np.mean(np.prod(y_pred[:, 2:], axis=1))
acc_box, wrong_mask, correct_mask = calc_acc_c(y_true, y_pred)
bld_pred = y_pred[:, 4]
bld_true = y_true[:, 2]
bld_acc = np.where(bld_pred == bld_true)[0]
floor_pred = y_pred[:, 5]
floor_true = y_true[:, 3]
floor_acc = np.where(floor_pred == floor_true)[0]
pos_error = np.mean(np.linalg.norm(y_pred[:, :2] - y_true[:, :2], axis=1))
# pos error correct
mask = np.where(np.logical_and(bld_pred == bld_true, floor_pred == floor_true))[0]
pos_error_correct = np.mean(np.linalg.norm(y_pred[mask, :2] - y_true[mask, :2], axis=1))
bld_acc_sum += len(bld_acc) / len(bld_true)
floor_acc_sum += len(floor_acc) / len(floor_true)
pos_error_sum += pos_error
# print("bld_acc: {}".format(len(bld_acc)/len(bld_true)))
# print("floor_acc: {}".format(len(floor_acc) / len(floor_true)))
#
# print("MSE: {}".format(pos_error))
# print("MSE (only correct): {}".format(pos_error_correct))
# print("--------------")
return bld_acc_sum / num_rep, floor_acc_sum / num_rep, pos_error_sum / num_rep
def main_uji():
pd_dict = {"HL": [], "HU": [], "Dropout": [], "bld": [], "floor": [], "mse": []}
folder = "evaluation/uji/gpu/full_grid/hyper/output/"
file_name = "DNN-DLB_first_neuron_{}_hidden_layers_{}_dropout_{}"
for hl in [1,2,3]:
for hu in [128]:
for dropout in [0.0, 0.1,0.2,0.3,0.4,0.5,0.6,0.7]:
bld_acc, fl_acc, mse = calc_vals(folder + file_name.format(hl, hu, dropout) + "_{}", num_rep=5)
pd_dict["HL"].append(hl)
pd_dict["HU"].append(hu)
pd_dict["Dropout"].append(dropout)
pd_dict["bld"].append(bld_acc)
pd_dict["floor"].append(fl_acc)
pd_dict["mse"].append(mse)
df = pd.DataFrame(pd_dict)
print(df)
if __name__ == "__main__":
main()
\ No newline at end of file
#main_uji()
main()
#file_name = "/home/laskama/PycharmProjects/bboxPrediction/evaluation/uji/gpu/full_grid/scalable_dnn/output/BASE-DNN-DLB"
#bld_acc, fl_acc, mse = calc_vals(file_name + "_{}", num_rep=1)
# print([bld_acc, fl_acc, mse])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment