-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Major and Minor updates to GDL #206
Changes from 38 commits
ac80352
31f4a64
052a985
63cd6a0
069e030
4a10cc3
9e87901
7409695
fa7c1d7
fb58e3c
55f83f0
200d48f
a8a095a
e77f8a1
0a25fbc
81ed707
9b4368b
c1233a4
4fae864
3f4d3fb
8a38726
d7e8d35
e060066
ec21084
1db54e6
f7c06f0
c1d21b4
fc4ab9f
469000e
33bca73
d40bc0f
30f43b8
8cd4407
59443ec
2e8758d
c69b616
636e084
4d39157
427fcaf
563191f
7fa444d
9fde1b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
FROM continuumio/miniconda3 | ||
|
||
WORKDIR /app | ||
|
||
# Create the environment: | ||
COPY environment.yml . | ||
RUN conda env create -f environment.yml | ||
|
||
# Make RUN commands use the new environment: | ||
SHELL ["conda", "run", "-n", "geo_deep_env", "/bin/bash", "-c"] | ||
|
||
# Make sure the environment is activated: | ||
RUN echo "Make sure flask is installed:" | ||
RUN python -c "import flask" | ||
|
||
# The code to run when container is started: | ||
#COPY run.py . | ||
ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "geo_deep_env", "python"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
version: '3' | ||
services: | ||
geo-deep-learning: | ||
build: . | ||
environment: | ||
- PYTHONPATH=. | ||
volumes: | ||
- .:/app | ||
entrypoint: python | ||
command: --version |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
import pickle | ||
from functools import partial | ||
import pprint | ||
import numpy as np | ||
|
||
import mlflow | ||
import torch | ||
|
@@ -21,12 +22,10 @@ | |
from train_segmentation import main as train_main | ||
|
||
# This is the hyperparameter space to explore | ||
my_space = {'target_size': hp.choice('target_size', [128, 256]), | ||
'model_name': hp.choice('model_name', ['unet', 'deeplabv3+_pretrained']), | ||
'permanent_water_weight': hp.uniform('permanent_water_weight', 1.0, 10.0), | ||
'rivers_weight': hp.uniform('rivers_weight', 1.0, 10.0), | ||
'flood_weight': hp.uniform('flood_weight', 1.0, 10.0), | ||
'noise': hp.choice('noise', [0.0, 1.0])} | ||
my_space = {'model_name': hp.choice('model_name', ['unet_pretrained', 'deeplabv3_resnet101']), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment that the HPC one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be tackled in a future PR |
||
'loss_fn': hp.choice('loss_fn', ['CrossEntropy', 'Lovasz', 'Duo']), | ||
'optimizer': hp.choice('optimizer', ['adam', 'adabound']), | ||
'learning_rate': hp.loguniform('learning_rate', np.log(1e-7), np.log(0.1))} | ||
|
||
|
||
def get_latest_mlrun(params): | ||
|
@@ -62,20 +61,23 @@ def objective_with_args(hparams, params, config_path): | |
""" | ||
|
||
# ToDo: This is dependent on the specific structure of the GDL config file | ||
params['training']['target_size'] = hparams['target_size'] | ||
params['global']['model_name'] = hparams['model_name'] | ||
# ToDo: Should adjust batch size as a function of model and target size... | ||
params['training']['class_weights'] = [1.0, hparams['permanent_water_weight'], hparams['rivers_weight'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A (hyperopt) template should not have parameters clearly linked to a specific application, e.g. floods like in this case. "specific structure of the GDL config file" indeed ... We may need a structure of YAML files as a function of application that a template could make use of. |
||
hparams['flood_weight']] | ||
params['training']['augmentation']['noise'] = hparams['noise'] | ||
# params['training']['target_size'] = hparams['target_size'] | ||
params['training']['loss_fn '] = hparams['loss_fn'] | ||
params['training']['optimizer'] = hparams['optimizer'] | ||
params['training']['learning_rate'] = hparams['learning_rate'] | ||
|
||
try: | ||
mlrun = get_latest_mlrun(params) | ||
run_name_split = mlrun.data.tags['mlflow.runName'].split('_') | ||
params['global']['mlflow_run_name'] = run_name_split[0] + f'_{int(run_name_split[1])+1}' | ||
params['global']['mlflow_run_name'] = run_name_split[0] + f'_{int(run_name_split[1]) + 1}' | ||
except: | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why try/except statement here? If necessary, maybe it should be narrowed down to catch only known errors. Not a priority. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be worked on, previous work from an intern |
||
|
||
if params['global']['model_name'] == "unet_pretrained": | ||
params['training']['state_dict_path'] = params['training']['dict_unet'] | ||
elif params['global']['model_name'] == "deeplabv3_resnet101": | ||
params['training']['state_dict_path'] = params['training']['dict_deeplab'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the dict_[model] parameter comes from where? Is it an output of a previous run? Maybe a comment or two would help here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be taken off, it is unique to my special use case of hyperopt. |
||
train_main(params, config_path) | ||
torch.cuda.empty_cache() | ||
|
||
|
@@ -88,7 +90,7 @@ def objective_with_args(hparams, params, config_path): | |
return {'loss': -mlrun.data.metrics['tst_iou'], 'status': STATUS_OK} | ||
|
||
|
||
def trials_to_csv(trials): | ||
def trials_to_csv(trials, csv_pth): | ||
"""hyperopt trials to CSV | ||
|
||
:param trials: hyperopt trials object | ||
|
@@ -109,14 +111,18 @@ def trials_to_csv(trials): | |
csv_str = csv_str + f'{trials.results[i]["loss"]}' + '\n' | ||
|
||
# ToDo: Customize where the csv output is | ||
with open('hyperopt_results.csv', 'w') as csv_obj: | ||
with open(csv_pth, 'w') as csv_obj: | ||
csv_obj.write(csv_str) | ||
|
||
|
||
def main(params, config_path): | ||
# ToDo: Customize where the trials file is | ||
if Path('hyperopt_trials.pkl').is_file(): | ||
trials = pickle.load(open("hyperopt_trials.pkl", "rb")) | ||
# ToDo: Customize where the trials file is | ||
root_path = Path(params['global']['assets_path']) | ||
pkl_file = root_path.joinpath('hyperopt_trials.pkl') | ||
csv_file = root_path.joinpath('hyperopt_results.csv') | ||
if pkl_file.is_file(): | ||
trials = pickle.load(open(pkl_file, "rb")) | ||
else: | ||
trials = Trials() | ||
|
||
|
@@ -128,19 +134,19 @@ def main(params, config_path): | |
space=my_space, | ||
algo=tpe.suggest, | ||
trials=trials, | ||
max_evals=n+params['global']['hyperopt_delta']) | ||
max_evals=n + params['global']['hyperopt_delta']) | ||
n += params['global']['hyperopt_delta'] | ||
pickle.dump(trials, open("hyperopt_trials.pkl", "wb")) | ||
pickle.dump(trials, open(pkl_file, "wb")) | ||
|
||
# ToDo: Cleanup the output | ||
pprint.pprint(trials.vals) | ||
pprint.pprint(trials.results) | ||
for key, val in best.items(): | ||
if my_space[key].name == 'switch': | ||
best[key] = my_space[key].pos_args[val+1].obj | ||
best[key] = my_space[key].pos_args[val + 1].obj | ||
pprint.pprint(best) | ||
print(trials.best_trial['result']) | ||
trials_to_csv(trials) | ||
trials_to_csv(trials, csv_file) | ||
|
||
|
||
if __name__ == '__main__': | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -212,7 +212,8 @@ def samples_preparation(in_img_array, | |
metadata_idx = append_to_dataset(samples_file["metadata"], repr(image_metadata)) | ||
|
||
if overlap > 25: | ||
logging.warning("high overlap >25%, note that automatic train/val split creates very similar samples in both sets") | ||
logging.warning( | ||
"high overlap >25%, note that automatic train/val split creates very similar samples in both sets") | ||
dist_samples = round(sample_size * (1 - (overlap / 100))) | ||
added_samples = 0 | ||
excl_samples = 0 | ||
|
@@ -247,6 +248,7 @@ def samples_preparation(in_img_array, | |
# Stratification bias | ||
if (stratd is not None) and (dataset == 'trn'): | ||
tile_size = target.size | ||
u, count = np.unique(target, return_counts=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for fixing this bug. |
||
tile_counts = {x: y for x, y in zip(u, count)} | ||
tile_props = {x: y / tile_size for x, y in zip(u, count)} | ||
for key in tile_props.keys(): | ||
|
@@ -268,8 +270,8 @@ def samples_preparation(in_img_array, | |
for key, val in tile_props.items()} | ||
distances_val = {key: np.abs(val - stratd['val']['total_props'][key]) | ||
for key, val in tile_props.items()} | ||
dist_trn = np.mean(np.array(list(distances_trn.values()))**2) | ||
dist_val = np.mean(np.array(list(distances_val.values()))**2) | ||
dist_trn = np.mean(np.array(list(distances_trn.values())) ** 2) | ||
dist_val = np.mean(np.array(list(distances_val.values())) ** 2) | ||
dist = dist_val - dist_trn | ||
stratification_bias = stratd['strat_factor'] * np.sign(dist) | ||
else: | ||
|
@@ -311,7 +313,7 @@ def samples_preparation(in_img_array, | |
final_dataset = 'val' if val else dataset | ||
logging.debug(f'Dset={final_dataset}, ' | ||
f'Added samps={added_samples}/{len(_tqdm) * len(range(0, w, dist_samples))}, ' | ||
f'Excld samps={excl_samples}/{len(_tqdm) * len(range(0, w, dist_samples))}, ' | ||
f'Excld samps={excl_samples}/{len(_tqdm) * len(range(0, w, dist_samples))}, ' | ||
f'Target annot perc={100 - target_background_percent:.1f}') | ||
|
||
if added_samples == 0: | ||
|
@@ -365,7 +367,7 @@ def main(params): | |
:param params: (dict) Parameters found in the yaml config file. | ||
""" | ||
start_time = time.time() | ||
|
||
# mlflow logging | ||
mlflow_uri = get_key_def('mlflow_uri', params['global'], default="./mlruns") | ||
experiment_name = get_key_def('mlflow_experiment_name', params['global'], default='gdl-training', expected_type=str) | ||
|
@@ -416,7 +418,6 @@ def main(params): | |
else: | ||
stratd = None | ||
|
||
|
||
# add git hash from current commit to parameters if available. Parameters will be saved to hdf5s | ||
params['global']['git_hash'] = get_git_hash() | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks that nice