Dean commited on
Commit
a711240
1 Parent(s): b013dfa

Preparing logging for training and evaluation, and adding evaluation step [WIP]

Browse files
dvc.lock CHANGED
@@ -3,8 +3,8 @@ process_data:
3
  src/data/processed
4
  deps:
5
  - path: src/code/make_dataset.py
6
- md5: fd5076d53909a47ce3b6598c26af6c97
7
- size: 3783
8
  - path: src/data/raw/nyu_depth_v2_labeled.mat
9
  md5: 520609c519fba3ba5ac58c8fefcc3530
10
  size: 2972037809
@@ -13,8 +13,8 @@ process_data:
13
  size: 2626
14
  outs:
15
  - path: src/data/processed/
16
- md5: d98a9647a37ab431bfa35815eb4afda0.dir
17
- size: 232903470
18
  nfiles: 2898
19
  train:
20
  cmd: python3 src/code/training.py src/data/processed
 
3
  src/data/processed
4
  deps:
5
  - path: src/code/make_dataset.py
6
+ md5: 3a0dee3a1ba9c587b8ca6ea6f0447ada
7
+ size: 5227
8
  - path: src/data/raw/nyu_depth_v2_labeled.mat
9
  md5: 520609c519fba3ba5ac58c8fefcc3530
10
  size: 2972037809
 
13
  size: 2626
14
  outs:
15
  - path: src/data/processed/
16
+ md5: 38e5a1b51dfd29c0f313779b2f3d4540.dir
17
+ size: 234696354
18
  nfiles: 2898
19
  train:
20
  cmd: python3 src/code/training.py src/data/processed
dvc.yaml CHANGED
@@ -9,9 +9,17 @@ stages:
9
  outs:
10
  - src/data/processed/
11
  train:
12
- cmd: python3 src/code/training.py src/data/processed
13
  deps:
14
  - src/code/training.py
15
- - src/data/processed/
16
  outs:
17
  - src/models/
 
 
 
 
 
 
 
 
 
9
  outs:
10
  - src/data/processed/
11
  train:
12
+ cmd: python3 src/code/training.py src/data/processed/train
13
  deps:
14
  - src/code/training.py
15
+ - src/data/processed/train
16
  outs:
17
  - src/models/
18
+ eval:
19
+ cmd: python3 src/code/eval.py src/data/processed/test
20
+ deps:
21
+ - src/code/eval.py
22
+ - src/models/model.pth
23
+ - src/data/processed/test
24
+ outs:
25
+ - src/eval/
requirements.txt CHANGED
@@ -1,8 +1,9 @@
1
- dvc==1.10.1
2
- fastai==2.1.5
3
  torch==1.7.0
4
  h5py==2.10.0
5
  opencv-python==4.4.0.42
6
  tqdm==4.52.0
7
  numpy==1.19.4
8
- scikit-learn==0.23.2
 
 
1
+ dvc==1.11.15
2
+ fastai==2.2.5
3
  torch==1.7.0
4
  h5py==2.10.0
5
  opencv-python==4.4.0.42
6
  tqdm==4.52.0
7
  numpy==1.19.4
8
+ scikit-learn==0.23.2
9
+ dagshub==0.1.5
src/code/custom_data_loading.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastai.vision.all import \
2
+ DataLoaders, \
3
+ delegates, \
4
+ DataBlock, \
5
+ ImageBlock, \
6
+ PILImage, \
7
+ PILImageBW, \
8
+ RandomSplitter, \
9
+ Path, \
10
+ get_files
11
+
12
+
13
+ class ImageImageDataLoaders(DataLoaders):
14
+ """Basic wrapper around several `DataLoader`s with factory methods for Image to Image problems"""
15
+ @classmethod
16
+ @delegates(DataLoaders.from_dblock)
17
+ def from_label_func(cls, path, filenames, label_func, is_test, valid_pct=0.2, seed=None, item_transforms=None,
18
+ batch_transforms=None, **kwargs):
19
+ """Create from list of `fnames` in `path`s with `label_func`."""
20
+ datablock = DataBlock(blocks=(ImageBlock(cls=PILImage), ImageBlock(cls=PILImageBW)),
21
+ get_y=label_func,
22
+ item_tfms=item_transforms,
23
+ batch_tfms=batch_transforms)
24
+ if not is_test:
25
+ datablock.splitter = RandomSplitter(valid_pct, seed=seed)
26
+ res = cls.from_dblock(datablock, filenames, path=path, **kwargs)
27
+ return res
28
+
29
+
30
+ def get_y_fn(x):
31
+ y = str(x.absolute()).replace('.jpg', '_depth.png')
32
+ y = Path(y)
33
+
34
+ return y
35
+
36
+
37
+ def create_data(data_path, is_test=False):
38
+ filenames = get_files(data_path, extensions='.jpg')
39
+ if len(filenames) == 0:
40
+ raise ValueError("Could not find any files in the given path")
41
+ dataset = ImageImageDataLoaders.from_label_func(data_path,
42
+ is_test=is_test,
43
+ seed=42,
44
+ bs=4, num_workers=0,
45
+ filenames=filenames,
46
+ label_func=get_y_fn)
47
+ return dataset
src/code/eval.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from fastai.vision.all import unet_learner, Path, resnet34, MSELossFlat
3
+ import torch
4
+ from src.code.custom_data_loading import create_data
5
+ from dagshub.fastai import DAGsHubLogger
6
+
7
+
8
+ def compute_errors(targ, pred):
9
+ thresh = torch.max((targ / pred), (pred / targ)).numpy()
10
+ a1 = (thresh < 1.25).mean()
11
+ a2 = (thresh < 1.25 ** 2).mean()
12
+ a3 = (thresh < 1.25 ** 3).mean()
13
+
14
+ abs_rel = (torch.abs(targ - pred) / targ).mean().item()
15
+ sq_rel = torch.mean(((targ - pred).pow(2)) / targ).item()
16
+
17
+ rmse = torch.sqrt((targ - pred).pow(2).mean()).item()
18
+
19
+ rmse_log = torch.sqrt((torch.log(1 + targ) - torch.log(1 + pred)).pow(2).mean()).item()
20
+
21
+ err = torch.log(1 + pred) - torch.log(1 + targ)
22
+ silog = torch.sqrt(torch.mean(err.pow(2)) - torch.mean(err).pow(2)).item() * 100
23
+
24
+ log_10 = (torch.abs(torch.log10(1 + targ) - torch.log10(1 + pred))).mean().item()
25
+ return dict(a1=a1,
26
+ a2=a2,
27
+ a3=a3,
28
+ abs_rel=abs_rel,
29
+ sq_rel=sq_rel,
30
+ rmse=rmse,
31
+ rmse_log=rmse_log,
32
+ silog=silog,
33
+ log_10=log_10)
34
+
35
+
36
+ if __name__ == "__main__":
37
+ if len(sys.argv) < 2:
38
+ print("usage: %s <test_data_path>" % sys.argv[0], file=sys.stderr)
39
+ sys.exit(0)
40
+
41
+ data_path = Path(sys.argv[1])
42
+ data = create_data(data_path, is_test=True)
43
+
44
+ learner = unet_learner(data,
45
+ resnet34,
46
+ n_out=3,
47
+ loss_func=MSELossFlat(),
48
+ path='src/',
49
+ model_dir='models')
50
+ learner = learner.load('model')
51
+ predictions, targets = learner.get_preds()
52
+ print(compute_errors(targets, predictions))
src/code/make_dataset.py CHANGED
@@ -26,11 +26,21 @@
26
  # SOFTWARE.
27
  #######################################################################################
28
  #
29
- # Helper script to convert the NYU Depth v2 dataset Matlab file into a set of
30
- # PNG and JPEG images.
31
- #
32
  # See https://github.com/deeplearningais/curfil/wiki/Training-and-Prediction-with-the-NYU-Depth-v2-Dataset
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  from __future__ import print_function
35
 
36
  import h5py
@@ -42,41 +52,57 @@ import cv2
42
  from tqdm import tqdm
43
 
44
 
45
- def convert_image(i, scene, depth, image, folder):
46
- # depth is given in meters (Kinect has a range of around .5m and 4.5m but can sense also at 8m)
47
- normalized_depth = cv2.normalize(depth, None, 0, 255, cv2.NORM_MINMAX)
48
- cv2.imwrite("%s/%05d_depth.png" % (folder, i), normalized_depth)
 
 
49
 
50
- image = image[:, :, ::-1]
51
- image_black_boundary = np.zeros((480, 640, 3), dtype=np.uint8)
52
- image_black_boundary[7:474, 7:632, :] = image[7:474, 7:632, :]
53
- cv2.imwrite("%s/%05d.jpg" % (folder, i), image_black_boundary)
 
 
 
 
 
 
 
 
 
 
 
54
 
55
 
56
  if __name__ == "__main__":
57
 
58
- if len(sys.argv) < 4:
 
59
  print("usage: %s <h5_file> <train_test_split> <out_folder>" % sys.argv[0], file=sys.stderr)
60
  sys.exit(0)
61
 
 
62
  h5_file = h5py.File(sys.argv[1], "r")
63
- # h5py is not able to open that file. but scipy is
64
- train_test = scipy.io.loadmat(sys.argv[2])
65
  out_folder = sys.argv[3]
66
 
 
67
  test_images = set([int(x) for x in train_test["testNdxs"]])
68
  train_images = set([int(x) for x in train_test["trainNdxs"]])
69
  print("%d training images" % len(train_images))
70
  print("%d test images" % len(test_images))
71
 
 
72
  depth = h5_file['depths']
 
 
73
 
74
- print("reading", sys.argv[1])
75
-
76
- images = h5_file['images']
77
  scenes = [u''.join(chr(c[0]) for c in h5_file[obj_ref]) for obj_ref in h5_file['sceneTypes'][0]]
78
 
79
- for i, image in tqdm(enumerate(images), desc="processing images", total=len(images)):
80
  idx = int(i) + 1
81
  if idx in train_images:
82
  train_test = "train"
@@ -84,9 +110,11 @@ if __name__ == "__main__":
84
  assert idx in test_images, "index %d neither found in training set nor in test set" % idx
85
  train_test = "test"
86
 
 
87
  folder = "%s/%s/%s" % (out_folder, train_test, scenes[i])
88
  if not os.path.exists(folder):
89
  os.makedirs(folder)
90
- convert_image(i, scenes[i], depth[i, :, :].T, image.T, folder)
 
91
 
92
  print("Finished")
 
26
  # SOFTWARE.
27
  #######################################################################################
28
  #
 
 
 
29
  # See https://github.com/deeplearningais/curfil/wiki/Training-and-Prediction-with-the-NYU-Depth-v2-Dataset
30
 
31
+
32
+ """Helper script to convert the NYU Depth v2 dataset Matlab file into a set of PNG and JPEG images.
33
+ Receives 3 Files from argparse:
34
+ <h5_file> - Contains the original images, depths maps, and scene types
35
+ <train_test_split> - contains two numpy arrays with the index of the
36
+ images based on the split to train and test sets.
37
+ <out_folder> - Name of the folder to save the original and depth images.
38
+
39
+ Every image in the DB will have it's twine B&W image that indicates the depth
40
+ in the image. the images will be read, converted by the convert_image function
41
+ and finally saved to path based on train test split and Scene types.
42
+ """
43
+
44
  from __future__ import print_function
45
 
46
  import h5py
 
52
  from tqdm import tqdm
53
 
54
 
55
+ def convert_image(index, depth_map, img, output_folder):
56
+ """Processes data images and depth maps
57
+ :param index: int, image index
58
+ :param depth_map: numpy array, image depth - 2D array.
59
+ :param img: numpy array, the original RGB image - 3D array.
60
+ :param output_folder: path to save the image in.
61
 
62
+ Receives an image with it's relevant depth map.
63
+ Normalizes the depth map, and adds a 7 px boundary to the original image.
64
+ Saves both image and depth map to the appropriate processed data folder.
65
+ """
66
+
67
+ # Normalize the depth image
68
+ normalized_depth = cv2.normalize(depth_map, None, 0, 255, cv2.NORM_MINMAX)
69
+ cv2.imwrite("%s/%05d_depth.png" % (output_folder, index), normalized_depth)
70
+
71
+ # Adding black frame to original image
72
+ img = img[:, :, ::-1] # Flipping the image from RGB to BGR for opencv
73
+ image_black_boundary = np.zeros(img.shape, dtype=np.uint8)
74
+ image_black_boundary[7:image_black_boundary.shape[0] - 6, 7:image_black_boundary.shape[1] - 6, :] = \
75
+ img[7:img.shape[0] - 6, 7:img.shape[1] - 6, :]
76
+ cv2.imwrite("%s/%05d.jpg" % (output_folder, index), image_black_boundary)
77
 
78
 
79
  if __name__ == "__main__":
80
 
81
+ # Check if got all needed input for argparse
82
+ if len(sys.argv) != 4:
83
  print("usage: %s <h5_file> <train_test_split> <out_folder>" % sys.argv[0], file=sys.stderr)
84
  sys.exit(0)
85
 
86
+ # load arguments to variables
87
  h5_file = h5py.File(sys.argv[1], "r")
88
+ train_test = scipy.io.loadmat(sys.argv[2]) # h5py is not able to open that file. but scipy is
 
89
  out_folder = sys.argv[3]
90
 
91
+ # Extract images *indexes* for train and test data sets
92
  test_images = set([int(x) for x in train_test["testNdxs"]])
93
  train_images = set([int(x) for x in train_test["trainNdxs"]])
94
  print("%d training images" % len(train_images))
95
  print("%d test images" % len(test_images))
96
 
97
+ # Grayscale
98
  depth = h5_file['depths']
99
+ print("Reading", sys.argv[1])
100
+ images = h5_file['images'] # (num_channels, height, width)
101
 
102
+ # Extract all sceneTypes per image - "office", "classroom", etc.
 
 
103
  scenes = [u''.join(chr(c[0]) for c in h5_file[obj_ref]) for obj_ref in h5_file['sceneTypes'][0]]
104
 
105
+ for i, image in tqdm(enumerate(images), desc="Processing images", total=len(images)):
106
  idx = int(i) + 1
107
  if idx in train_images:
108
  train_test = "train"
 
110
  assert idx in test_images, "index %d neither found in training set nor in test set" % idx
111
  train_test = "test"
112
 
113
+ # Create path to save image in
114
  folder = "%s/%s/%s" % (out_folder, train_test, scenes[i])
115
  if not os.path.exists(folder):
116
  os.makedirs(folder)
117
+
118
+ convert_image(i, depth[i, :, :].T, image.T, folder)
119
 
120
  print("Finished")
src/code/training.py CHANGED
@@ -1,49 +1,36 @@
1
- import torch
 
 
 
2
  import sys
3
- from fastai.vision.all import *
4
- from torchvision.utils import save_image
5
-
6
-
7
- class ImageImageDataLoaders(DataLoaders):
8
- "Basic wrapper around several `DataLoader`s with factory methods for Image to Image problems"
9
-
10
- @classmethod
11
- @delegates(DataLoaders.from_dblock)
12
- def from_label_func(cls, path, fnames, label_func, valid_pct=0.2, seed=None, item_tfms=None,
13
- batch_tfms=None, **kwargs):
14
- "Create from list of `fnames` in `path`s with `label_func`."
15
- dblock = DataBlock(blocks=(ImageBlock(cls=PILImage), ImageBlock(cls=PILImageBW)),
16
- splitter=RandomSplitter(valid_pct, seed=seed),
17
- get_y=label_func,
18
- item_tfms=item_tfms,
19
- batch_tfms=batch_tfms)
20
- res = cls.from_dblock(dblock, fnames, path=path, **kwargs)
21
- return res
22
-
23
-
24
- def get_y_fn(x):
25
- y = str(x.absolute()).replace('.jpg', '_depth.png')
26
- y = Path(y)
27
-
28
- return y
29
-
30
-
31
- def create_data(data_path):
32
- fnames = get_files(data_path / 'train', extensions='.jpg')
33
- data = ImageImageDataLoaders.from_label_func(data_path / 'train', seed=42, bs=4, num_workers=0,
34
- fnames=fnames, label_func=get_y_fn)
35
- return data
36
 
37
 
38
  if __name__ == "__main__":
39
- if len(sys.argv) < 2:
 
40
  print("usage: %s <data_path>" % sys.argv[0], file=sys.stderr)
41
  sys.exit(0)
42
 
43
  data = create_data(Path(sys.argv[1]))
44
- learner = unet_learner(data, resnet34, metrics=rmse, wd=1e-2, n_out=3, loss_func=MSELossFlat(),
45
- path='src/test/')
 
 
 
 
 
 
 
 
 
 
 
 
46
  print("Training model...")
47
- learner.fine_tune(1)
48
  print("Saving model...")
49
  learner.save('model')
 
 
1
+ """Trains or fine-tunes a model for the task of monocular depth estimation
2
+ Receives 1 arguments from argparse:
3
+ <data_path> - Path to the dataset which is split into 2 folders - train and test.
4
+ """
5
  import sys
6
+ from fastai.vision.all import unet_learner, Path, resnet34, rmse, MSELossFlat
7
+ from src.code.custom_data_loading import create_data
8
+ from dagshub.fastai import DAGsHubLogger
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
 
11
  if __name__ == "__main__":
12
+ # Check if got all needed input for argparse
13
+ if len(sys.argv) != 2:
14
  print("usage: %s <data_path>" % sys.argv[0], file=sys.stderr)
15
  sys.exit(0)
16
 
17
  data = create_data(Path(sys.argv[1]))
18
+ wd, lr, ep = 1e-2, 1e-3, 1
19
+ learner = unet_learner(data,
20
+ resnet34,
21
+ metrics=rmse,
22
+ wd=wd,
23
+ n_out=3,
24
+ loss_func=MSELossFlat(),
25
+ path='src/',
26
+ model_dir='models',
27
+ cbs=DAGsHubLogger(
28
+ metrics_path="train_metrics.csv",
29
+ hparams_path="train_params.yml"
30
+ ))
31
+
32
  print("Training model...")
33
+ learner.fine_tune(epochs=ep, base_lr=lr)
34
  print("Saving model...")
35
  learner.save('model')
36
+ print("Done!")
src/data/raw/nyu_depth_v2_labeled.mat.dvc CHANGED
@@ -6,3 +6,4 @@ deps:
6
  outs:
7
  - md5: 520609c519fba3ba5ac58c8fefcc3530
8
  path: nyu_depth_v2_labeled.mat
 
 
6
  outs:
7
  - md5: 520609c519fba3ba5ac58c8fefcc3530
8
  path: nyu_depth_v2_labeled.mat
9
+ size: 2972037809
src/data/raw/splits.mat.dvc CHANGED
@@ -6,3 +6,4 @@ deps:
6
  outs:
7
  - md5: 08e3c3aea27130ac7c01ffd739a4535f
8
  path: splits.mat
 
 
6
  outs:
7
  - md5: 08e3c3aea27130ac7c01ffd739a4535f
8
  path: splits.mat
9
+ size: 2626