benjaik commited on
Commit
a919a8c
·
verified ·
1 Parent(s): 0e198a3

Upload code/train.py

Browse files
Files changed (1) hide show
  1. code/train.py +237 -0
code/train.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
+ # Copyright (c) 2023 Image Processing Research Group of University Federico II of Naples ('GRIP-UNINA').
3
+ #
4
+ # All rights reserved.
5
+ # This work should only be used for nonprofit purposes.
6
+ #
7
+ # By downloading and/or using any of these files, you implicitly agree to all the
8
+ # terms of the license, as specified in the document LICENSE.txt
9
+ # (included in this package) and online at
10
+ # http://www.grip.unina.it/download/LICENSE_OPEN.txt
11
+
12
+ """
13
+ Created in September 2022
14
+ @author: fabrizio.guillaro
15
+ """
16
+
17
+ import sys, os
18
+ path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
19
+ if path not in sys.path:
20
+ sys.path.insert(0, path)
21
+
22
+ import argparse
23
+
24
+ import logging
25
+ import time
26
+ import timeit
27
+
28
+ import gc
29
+ import numpy as np
30
+
31
+ import torch
32
+ import torch.backends.cudnn as cudnn
33
+ import torch.optim
34
+ torch.autograd.set_detect_anomaly(True)
35
+ from tensorboardX import SummaryWriter
36
+
37
+ from lib.config import config, update_config
38
+ from lib.core.function import train, validate
39
+ from lib.utils import get_model, get_optimizer
40
+ from lib.utils import create_logger, FullModel, adjust_learning_rate
41
+
42
+ from dataset.data_core import myDataset
43
+ import albumentations
44
+
45
+
46
+ def main():
47
+ parser = argparse.ArgumentParser(description='Train TruFor')
48
+ parser.add_argument('-exp', '--experiment', type=str)
49
+ parser.add_argument('-g', '--gpu', type=int, default=[0], nargs="+", help='device(s)')
50
+ parser.add_argument('opts', help='other options', default=None, nargs=argparse.REMAINDER)
51
+ args = parser.parse_args()
52
+
53
+ os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(str(x) for x in args.gpu)
54
+ args.gpu = range(len(args.gpu))
55
+
56
+ update_config(config, args)
57
+
58
+ logger, final_output_dir, tb_log_dir = create_logger(config, f'{args.experiment}', 'train')
59
+ logger.info(config)
60
+ logger.info('\n')
61
+
62
+ # cudnn setting
63
+ cudnn.benchmark = config.CUDNN.BENCHMARK
64
+ cudnn.deterministic = config.CUDNN.DETERMINISTIC
65
+ cudnn.enabled = config.CUDNN.ENABLED
66
+
67
+ gpus = list(config.GPUS)
68
+
69
+ writer_dict = {
70
+ 'writer': SummaryWriter(tb_log_dir),
71
+ 'train_global_steps': 0,
72
+ 'valid_global_steps': 0,
73
+ }
74
+
75
+ if config.TRAIN.AUG is not None:
76
+ aug_train = albumentations.load(config.TRAIN.AUG, data_format='yaml')
77
+ else:
78
+ aug_train = None
79
+
80
+ if config.VALID.AUG is not None:
81
+ aug_valid = albumentations.load(config.VALID.AUG, data_format='yaml')
82
+ else:
83
+ aug_valid = None
84
+
85
+ logger.info(f'Train augmentation: {config.TRAIN.AUG} {aug_train}')
86
+ logger.info(f'Validation augmentation: {config.VALID.AUG} {aug_valid}')
87
+
88
+ crop_size = (config.TRAIN.IMAGE_SIZE[1], config.TRAIN.IMAGE_SIZE[0])
89
+ train_dataset = myDataset(config, crop_size=crop_size, grid_crop=False, mode='train', aug=aug_train)
90
+ valid_dataset = myDataset(config, crop_size=None, grid_crop=False, mode="valid", aug=aug_valid,
91
+ max_dim=config.VALID.MAX_SIZE)
92
+
93
+ trainloader = torch.utils.data.DataLoader(
94
+ train_dataset,
95
+ batch_size = config.TRAIN.BATCH_SIZE_PER_GPU*len(gpus),
96
+ shuffle = config.TRAIN.SHUFFLE,
97
+ num_workers = 0)
98
+
99
+ validloader = torch.utils.data.DataLoader(
100
+ valid_dataset,
101
+ batch_size = 1, # 1 to allow arbitrary input sizes
102
+ shuffle = False, # must be False to get accurate filename
103
+ num_workers = config.WORKERS)
104
+
105
+ # model
106
+ model = get_model(config)
107
+ model = torch.nn.DataParallel(model, device_ids=gpus).cuda()
108
+ model = FullModel(model, config).cuda()
109
+
110
+ # optimizer
111
+ optimizer = get_optimizer(model, config)
112
+
113
+ epoch_iters = np.int32(train_dataset.__len__() / config.TRAIN.BATCH_SIZE_PER_GPU / len(gpus))
114
+
115
+ best_key = config.VALID.BEST_KEY
116
+ if 'loss' in best_key:
117
+ best_value = np.inf
118
+ else:
119
+ best_value = 0
120
+ logger.info(f'best valid key: {best_key}')
121
+
122
+
123
+ last_epoch = 0
124
+ if not config.TRAIN.PRETRAINING == '' and not config.TRAIN.PRETRAINING == None:
125
+ model_state_file = config.TRAIN.PRETRAINING
126
+ assert os.path.isfile(model_state_file)
127
+ checkpoint = torch.load(model_state_file, map_location=lambda storage, loc: storage)
128
+ state_dict = checkpoint['state_dict']
129
+ try:
130
+ model.model.module.load_state_dict(state_dict, strict=False)
131
+ except:
132
+ state_dict = {k: state_dict[k] for k in state_dict if not k.startswith('detection')}
133
+ model.model.module.load_state_dict(state_dict, strict=False)
134
+ del checkpoint
135
+ del state_dict
136
+ logger.info("=> loaded pretraining ({})".format(model_state_file))
137
+
138
+
139
+ if config.TRAIN.RESUME:
140
+ model_state_file = os.path.join(final_output_dir, 'checkpoint.pth.tar')
141
+ if os.path.isfile(model_state_file):
142
+ checkpoint = torch.load(model_state_file, map_location=lambda storage, loc: storage)
143
+ best_value = checkpoint['best_value']
144
+ assert checkpoint['best_key']==best_key
145
+ last_epoch = checkpoint['epoch']
146
+ model.model.module.load_state_dict(checkpoint['state_dict'])
147
+ optimizer.load_state_dict(checkpoint['optimizer'])
148
+ # Checkpoints are loaded through CPU storage above. Move optimizer
149
+ # tensor state back beside the CUDA parameters before resuming.
150
+ for state in optimizer.state.values():
151
+ for key, value in state.items():
152
+ if torch.is_tensor(value):
153
+ state[key] = value.cuda()
154
+ logger.info("=> loaded checkpoint (epoch {})".format(checkpoint['epoch']))
155
+ writer_dict['train_global_steps'] = last_epoch
156
+ else:
157
+ logger.info("No previous checkpoint.")
158
+
159
+
160
+ end_epoch = config.TRAIN.END_EPOCH + config.TRAIN.EXTRA_EPOCH
161
+ num_iters = config.TRAIN.END_EPOCH * epoch_iters
162
+ start_epoch = last_epoch
163
+ if config.VALID.FIRST_VALID:
164
+ start_epoch = start_epoch -1
165
+
166
+ for epoch in range(start_epoch, end_epoch):
167
+ # train
168
+ if epoch>=last_epoch:
169
+ train_dataset.shuffle() # for class-balanced sampling
170
+
171
+ print(f'TRAINING epoch {epoch}:')
172
+ train(epoch, config.TRAIN.END_EPOCH,
173
+ epoch_iters, config.TRAIN.LR, num_iters,
174
+ trainloader, optimizer, model, writer_dict,
175
+ adjust_learning_rate=adjust_learning_rate)
176
+
177
+ torch.cuda.empty_cache()
178
+ gc.collect()
179
+ time.sleep(1.0)
180
+
181
+ logger.info('=> saving checkpoint to {}'.format(
182
+ os.path.join(final_output_dir, 'checkpoint.pth.tar')))
183
+ torch.save({
184
+ 'epoch': epoch + 1,
185
+ 'best_value': best_value,
186
+ 'best_key': best_key,
187
+ 'state_dict': model.model.module.state_dict(),
188
+ 'optimizer': optimizer.state_dict(),
189
+ }, os.path.join(final_output_dir, 'checkpoint.pth.tar'))
190
+
191
+
192
+ # valid
193
+ print(f'VALIDATION epoch {epoch}:')
194
+ writer_dict['valid_global_steps'] = epoch
195
+
196
+ value_valid, IoU_array, confusion_matrix = \
197
+ validate(config, validloader, model, writer_dict, "valid")
198
+
199
+ torch.cuda.empty_cache()
200
+ gc.collect()
201
+ time.sleep(3.0)
202
+
203
+ if 'loss' in best_key:
204
+ if value_valid[best_key] < best_value: # smallest loss
205
+ best_value = value_valid[best_key]
206
+ torch.save({
207
+ 'epoch': epoch + 1,
208
+ 'best_value': best_value,
209
+ 'best_key': best_key,
210
+ 'state_dict': model.model.module.state_dict(),
211
+ 'optimizer': optimizer.state_dict(),
212
+ }, os.path.join(final_output_dir, 'best.pth.tar'))
213
+ logger.info("best.pth.tar updated.")
214
+
215
+ elif value_valid[best_key] > best_value: # highest metric
216
+ best_value = value_valid[best_key]
217
+ torch.save({
218
+ 'epoch': epoch + 1,
219
+ 'best_value': best_value,
220
+ 'best_key': best_key,
221
+ 'state_dict': model.model.module.state_dict(),
222
+ 'optimizer': optimizer.state_dict(),
223
+ }, os.path.join(final_output_dir, 'best.pth.tar'))
224
+ logger.info("best.pth.tar updated.")
225
+
226
+ msg = '(Valid) Loss: {:.3f}, Best_{:s}: {: 4.4f}'.format(
227
+ value_valid['loss'], best_key, best_value)
228
+ logging.info(msg)
229
+ logging.info(IoU_array)
230
+ logging.info("confusion_matrix:")
231
+ logging.info(confusion_matrix)
232
+
233
+
234
+
235
+
236
+ if __name__ == '__main__':
237
+ main()