def evaluation(self, loader: Loader, epochs: int, imshow=False): # for debugging purposes val_accuracy = [] loss = [] for i, (image_batch, seg_batch) in enumerate(loader.get_minibatch(train=False, Aug=False)): pred = self.call(image_batch.astype(np.float32), training=False) loss.append(self.loss(seg=seg_batch.astype(np.float32), predictions=pred)) val_accuracy.append(Jaccard_Index(output_batch=pred, gt_batch=seg_batch, visual=imshow)) if i == epochs: return np.mean(val_accuracy), np.mean(loss)
def evaluation_with_assaf(self, loader: Loader, epochs:int, imshow=True): # for debugging purposes seg_measure = SegMeasure() val_accuracy = [] loss = [] for i, (image_batch, seg_batch) in enumerate(loader.get_minibatch(train=False)): pred = self.call(image_batch.astype(np.float32), training=False) loss.append(self.loss(seg=seg_batch.astype(np.float32), predictions=pred)) val_accuracy.append(seg_measure(seg_batch, pred).numpy()) if i == epochs: return np.mean(val_accuracy), np.mean(loss)
def _train_on_batch(self, image_batch, seg_batch, visual): sub_image = crop(image_batch=image_batch) # crop function is used to divide the image to tiles sub_seg = crop(image_batch=seg_batch) train_acc = [] train_lost = [] for i in range(self.divide_by): # height for j in range(self.divide_by): # width train_acc_val, train_loss_val = super(TilesUnet, self).\ _train_on_batch(image_batch=sub_image[:, j + 2 * i, :, :], seg_batch=sub_seg[:, j + 2 * i, :, :], visual=visual) train_acc.append(train_acc_val) train_lost.append(train_loss_val) return np.mean(train_acc), np.mean(train_lost)
def validation(self, loader: Loader): """ validation function that computes the Jaccard Index accuracy on the val data set :param loader: generator of data :return: mean of accuracy and loss """ seg_measure = SegMeasure() val_accuracy = [] loss = [] for i, (image_batch, seg_batch) in enumerate(loader.get_minibatch(train=False, Aug=config.Augment)): pred = self.call(image_batch.astype(np.float32), training=False) loss.append(self.loss(seg=seg_batch.astype(np.float32), predictions=pred)) if config.use_assaf: val_accuracy.append(seg_measure(gt=seg_batch, net_output=pred)) else: val_accuracy.append(Jaccard_Index(output_batch=pred, gt_batch=seg_batch)) if i == config.validation_steps: return np.mean(val_accuracy), np.mean(loss)
def _train_on_batch(self, image_batch, seg_batch, visual): mirror = False if random.random() < config.mirror_threshold: # we randomly insert mirrored cropped images to the dataset mirrored_and_cropped_images, mirrored_and_cropped_seg = mirror_image(image_batch=image_batch, seg_batch=seg_batch, divide_by=self.divide_by) mirror = True train_acc = [] train_lost = [] for i in range(self.divide_by): # height for j in range(self.divide_by): # width if mirror: train_acc_val, train_loss_val = super(TilesUnetMirrored, self). \ _train_on_batch(image_batch=mirrored_and_cropped_images[:, j + 2 * i, :, :], seg_batch=mirrored_and_cropped_seg[:, j + 2 * i, :, :], visual=visual) else: train_acc_val, train_loss_val = super(TilesUnetMirrored, self). \ _train_on_batch(image_batch=image_batch.astype(np.float32), seg_batch=seg_batch.astype(np.float32), visual=visual) train_acc.append(train_acc_val) train_lost.append(train_loss_val) return np.mean(train_acc), np.mean(train_lost)
def fit(self, logger, loader: Loader, callbacks, epochs:int, steps_per_epoch: int, val_freq=2, val_steps=4): """ training loop that trains the model and controls the augmentation, learning rate and the mirroring capability. the training loops stops on two conditions: A. the val accuracy converges over N consecutive trials B. ran for "epochs" number of epochs :param logger: logger to log information :param loader: generator of data :param callbacks: a dict of tensorboard callbacks and checkpoint callbacks :param epochs: number of epochs to run :param steps_per_epoch: number of iterations per epoch :param val_freq: frequency of epochs to preform validation :param val_steps: number of steps to preform in validation """ Tensorcallback = callbacks['tensorboard'] Checkpoint = callbacks['checkpoint'] info("----- Start Train -----", logger) best_val_acc = 0 consecutive_trials_val_acc_unchanged = 0 for epoch in range(epochs): if config.Augment: if best_val_acc > 0.7: # a threshold for Curriculum learning config.elastic_threshold = min(0.5, 1 * epoch / epochs) # for the use of elastic threshold if best_val_acc > 0.65: config.mirror_threshold = min(0.5, 1 * epoch / epochs) # for the use of mirroring elif epoch <= 1: # insert randomly augmented images config.mirror_threshold = 0.5 # for the use of mirroring config.elastic_threshold = 0.5 # for the use of elastic threshold train_accuracy = [] train_loss = [] self.optimizer.learning_rate = config.learning_rate_scheduler(epoch) # learning rate scheduler for iteration, (image_batch, seg_batch) in enumerate(loader.get_minibatch(Aug=config.Augment)): acc_val, loss_val = self._train_on_batch(image_batch=image_batch, seg_batch=seg_batch, visual=epoch % 5 == 0 and config.visual) train_accuracy.append(acc_val) train_loss.append(loss_val) if iteration == steps_per_epoch: break train_loss_mean = np.mean(train_loss) train_accuracy_mean = np.mean(train_accuracy) if epoch % val_freq == 0: # output validation accuracy val_accuracy, val_loss = self.validation(loader=loader) info("--- Epoch {}/{}: train accuracy" " {}, val accuracy {} and loss {} with learning rate {}--- " .format(epoch, epochs, train_accuracy_mean, val_accuracy, train_loss_mean, self.optimizer.learning_rate.numpy()), logger) logs = {'acc': train_accuracy_mean, 'loss': train_loss_mean, 'val_acc': val_accuracy, 'val_loss': val_loss} Tensorcallback.on_epoch_end(epoch=epoch, logs=logs) Checkpoint.on_epoch_end(epoch=epoch, logs=logs) if best_val_acc < val_accuracy: best_val_acc = val_accuracy consecutive_trials_val_acc_unchanged = 0 info("-- Epoch {}/{} : best val so far is {} ---".format(epoch, epochs, best_val_acc), logger) else: consecutive_trials_val_acc_unchanged += 1 if consecutive_trials_val_acc_unchanged >= config.converged_threshold: # check if val converged info("--- Epoch {}/{} : val acc converged for {} consecutive trials, terminating training... ---" .format(epoch, epochs, config.converged_threshold), logger) break Tensorcallback.on_train_end('_')