JustAGek commited on
Commit
d152cc9
·
1 Parent(s): 576f34f

DLoc baseline + Mamba minimal run

Browse files
.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data and outputs
2
+ /data/
3
+ /runs/
4
+ **/*.mat
5
+ **/*.h5
6
+ **/*.hdf5
7
+ **/*.pt
8
+ **/*.pth
9
+ **/*.ckpt
10
+ **/*.npz
11
+ **/*.npy
12
+ **/*.log
Generators.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ '''
3
+ Defines the Encoders and Decoder that make up the
4
+ Enc+Dec/Enc+2Dec model defined in DLoc
5
+ Idea and code originally from fstin Johnson's architecture.
6
+ https://github.com/jcjohnson/fast-neural-style/
7
+ Code base expanded from pix2pix Phillip Isola's implementation
8
+ https://github.com/phillipi/pix2pix
9
+
10
+ You can add your costum network building blocks here to test various other architectures.
11
+ '''
12
+ import torch
13
+ import torch.nn as nn
14
+ import functools
15
+
16
+
17
+ # Tha base Encoder function defined for the DLoc's Encoder
18
+ class ResnetEncoder(nn.Module):
19
+ def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=6, padding_type='zero'):
20
+ assert(n_blocks >= 0)
21
+ super(ResnetEncoder, self).__init__()
22
+ self.input_nc = input_nc
23
+ self.output_nc = output_nc
24
+ self.ngf = ngf
25
+ if type(norm_layer) == functools.partial:
26
+ use_bias = norm_layer.func == nn.InstanceNorm2d
27
+ else:
28
+ use_bias = norm_layer == nn.InstanceNorm2d
29
+
30
+ model = [nn.Conv2d(input_nc, input_nc, kernel_size=7, padding=3,
31
+ bias=use_bias),
32
+ norm_layer(input_nc),
33
+ nn.Tanh()]
34
+
35
+ model += [nn.Conv2d(input_nc, ngf, kernel_size=7, padding=3,
36
+ bias=use_bias),
37
+ norm_layer(ngf),
38
+ nn.ReLU(True)]
39
+
40
+ n_downsampling = 2
41
+ for i in range(n_downsampling):
42
+ mult = 2**i
43
+ model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3,
44
+ stride=2, padding=1, bias=use_bias),
45
+ norm_layer(ngf * mult * 2),
46
+ nn.ReLU(True)]
47
+
48
+ mult = 2**n_downsampling
49
+ for i in range(n_blocks):
50
+ model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)]
51
+
52
+ self.model = nn.Sequential(*model)
53
+
54
+ def forward(self, input):
55
+ return self.model(input)
56
+
57
+
58
+ # Tha base Decoder function defined for the DLoc's Decoders.
59
+ # Depending upon the ModelADT wraper around the decoder,
60
+ # the decoder would either be a Location Decoder or a Consistency decoder.
61
+ # For more details refer to ModelADT.py wrapper implementation and params.py
62
+ class ResnetDecoder(nn.Module):
63
+ def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=9, padding_type='zero', encoder_blocks=6):
64
+ assert(n_blocks >= 0)
65
+ super(ResnetDecoder, self).__init__()
66
+ self.input_nc = input_nc
67
+ self.output_nc = output_nc
68
+ self.ngf = ngf
69
+ if type(norm_layer) == functools.partial:
70
+ use_bias = norm_layer.func == nn.InstanceNorm2d
71
+ else:
72
+ use_bias = norm_layer == nn.InstanceNorm2d
73
+
74
+ model = []
75
+ n_downsampling = 2
76
+ for i in range(n_downsampling):
77
+ mult = 2**i
78
+
79
+ mult = 2**n_downsampling
80
+ for i in range(n_blocks):
81
+ if i <= encoder_blocks:
82
+ continue
83
+ model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)]
84
+
85
+ for i in range(n_downsampling):
86
+ mult = 2**(n_downsampling - i)
87
+ model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),
88
+ kernel_size=3, stride=2,
89
+ padding=1, output_padding=0,
90
+ bias=use_bias),
91
+ norm_layer(int(ngf * mult / 2)),
92
+ nn.ReLU(True)]
93
+ # model += [nn.ReflectionPad2d(3)]
94
+ model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=[3,3])]
95
+ model += [nn.Sigmoid()]
96
+
97
+ self.model = nn.Sequential(*model)
98
+
99
+ def forward(self, input):
100
+ #print("decoder.input = ", input.shape)
101
+ return self.model(input)
102
+ # In[3]:
103
+
104
+
105
+ # Define a resnet block
106
+ class ResnetBlock(nn.Module):
107
+ def __init__(self, dim, padding_type, norm_layer, use_dropout, use_bias):
108
+ super(ResnetBlock, self).__init__()
109
+ self.conv_block = self.build_conv_block(dim, padding_type, norm_layer, use_dropout, use_bias)
110
+
111
+ def build_conv_block(self, dim, padding_type, norm_layer, use_dropout, use_bias):
112
+ conv_block = []
113
+ p = 0
114
+ if padding_type == 'reflect':
115
+ conv_block += [nn.ReflectionPad2d(1)]
116
+ elif padding_type == 'replicate':
117
+ conv_block += [nn.ReplicationPad2d(1)]
118
+ elif padding_type == 'zero':
119
+ p = 1
120
+ else:
121
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
122
+
123
+ conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
124
+ norm_layer(dim),
125
+ nn.ReLU(True)]
126
+ if use_dropout:
127
+ conv_block += [nn.Dropout(0.25)]
128
+
129
+ p = 0
130
+ if padding_type == 'reflect':
131
+ conv_block += [nn.ReflectionPad2d(1)]
132
+ elif padding_type == 'replicate':
133
+ conv_block += [nn.ReplicationPad2d(1)]
134
+ elif padding_type == 'zero':
135
+ p = 1
136
+ else:
137
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
138
+ conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
139
+ norm_layer(dim)]
140
+
141
+ return nn.Sequential(*conv_block)
142
+
143
+ def forward(self, x):
144
+ out = x + self.conv_block(x)
145
+ return out
README.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DLoc minimal run (baseline + mamba)
2
+
3
+ This folder is an isolated, minimal run package for:
4
+ - DLoc baseline (Fig 10b, single GPU)
5
+ - Mamba-DLoc (single GPU)
6
+
7
+ It excludes all data and training outputs by default.
8
+
9
+ ## Required data (place in ./data)
10
+ - dataset_jacobs_July28.mat (fixed 7,635 samples)
11
+ - dataset_non_fov_train_jacobs_July28_2.mat
12
+ - dataset_fov_train_jacobs_July28_2.mat
13
+ - dataset_non_fov_test_jacobs_July28_2.mat
14
+ - dataset_fov_test_jacobs_July28_2.mat
15
+
16
+ ## Setup
17
+ This assumes PyTorch is already installed (e.g., vast.ai PyTorch image).
18
+
19
+ ```bash
20
+ pip install -r requirements.txt
21
+ ```
22
+
23
+ ## Run baseline (Fig 10b)
24
+ ```bash
25
+ cp params_storage/params_fig10b_single_gpu.py params.py
26
+ python train_and_test.py
27
+ ```
28
+
29
+ ## Run Mamba
30
+ ```bash
31
+ cp params_storage/params_mamba_single_gpu.py params.py
32
+ python train_and_test.py
33
+ ```
34
+
35
+ ## Notes
36
+ - Outputs go to ./runs/<timestamp>/
37
+ - This folder is safe to upload to Git/HF (data and runs are ignored).
data_loader.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ # A simple data loader that imports the train and test mat files
3
+ # from the `filename` and converts them to torch.tesnors()
4
+ # to be loaded for training and testing DLoc network
5
+ # `features_wo_offset`: targets for the consistency decoder
6
+ # `features_w_offset` : inputs for the network/encoder
7
+ # `labels_gaussian_2d`: targets for the location decoder
8
+ import torch
9
+ import h5py
10
+ import scipy.io
11
+ import numpy as np
12
+
13
+ def load_data(filename):
14
+ print('Loading '+filename)
15
+ arrays = {}
16
+ f = h5py.File(filename,'r')
17
+ features_wo_offset = torch.tensor(np.transpose(np.array(f.get('features_wo_offset'), dtype=np.float32)), dtype=torch.float32)
18
+ features_w_offset = torch.tensor(np.transpose(np.array(f.get('features_w_offset'), dtype=np.float32)), dtype=torch.float32)
19
+ labels_gaussian_2d = torch.tensor(np.transpose(np.array(f.get('labels_gaussian_2d'), dtype=np.float32)), dtype=torch.float32)
20
+
21
+ return features_wo_offset,features_w_offset, labels_gaussian_2d
22
+
23
+
24
+ class LazyMultiHDF5Dataset(torch.utils.data.Dataset):
25
+ """Reads samples on demand from multiple HDF5 .mat files.
26
+ Uses ~0 RAM regardless of dataset size. Each __getitem__ does 3 small
27
+ HDF5 slice reads (~700 KB total per sample).
28
+
29
+ Returns the same tuple ordering as the original TensorDataset:
30
+ (features_wo_offset, features_w_offset, labels_gaussian_2d)
31
+ """
32
+
33
+ def __init__(self, file_paths):
34
+ self.file_paths = file_paths
35
+ self._handles = {} # lazy-opened per worker/process
36
+ self.cum_sizes = []
37
+ self.var_names = {} # per file: (w_name, wo_name, lbl_name)
38
+
39
+ total = 0
40
+ for fp in file_paths:
41
+ with h5py.File(fp, 'r') as f:
42
+ keys = list(f.keys())
43
+ w_name = 'features_w_offset' if 'features_w_offset' in keys else 'features_with_offset'
44
+ wo_name = 'features_wo_offset' if 'features_wo_offset' in keys else 'features_without_offset'
45
+ lbl_name = 'labels_gaussian_2d'
46
+ self.var_names[fp] = (w_name, wo_name, lbl_name)
47
+ # HDF5 stores MATLAB dims reversed: last dim = N
48
+ n = f[w_name].shape[-1]
49
+ total += n
50
+ self.cum_sizes.append(total)
51
+ print(f' Indexed {fp}: {n} samples')
52
+
53
+ self.total_len = total
54
+ print(f' Total: {self.total_len} samples (lazy, ~0 MB RAM)')
55
+
56
+ def __len__(self):
57
+ return self.total_len
58
+
59
+ def _get_handle(self, fp):
60
+ if fp not in self._handles:
61
+ self._handles[fp] = h5py.File(fp, 'r')
62
+ return self._handles[fp]
63
+
64
+ def __getitem__(self, idx):
65
+ # Find which file this idx belongs to
66
+ file_idx = 0
67
+ for i, cs in enumerate(self.cum_sizes):
68
+ if idx < cs:
69
+ file_idx = i
70
+ break
71
+
72
+ offset = self.cum_sizes[file_idx - 1] if file_idx > 0 else 0
73
+ local_idx = idx - offset
74
+
75
+ fp = self.file_paths[file_idx]
76
+ f = self._get_handle(fp)
77
+ w_name, wo_name, lbl_name = self.var_names[fp]
78
+
79
+ # HDF5 dims are reversed vs MATLAB:
80
+ # features: MATLAB [N,4,161,361] -> HDF5 [361,161,4,N]
81
+ # labels: MATLAB [N,161,361] -> HDF5 [361,161,N]
82
+ feat_w = np.array(f[w_name][:, :, :, local_idx], dtype=np.float32).transpose() # -> [4,161,361]
83
+ feat_wo = np.array(f[wo_name][:, :, :, local_idx], dtype=np.float32).transpose() # -> [4,161,361]
84
+ label = np.array(f[lbl_name][:, :, local_idx], dtype=np.float32).transpose() # -> [161,361]
85
+ label = label[np.newaxis, :, :] # -> [1,161,361]
86
+
87
+ return (
88
+ torch.from_numpy(feat_wo),
89
+ torch.from_numpy(feat_w),
90
+ torch.from_numpy(label)
91
+ )
92
+
93
+ def __del__(self):
94
+ for f in self._handles.values():
95
+ try:
96
+ f.close()
97
+ except Exception:
98
+ pass
joint_model.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ '''
3
+ Defines a PyTorch graph for forward and backward propogation
4
+ within the network encoders and decoders.
5
+ '''
6
+ import torch
7
+ from utils import *
8
+ from Generators import *
9
+ from data_loader import *
10
+ from params import *
11
+
12
+
13
+ '''
14
+ Class Definition for 1 Encoder and 1 Decoder joint model
15
+ '''
16
+ class Enc_Dec_Network():
17
+
18
+ def initialize(self, opt, encoder, decoder, frozen_dec=False, frozen_enc=False, gpu_ids='1'):
19
+ self.opt = opt
20
+ self.isTrain = opt.isTrain
21
+ self.encoder = encoder
22
+ self.decoder = decoder
23
+ self.frozen_dec = frozen_dec
24
+ self.frozen_enc = frozen_enc
25
+ self.device = torch.device('cuda:{}'.format(gpu_ids[0])) # if self.gpu_ids else torch.device('cpu')
26
+ # self.encoder.net = encoder.net.to(self.device)
27
+ # self.decoder.net = decoder.net.to(self.device)
28
+
29
+ def set_input(self, input, target, convert_enc=True, shuffle_channel=True):
30
+ self.input = input.to(self.device)
31
+ self.target = target.to(self.device)
32
+ self.encoder.set_data(self.input, self.input, convert=convert_enc, shuffle_channel=shuffle_channel)
33
+
34
+ def save_networks(self, epoch):
35
+ self.encoder.save_networks(epoch)
36
+ self.decoder.save_networks(epoch)
37
+
38
+ def save_outputs(self):
39
+ self.encoder.save_outputs()
40
+ self.decoder.save_outputs()
41
+
42
+ def update_learning_rate(self):
43
+ self.encoder.update_learning_rate()
44
+
45
+ def forward(self):
46
+ self.encoder.forward()
47
+ self.decoder.set_data(self.encoder.output, self.target)
48
+ self.decoder.forward()
49
+
50
+ def test(self):
51
+ self.encoder.test()
52
+ self.decoder.set_data(self.encoder.output, self.target)
53
+ self.decoder.test()
54
+
55
+ def backward(self):
56
+ self.decoder.backward()
57
+ # self.encoder.backward()
58
+
59
+ def optimize_parameters(self):
60
+ self.forward()
61
+ self.backward()
62
+ if not self.frozen_enc:
63
+ self.encoder.optimizer.step()
64
+ if not self.frozen_dec:
65
+ self.decoder.optimizer.step()
66
+ self.encoder.optimizer.zero_grad()
67
+ self.decoder.optimizer.zero_grad()
68
+
69
+ def eval(self):
70
+ self.encoder.forward()
71
+ self.decoder.set_data(self.encoder.output, self.target)
72
+ self.decoder.forward()
73
+
74
+ '''
75
+ Class Definition for the final DLoc architecture with
76
+ 1 Encoder and 2 Decoders joint model
77
+ '''
78
+ class Enc_2Dec_Network():
79
+
80
+ def initialize(self, opt , encoder, decoder, offset_decoder, frozen_dec=False, frozen_enc=False, gpu_ids='1'):
81
+ print('initializing Encoder and 2 Decoders Model')
82
+ self.opt = opt
83
+ self.isTrain = opt.isTrain
84
+ self.encoder = encoder
85
+ self.decoder = decoder
86
+ self.offset_decoder = offset_decoder
87
+ self.frozen_dec = frozen_dec
88
+ self.frozen_enc = frozen_enc
89
+ self.device = torch.device('cuda:{}'.format(gpu_ids[0])) # if self.gpu_ids else torch.device('cpu')
90
+ # self.encoder.net = encoder.net.to(self.device)
91
+ # self.decoder.net = decoder.net.to(self.device)
92
+ self.results_save_dir = opt.results_dir
93
+
94
+ def set_input(self, input, target ,offset_target ,convert_enc=True, shuffle_channel=True):
95
+ # features_w_offset, labels_gaussian_2d, features_wo_offset
96
+ # input, target, offset_target
97
+ self.input = input.to(self.device)
98
+ self.target = target.to(self.device)
99
+ self.offset_target = offset_target.to(self.device)
100
+ self.encoder.set_data(self.input, self.input, convert=convert_enc, shuffle_channel=shuffle_channel)
101
+
102
+ def save_networks(self, epoch):
103
+ self.encoder.save_networks(epoch)
104
+ self.decoder.save_networks(epoch)
105
+ self.offset_decoder.save_networks(epoch)
106
+
107
+ def save_outputs(self):
108
+ self.encoder.save_outputs()
109
+ self.decoder.save_outputs()
110
+ self.offset_decoder.save_outputs()
111
+
112
+ def update_learning_rate(self):
113
+ self.encoder.update_learning_rate()
114
+ self.decoder.update_learning_rate()
115
+ self.offset_decoder.update_learning_rate()
116
+
117
+ def forward(self):
118
+ self.encoder.forward()
119
+ self.decoder.set_data(self.encoder.output, self.target)
120
+ self.offset_decoder.set_data(self.encoder.output, self.offset_target)
121
+ self.decoder.forward()
122
+ self.offset_decoder.forward()
123
+
124
+ # Test the network once set into Evaluation mode!
125
+ def test(self):
126
+ self.encoder.test()
127
+ self.decoder.set_data(self.encoder.output, self.target)
128
+ self.offset_decoder.set_data(self.encoder.output, self.offset_target)
129
+ self.decoder.test()
130
+ self.offset_decoder.test()
131
+
132
+ def backward(self):
133
+ self.decoder.backward()
134
+ self.offset_decoder.backward()
135
+ # self.encoder.backward()
136
+
137
+ def optimize_parameters(self):
138
+ self.forward()
139
+ self.backward()
140
+ if not self.frozen_enc:
141
+ self.encoder.optimizer.step()
142
+ if not self.frozen_dec:
143
+ self.decoder.optimizer.step()
144
+ self.offset_decoder.optimizer.step()
145
+ self.encoder.optimizer.zero_grad()
146
+ self.decoder.optimizer.zero_grad()
147
+ self.offset_decoder.optimizer.zero_grad()
148
+
149
+ # set the models to evaluation mode
150
+ def eval(self):
151
+ self.encoder.eval()
152
+ self.decoder.eval()
153
+ self.offset_decoder.eval()
154
+
155
+
156
+ class _EncoderProxy:
157
+ """Lightweight proxy that shares opt/optimizer but no-ops on LR update.
158
+
159
+ trainer.py calls update_learning_rate() on both model.encoder and
160
+ model.decoder. For the Mamba pipeline there is only one optimizer,
161
+ so this proxy prevents double-stepping the LR scheduler.
162
+ """
163
+
164
+ def __init__(self, model_adt):
165
+ self.opt = model_adt.opt
166
+ self.optimizer = model_adt.optimizer
167
+
168
+ def update_learning_rate(self):
169
+ pass # decoder handles the single scheduler
170
+
171
+ def save_networks(self, epoch):
172
+ pass # decoder handles saving
173
+
174
+
175
+ class Mamba_Network():
176
+ """Joint-model wrapper for the single end-to-end MambaDLocNet.
177
+
178
+ Exposes the same interface that trainer.py expects
179
+ (model.encoder, model.decoder, set_input, optimize_parameters, ...)
180
+ while internally using a single ModelADT with one optimizer.
181
+ """
182
+
183
+ def initialize(self, opt, mamba_model_adt, gpu_ids='0'):
184
+ self.opt = opt
185
+ self.isTrain = opt.isTrain
186
+ self.decoder = mamba_model_adt # trainer reads .output, .loss, .model_name, .opt
187
+ self.encoder = _EncoderProxy(mamba_model_adt) # no-op LR update
188
+ self.device = torch.device('cuda:{}'.format(gpu_ids[0]))
189
+
190
+ def set_input(self, input, target, shuffle_channel=False):
191
+ self.input = input.to(self.device)
192
+ self.target = target.to(self.device)
193
+ self.decoder.set_data(self.input, self.target, shuffle_channel=shuffle_channel)
194
+
195
+ def save_networks(self, epoch):
196
+ self.decoder.save_networks(epoch)
197
+
198
+ def update_learning_rate(self):
199
+ self.decoder.update_learning_rate()
200
+
201
+ def forward(self):
202
+ self.decoder.forward()
203
+
204
+ def test(self):
205
+ self.decoder.test()
206
+
207
+ def backward(self):
208
+ self.decoder.backward()
209
+
210
+ def optimize_parameters(self):
211
+ self.forward()
212
+ self.backward()
213
+ self.decoder.optimizer.step()
214
+ self.decoder.optimizer.zero_grad()
215
+
216
+ def eval(self):
217
+ self.decoder.eval()
mamba_model.py ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ mamba_model.py
4
+ Mamba-DLoc: Replaces the ResNet bottleneck in DLoc with Mamba selective
5
+ state-space (S6) blocks for efficient long-range sequence modelling.
6
+
7
+ Architecture overview
8
+ ---------------------
9
+ CNN Stem (4 -> 128 channels, 2x spatial downsample)
10
+ -> Tokenize (flatten spatial -> sequence)
11
+ -> 4x MambaResidualBlock (LayerNorm -> Mamba -> residual)
12
+ -> Reshape back to spatial
13
+ -> CNN Decoder (upsample back to original resolution)
14
+
15
+ Input: [B, 4, 161, 361] AoA heatmaps
16
+ Output: [B, 1, 161, 361] location heatmap
17
+ """
18
+
19
+ import math
20
+ import torch
21
+ import torch.nn as nn
22
+ import torch.nn.functional as F
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Try to import the CUDA-optimised Mamba implementation (Linux + CUDA only).
26
+ # Fall back to a pure-PyTorch implementation on Windows / CPU.
27
+ # ---------------------------------------------------------------------------
28
+ HAS_MAMBA_SSM = False
29
+ try:
30
+ from mamba_ssm import Mamba as CudaMamba # type: ignore
31
+ HAS_MAMBA_SSM = True
32
+ except ImportError:
33
+ CudaMamba = None
34
+
35
+
36
+ # ===================================================================
37
+ # Pure-PyTorch Mamba (S6 selective scan) - works on any backend
38
+ # ===================================================================
39
+ class PurePytorchMamba(nn.Module):
40
+ """
41
+ Minimal re-implementation of the Mamba selective-scan block (S6).
42
+
43
+ Interface: [B, L, D] -> [B, L, D]
44
+
45
+ Parameters
46
+ ----------
47
+ d_model : int - input / output dimension (D)
48
+ d_state : int - SSM hidden state dimension (N)
49
+ d_conv : int - local convolution kernel width
50
+ expand : int - expansion factor for inner dimension (E = expand * D)
51
+ """
52
+
53
+ def __init__(self, d_model: int = 128, d_state: int = 16,
54
+ d_conv: int = 4, expand: int = 2):
55
+ super().__init__()
56
+ self.d_model = d_model
57
+ self.d_state = d_state
58
+ self.d_conv = d_conv
59
+ self.expand = expand
60
+ self.d_inner = d_model * expand # E
61
+ self.dt_rank = math.ceil(d_model / 16) # rank for delta-t projection
62
+
63
+ # --- input projection: D -> 2*E (main path + gate) ---
64
+ self.in_proj = nn.Linear(d_model, 2 * self.d_inner, bias=False)
65
+
66
+ # --- causal depthwise conv on main path ---
67
+ self.conv1d = nn.Conv1d(
68
+ self.d_inner, self.d_inner,
69
+ kernel_size=d_conv, padding=d_conv - 1, # causal: trim later
70
+ groups=self.d_inner, bias=True,
71
+ )
72
+
73
+ # --- SSM parameter projections ---
74
+ # from the convolved main path (E) -> dt_rank + 2*N
75
+ self.x_proj = nn.Linear(self.d_inner, self.dt_rank + 2 * d_state, bias=False)
76
+
77
+ # dt_rank -> E (broadcast delta across inner dim)
78
+ self.dt_proj = nn.Linear(self.dt_rank, self.d_inner, bias=True)
79
+
80
+ # --- learnable SSM parameters ---
81
+ # A_log: [E, N] initialised as log(1..N) broadcast to each inner dim
82
+ A = torch.arange(1, d_state + 1, dtype=torch.float32).unsqueeze(0).expand(self.d_inner, -1)
83
+ self.A_log = nn.Parameter(torch.log(A)) # learned in log-space
84
+
85
+ # D (skip connection scalar per inner dim)
86
+ self.D = nn.Parameter(torch.ones(self.d_inner))
87
+
88
+ # --- output projection: E -> D ---
89
+ self.out_proj = nn.Linear(self.d_inner, d_model, bias=False)
90
+
91
+ # ---------------------------------------------------------------
92
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
93
+ """
94
+ x : [B, L, D]
95
+ returns : [B, L, D]
96
+ """
97
+ B, L, _ = x.shape
98
+
99
+ # --- input projection & split ---
100
+ xz = self.in_proj(x) # [B, L, 2E]
101
+ x_main, z = xz.chunk(2, dim=-1) # each [B, L, E]
102
+
103
+ # --- causal conv1d on main path ---
104
+ # conv1d expects [B, E, L]
105
+ x_main = x_main.transpose(1, 2) # [B, E, L]
106
+ x_main = self.conv1d(x_main)[:, :, :L] # causal trim
107
+ x_main = x_main.transpose(1, 2) # [B, L, E]
108
+ x_main = F.silu(x_main)
109
+
110
+ # --- SSM parameters ---
111
+ x_ssm = self.x_proj(x_main) # [B, L, dt_rank + 2N]
112
+ dt, B_param, C_param = x_ssm.split(
113
+ [self.dt_rank, self.d_state, self.d_state], dim=-1
114
+ )
115
+ # dt: [B, L, dt_rank] -> [B, L, E]
116
+ dt = F.softplus(self.dt_proj(dt)) # [B, L, E]
117
+
118
+ # A: [E, N] (negative for stability)
119
+ A = -torch.exp(self.A_log) # [E, N]
120
+
121
+ # --- discretize ---
122
+ # dA: [B, L, E, N]
123
+ dA = torch.exp(dt.unsqueeze(-1) * A.unsqueeze(0).unsqueeze(0))
124
+ # dB: [B, L, E, N]
125
+ dB = dt.unsqueeze(-1) * B_param.unsqueeze(2) # broadcast E
126
+
127
+ # --- selective scan (sequential, kept simple for correctness) ---
128
+ # x_main: [B, L, E] -> weight input
129
+ # h: [B, E, N] SSM hidden state
130
+ h = torch.zeros(B, self.d_inner, self.d_state,
131
+ device=x.device, dtype=x.dtype)
132
+ ys = []
133
+ for t in range(L):
134
+ h = dA[:, t, :, :] * h + dB[:, t, :, :] * x_main[:, t, :].unsqueeze(-1)
135
+ y_t = (h * C_param[:, t, :].unsqueeze(1)).sum(dim=-1) # [B, E]
136
+ ys.append(y_t)
137
+ y = torch.stack(ys, dim=1) # [B, L, E]
138
+
139
+ # --- skip connection ---
140
+ y = y + x_main * self.D.unsqueeze(0).unsqueeze(0)
141
+
142
+ # --- gate ---
143
+ y = y * F.silu(z)
144
+
145
+ # --- output projection ---
146
+ return self.out_proj(y) # [B, L, D]
147
+
148
+
149
+ # ===================================================================
150
+ # Mamba residual block: LayerNorm -> Mamba -> residual add
151
+ # ===================================================================
152
+ class MambaResidualBlock(nn.Module):
153
+ """
154
+ Pre-norm residual block wrapping a Mamba layer.
155
+
156
+ Interface: [B, L, D] -> [B, L, D]
157
+ Uses the CUDA Mamba kernel when available, otherwise falls back to
158
+ PurePytorchMamba.
159
+ """
160
+
161
+ def __init__(self, d_model: int = 128, d_state: int = 16,
162
+ d_conv: int = 4, expand: int = 2):
163
+ super().__init__()
164
+ self.norm = nn.LayerNorm(d_model)
165
+ if HAS_MAMBA_SSM and CudaMamba is not None:
166
+ self.mamba = CudaMamba(
167
+ d_model=d_model, d_state=d_state,
168
+ d_conv=d_conv, expand=expand,
169
+ )
170
+ else:
171
+ self.mamba = PurePytorchMamba(
172
+ d_model=d_model, d_state=d_state,
173
+ d_conv=d_conv, expand=expand,
174
+ )
175
+
176
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
177
+ return x + self.mamba(self.norm(x))
178
+
179
+
180
+ # ===================================================================
181
+ # MambaDLocNet - full end-to-end model
182
+ # ===================================================================
183
+ class MambaDLocNet(nn.Module):
184
+ """
185
+ Mamba-DLoc: CNN stem -> Mamba sequence blocks -> CNN decoder.
186
+
187
+ Input: [B, 4, 161, 361]
188
+ Output: [B, 1, 161, 361]
189
+ """
190
+
191
+ # Spatial sizes at each resolution level (full, mid, low)
192
+ SPATIAL_SIZES = [(161, 361), (81, 181), (41, 91)]
193
+
194
+ def __init__(self, input_nc: int = 4, d_model: int = 128,
195
+ n_mamba_blocks: int = 4,
196
+ d_state: int = 16, d_conv: int = 4, expand: int = 2):
197
+ super().__init__()
198
+ self.d_model = d_model
199
+
200
+ # ------ CNN Stem (encoder) ------
201
+ self.stem = nn.Sequential(
202
+ # [B,input_nc,161,361] -> [B,32,161,361]
203
+ nn.Conv2d(input_nc, 32, kernel_size=3, stride=1, padding=1, bias=False),
204
+ nn.BatchNorm2d(32),
205
+ nn.ReLU(inplace=True),
206
+ # [B,32,161,361] -> [B,64,81,181]
207
+ nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1, bias=False),
208
+ nn.BatchNorm2d(64),
209
+ nn.ReLU(inplace=True),
210
+ # [B,64,81,181] -> [B,128,41,91]
211
+ nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=False),
212
+ nn.BatchNorm2d(128),
213
+ nn.ReLU(inplace=True),
214
+ )
215
+
216
+ # ------ Mamba sequence blocks ------
217
+ self.mamba_blocks = nn.Sequential(*[
218
+ MambaResidualBlock(d_model=d_model, d_state=d_state,
219
+ d_conv=d_conv, expand=expand)
220
+ for _ in range(n_mamba_blocks)
221
+ ])
222
+
223
+ # ------ CNN Decoder ------
224
+ # Stage 1: [B,128,41,91] -> interpolate to (81,181) -> conv 128->64
225
+ self.dec_conv1 = nn.Sequential(
226
+ nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1, bias=False),
227
+ nn.BatchNorm2d(64),
228
+ nn.ReLU(inplace=True),
229
+ )
230
+ # Stage 2: [B,64,81,181] -> interpolate to (161,361) -> conv 64->32
231
+ self.dec_conv2 = nn.Sequential(
232
+ nn.Conv2d(64, 32, kernel_size=3, stride=1, padding=1, bias=False),
233
+ nn.BatchNorm2d(32),
234
+ nn.ReLU(inplace=True),
235
+ )
236
+ # Stage 3: 1x1 head -> sigmoid
237
+ self.dec_head = nn.Sequential(
238
+ nn.Conv2d(32, 1, kernel_size=1, bias=True),
239
+ nn.Sigmoid(),
240
+ )
241
+
242
+ # ---------------------------------------------------------------
243
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
244
+ """
245
+ x : [B, 4, 161, 361]
246
+ returns : [B, 1, 161, 361]
247
+ """
248
+ B = x.size(0)
249
+
250
+ # --- CNN Stem ---
251
+ feat = self.stem(x) # [B, 128, 41, 91]
252
+
253
+ # --- Tokenize: flatten spatial dims into sequence ---
254
+ _, C, H, W = feat.shape
255
+ tokens = feat.reshape(B, C, H * W).permute(0, 2, 1) # [B, 3731, 128]
256
+
257
+ # --- Mamba blocks ---
258
+ tokens = self.mamba_blocks(tokens) # [B, 3731, 128]
259
+
260
+ # --- Reshape back to spatial ---
261
+ feat = tokens.permute(0, 2, 1).reshape(B, C, H, W) # [B, 128, 41, 91]
262
+
263
+ # --- CNN Decoder ---
264
+ feat = F.interpolate(feat, size=self.SPATIAL_SIZES[1],
265
+ mode='bilinear', align_corners=False) # [B,128,81,181]
266
+ feat = self.dec_conv1(feat) # [B,64,81,181]
267
+
268
+ feat = F.interpolate(feat, size=self.SPATIAL_SIZES[0],
269
+ mode='bilinear', align_corners=False) # [B,64,161,361]
270
+ feat = self.dec_conv2(feat) # [B,32,161,361]
271
+
272
+ out = self.dec_head(feat) # [B,1,161,361]
273
+ return out
modelADT.py ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ '''
3
+ Defines a generic wrapper class for all the network models
4
+ Utilizes params.py to create, initiate, load and train the network.
5
+ '''
6
+ import torch
7
+ import numpy as np
8
+ from collections import OrderedDict
9
+ import scipy.io
10
+ from torch.autograd import Variable
11
+ import os
12
+ from Generators import *
13
+ from utils import *
14
+
15
+ class ModelADT():
16
+ def name(self):
17
+ return 'Pix2PixModel'
18
+
19
+ def initialize(self, opt):
20
+
21
+ self.opt = opt
22
+ # self.gpu_ids = opt.gpu_ids
23
+ gpu_ids = []
24
+ for i in range(torch.cuda.device_count()):
25
+ gpu_ids.append(str(i))
26
+ print(gpu_ids)
27
+ self.gpu_ids = gpu_ids
28
+ self.isTrain = opt.isTrain
29
+ self.loss_weight = opt.lambda_L
30
+ self.reg_loss_weight = opt.lambda_reg
31
+ self.cross_loss_weight = opt.lambda_cross
32
+ self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) # if self.gpu_ids else torch.device('cpu')
33
+
34
+ print(self.device)
35
+ self.model_name = self.opt.name
36
+ self.save_dir = os.path.join(self.opt.checkpoints_save_dir, self.model_name)
37
+ self.load_dir = os.path.join(self.opt.checkpoints_load_dir, self.model_name)
38
+ self.results_save_dir = opt.results_dir
39
+
40
+ self.loss_names = []
41
+ self.visual_names = []
42
+ self.image_paths = []
43
+
44
+ self.loss_names = ['loss_criterion']
45
+ self.visual_names = ['output']
46
+
47
+
48
+ self.net = get_model_funct(self.opt.net)(self.opt, self.gpu_ids)
49
+ self.net = self.net.to(self.device)
50
+
51
+ if self.isTrain:
52
+ if self.opt.loss_type == "L2":
53
+ self.loss_criterion = torch.nn.MSELoss()
54
+ elif self.opt.loss_type == "L1":
55
+ self.loss_criterion = torch.nn.L1Loss()
56
+ elif self.opt.loss_type == "L1_sumL2":
57
+ self.loss_criterion = torch.nn.L1Loss()
58
+ elif self.opt.loss_type == "L2_sumL2":
59
+ self.loss_criterion = torch.nn.MSELoss()
60
+ elif self.opt.loss_type == "L2_sumL1":
61
+ self.loss_criterion = torch.nn.MSELoss()
62
+ elif self.opt.loss_type == "L2_offset_loss":
63
+ self.loss_criterion = torch.nn.MSELoss()
64
+ elif self.opt.loss_type == "L1_offset_loss":
65
+ self.loss_criterion = torch.nn.L1Loss()
66
+ elif self.opt.loss_type == "L1_sumL2_cross":
67
+ self.loss_criterion = torch.nn.MSELoss()
68
+ elif self.opt.loss_type == "L2_sumL2_cross":
69
+ self.loss_criterion = torch.nn.MSELoss()
70
+ self.cross_loss_criterion = torch.nn.NLLLoss()
71
+
72
+ # initialize optimizers
73
+ self.optimizers = []
74
+ self.optimizer = torch.optim.Adam(self.net.parameters(),lr=opt.lr, betas=(opt.beta1, 0.999), weight_decay=opt.weight_decay)
75
+ self.optimizers.append(self.optimizer)
76
+
77
+ # load and print networks; create schedulers
78
+ def setup(self, opt, parser=None):
79
+ if self.isTrain:
80
+ self.schedulers = [get_scheduler(optimizer, opt) for optimizer in self.optimizers]
81
+
82
+ if not self.isTrain or opt.continue_train:
83
+ self.load_networks(opt.starting_epoch_count)
84
+ if self.isTrain and opt.continue_train:
85
+ self.load_training_state(opt.starting_epoch_count)
86
+ self.print_networks(opt.verbose)
87
+
88
+ # make models eval mode during test time
89
+ def eval(self):
90
+ self.net.eval()
91
+
92
+ # used in test time, wrapping `forward` in no_grad() so we don't save
93
+ # intermediate steps for backprop
94
+ def test(self):
95
+ with torch.no_grad():
96
+ self.forward()
97
+
98
+ def save_outputs(self):
99
+ if not os.path.exists(self.results_save_dir):
100
+ os.makedirs(self.results_save_dir, exist_ok=True)
101
+ to_save_dict = {}
102
+ for tensor in self.visual_names:
103
+ tensor_val = getattr(self, tensor).data.cpu().numpy()
104
+ to_save_dict[tensor] = tensor_val
105
+ scipy.io.savemat(self.results_save_dir+".mat", mdict=to_save_dict)
106
+
107
+
108
+ # update learning rate (called once every epoch)
109
+ def update_learning_rate(self):
110
+ for scheduler in self.schedulers:
111
+ scheduler.step()
112
+ lr = self.optimizers[0].param_groups[0]['lr']
113
+ print('learning rate = %.7f' % lr)
114
+
115
+ # return visualization images. train.py will display these images, and save the images to a html
116
+ def get_current_visuals(self):
117
+ visual_ret = OrderedDict()
118
+ for name in self.visual_names:
119
+ if isinstance(name, str):
120
+ visual_ret[name] = getattr(self, name)
121
+ return visual_ret
122
+
123
+ # return traning losses/errors. train.py will print out these errors as debugging information
124
+ def get_current_losses(self):
125
+ errors_ret = OrderedDict()
126
+ for name in self.loss_names:
127
+ if isinstance(name, str):
128
+ # float(...) works for both scalar tensor and float number
129
+ errors_ret[name] = float(getattr(self, 'loss_' + name))
130
+ return errors_ret
131
+
132
+ # save models to the disk
133
+ def save_networks(self, epoch):
134
+ name = self.model_name
135
+ save_filename = '%s_net_%s.pth' % (epoch, name)
136
+ if not os.path.exists(self.save_dir):
137
+ os.makedirs(self.save_dir)
138
+ save_path = os.path.join(self.save_dir, save_filename)
139
+ net = self.net
140
+ print(save_path)
141
+ print('net'+name)
142
+ if len(self.gpu_ids) > 0 and torch.cuda.is_available() and hasattr(net, 'module'):
143
+ torch.save(net.module.cpu().state_dict(), save_path)
144
+ else:
145
+ torch.save(net.cpu().state_dict(), save_path)
146
+ net.to(self.device)
147
+
148
+ # save optimizer, scheduler, and RNG state
149
+ if self.isTrain:
150
+ optim_filename = '%s_optim_%s.pth' % (epoch, self.model_name)
151
+ optim_path = os.path.join(self.save_dir, optim_filename)
152
+ save_dict = {
153
+ 'optimizer': self.optimizer.state_dict(),
154
+ 'scheduler': self.schedulers[0].state_dict() if self.schedulers else None,
155
+ 'rng_torch': torch.random.get_rng_state(),
156
+ 'rng_numpy': np.random.get_state(),
157
+ }
158
+ if torch.cuda.is_available():
159
+ save_dict['rng_cuda'] = torch.cuda.get_rng_state_all()
160
+ torch.save(save_dict, optim_path)
161
+
162
+ def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0):
163
+ key = keys[i]
164
+ if i + 1 == len(keys): # at the end, pointing to a parameter/buffer
165
+ if module.__class__.__name__.startswith('InstanceNorm') and (key == 'running_mean' or key == 'running_var'):
166
+ if getattr(module, key) is None:
167
+ state_dict.pop('.'.join(keys))
168
+ if module.__class__.__name__.startswith('InstanceNorm') and (key == 'num_batches_tracked'):
169
+ state_dict.pop('.'.join(keys))
170
+ else:
171
+ self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1)
172
+
173
+ # load models from the disk
174
+ def load_networks(self, epoch, load_dir=""):
175
+ """
176
+ epoch (int/str): epoch index / "best" / "latest"
177
+ """
178
+ assert isinstance(epoch,int) or epoch=="best" or epoch=="latest"
179
+ load_filename = f'{epoch}_net_{self.model_name}.pth'
180
+
181
+ if load_dir:
182
+ # use given load dir
183
+ load_path = os.path.join(load_dir, self.model_name, load_filename)
184
+ else:
185
+ # use default load dir
186
+ load_path = os.path.join(self.load_dir, load_filename)
187
+
188
+ net = self.net
189
+ if isinstance(net, torch.nn.DataParallel):
190
+ net = net.module
191
+ print('loading the model from %s' % load_path)
192
+ # if you are using PyTorch newer than 0.4 (e.g., built from
193
+ # GitHub source), you can remove str() on self.device
194
+ state_dict = torch.load(load_path, weights_only=False)
195
+ if hasattr(state_dict, '_metadata'):
196
+ del state_dict._metadata
197
+
198
+ # patch InstanceNorm checkpoints prior to 0.4
199
+ print(state_dict.keys())
200
+ for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop
201
+ self.__patch_instance_norm_state_dict(state_dict, net, key.split('.'))
202
+ net.load_state_dict(state_dict)
203
+ net = net.to(self.device)
204
+
205
+ # load optimizer and scheduler state from disk
206
+ def load_training_state(self, epoch):
207
+ optim_filename = f'{epoch}_optim_{self.model_name}.pth'
208
+ load_path = os.path.join(self.load_dir, optim_filename)
209
+ if os.path.exists(load_path):
210
+ print(f'loading optimizer/scheduler from {load_path}')
211
+ state = torch.load(load_path, weights_only=False)
212
+ self.optimizer.load_state_dict(state['optimizer'])
213
+ if state.get('scheduler') and self.schedulers:
214
+ self.schedulers[0].load_state_dict(state['scheduler'])
215
+ # Restore RNG states for session continuity
216
+ if 'rng_torch' in state:
217
+ torch.random.set_rng_state(state['rng_torch'])
218
+ if 'rng_numpy' in state:
219
+ np.random.set_state(state['rng_numpy'])
220
+ if 'rng_cuda' in state and torch.cuda.is_available():
221
+ torch.cuda.set_rng_state_all(state['rng_cuda'])
222
+ else:
223
+ print(f'No optimizer state found at {load_path}, starting fresh')
224
+
225
+ # print network information
226
+ def print_networks(self, verbose):
227
+ print('---------- Networks initialized -------------')
228
+ net = self.net
229
+ name = self.model_name
230
+ num_params = 0
231
+ for param in net.parameters():
232
+ num_params += param.numel()
233
+ if verbose:
234
+ print(net)
235
+ print('[Network %s] Total number of parameters : %.3f M' % (name, num_params / 1e6))
236
+ print('-----------------------------------------------')
237
+
238
+ # set requies_grad=Fasle to avoid computation
239
+ def set_requires_grad(self, nets, requires_grad=False):
240
+ if not isinstance(nets, list):
241
+ nets = [nets]
242
+ for net in nets:
243
+ if net is not None:
244
+ for param in net.parameters():
245
+ param.requires_grad = requires_grad
246
+
247
+ # Set the input and target data for the network to train on/evaluate against
248
+ def set_data(self, input, target, convert=False, shuffle_channel=False):
249
+ shape_in = input.shape
250
+ if shuffle_channel:
251
+ self.input = input[:,torch.randperm(shape_in[1]),:,:]
252
+ else:
253
+ self.input = input
254
+ self.target = target
255
+ if convert:
256
+ self.input, self.target = Variable(self.input), Variable(self.target)
257
+
258
+ self.input = self.input.to(self.device)
259
+ self.target = self.target.to(self.device)
260
+
261
+ # Define the forward pass to compute loss
262
+ def forward(self):
263
+ self.output = self.net(self.input)
264
+ if self.opt.loss_type != "NoLoss":
265
+ self.loss = self.loss_weight*self.loss_criterion(self.output, self.target)
266
+
267
+ if self.opt.loss_type == "L1_sumL2" or self.opt.loss_type == "L2_sumL2":
268
+ self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
269
+ self.reg_loss = self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
270
+
271
+ if self.opt.loss_type == "L2_sumL1":
272
+ self.loss += self.reg_loss_weight*torch.norm(self.output,p=1).div(self.output.numel())
273
+ self.reg_loss = self.reg_loss_weight*torch.norm(self.output,p=1).div(self.output.numel())
274
+
275
+ if self.opt.loss_type == "L1_sumL2_cross" or self.opt.loss_type == "L2_sumL2_cross":
276
+ self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
277
+ self.loss += self.cross_loss_weight*self.cross_loss_criterion(self.output.flatten(start_dim=1),self.target.flatten(start_dim=1))
278
+
279
+ if self.opt.loss_type == "L1_offset_loss" or self.opt.loss_type == "L2_offset_loss":
280
+ self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
281
+
282
+ def backward(self):
283
+ self.loss.backward(retain_graph=True)
284
+
285
+ def optimize_parameters(self):
286
+ self.forward()
287
+ self.backward()
288
+ self.optimizer.step()
289
+ self.optimizer.zero_grad()
params.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from params_storage.params_fig10b_single_gpu import *
params_storage/__init__.py ADDED
File without changes
params_storage/params_fig10b_single_gpu.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # params_fig10b_single_gpu.py
2
+ # ===========================
3
+ # Reproduces Fig 10b from the paper:
4
+ # Complex environment - Jacobs Hall, July 28 + July 28_2, 4 APs
5
+ # Target: median ~64 cm, 90th ~160 cm
6
+ #
7
+ # Adapted for single GPU (RTX 3060 6GB) with batch_size=8.
8
+ # To use: copy this file to ../params.py
9
+ # cp params_storage/params_fig10b_single_gpu.py params.py
10
+ # Then run: python train_and_test.py
11
+ #
12
+ # Required data files in ./data/:
13
+ # dataset_jacobs_July28.mat
14
+ # dataset_fov_train_jacobs_July28_2.mat
15
+ # dataset_non_fov_train_jacobs_July28_2.mat
16
+ # dataset_fov_test_jacobs_July28_2.mat
17
+ # dataset_non_fov_test_jacobs_July28_2.mat
18
+ # (Generate these with: python prepare_data.py)
19
+
20
+ from easydict import EasyDict as edict
21
+ import time
22
+ from os.path import join
23
+
24
+ opt_exp = edict()
25
+
26
+ # ---------- Global Experiment params ----------
27
+ opt_exp.isTrain = True
28
+ opt_exp.continue_train = False
29
+ opt_exp.starting_epoch_count = 0
30
+ opt_exp.n_epochs = 50
31
+ opt_exp.gpu_ids = ['0'] # Single GPU
32
+ opt_exp.data = "rw_to_rw" # Jacobs Hall complex env
33
+ opt_exp.n_decoders = 2 # Encoder + location decoder + consistency decoder
34
+
35
+ opt_exp.batch_size = 8 # Reduced from 32 for 6 GB VRAM
36
+ opt_exp.ds_step_trn = 1
37
+ opt_exp.ds_step_tst = 1
38
+ opt_exp.weight_decay = 1e-5
39
+ opt_exp.confidence = False
40
+
41
+ # ------ Experiment save paths ----------
42
+ opt_exp.save_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) # No colons - Windows safe
43
+ opt_exp.checkpoints_dir = join('./runs', opt_exp.save_name)
44
+ opt_exp.results_dir = opt_exp.checkpoints_dir
45
+ opt_exp.log_dir = opt_exp.checkpoints_dir
46
+ opt_exp.load_dir = opt_exp.checkpoints_dir
47
+
48
+ # ---------- Encoder params ----------
49
+ opt_encoder = edict()
50
+ opt_encoder.parent_exp = opt_exp
51
+ opt_encoder.batch_size = opt_encoder.parent_exp.batch_size
52
+ opt_encoder.ngf = 64
53
+ opt_encoder.base_model = 'resnet_encoder'
54
+ opt_encoder.net = 'G'
55
+ opt_encoder.resnet_blocks = 6
56
+ opt_encoder.no_dropout = False
57
+ opt_encoder.init_type = 'xavier'
58
+ opt_encoder.init_gain = 0.02
59
+ opt_encoder.norm = 'instance'
60
+ opt_encoder.beta1 = 0.5
61
+ opt_encoder.lr = 0.00001
62
+ opt_encoder.lr_policy = 'step'
63
+ opt_encoder.lr_decay_iters = 50
64
+ opt_encoder.lambda_L = 1
65
+ opt_encoder.lambda_cross = 1e-5
66
+ opt_encoder.lambda_reg = 5e-4
67
+ opt_encoder.weight_decay = opt_encoder.parent_exp.weight_decay
68
+
69
+ opt_encoder.input_nc = 4 # 4 APs in Jacobs Hall
70
+ opt_encoder.output_nc = 1
71
+ opt_encoder.save_latest_freq = 5000
72
+ opt_encoder.save_epoch_freq = 1
73
+ opt_encoder.n_epochs = opt_encoder.parent_exp.n_epochs
74
+ opt_encoder.isTrain = True
75
+ opt_encoder.continue_train = False
76
+ opt_encoder.starting_epoch_count = opt_encoder.parent_exp.starting_epoch_count
77
+ opt_encoder.name = 'encoder'
78
+ opt_encoder.loss_type = "NoLoss"
79
+ opt_encoder.niter = 20
80
+ opt_encoder.niter_decay = 100
81
+
82
+ opt_encoder.gpu_ids = opt_encoder.parent_exp.gpu_ids
83
+ opt_encoder.num_threads = 4
84
+ opt_encoder.checkpoints_load_dir = opt_encoder.parent_exp.load_dir
85
+ opt_encoder.checkpoints_save_dir = opt_encoder.parent_exp.checkpoints_dir
86
+ opt_encoder.results_dir = opt_encoder.parent_exp.results_dir
87
+ opt_encoder.log_dir = opt_encoder.parent_exp.log_dir
88
+ opt_encoder.max_dataset_size = float("inf")
89
+ opt_encoder.verbose = False
90
+ opt_encoder.suffix = ''
91
+
92
+ # ---------- Location Decoder params ----------
93
+ opt_decoder = edict()
94
+ opt_decoder.parent_exp = opt_exp
95
+ opt_decoder.batch_size = opt_decoder.parent_exp.batch_size
96
+ opt_decoder.ngf = 64
97
+ opt_decoder.base_model = 'resnet_decoder'
98
+ opt_decoder.net = 'G'
99
+ opt_decoder.resnet_blocks = 9
100
+ opt_decoder.encoder_res_blocks = 6
101
+ opt_decoder.no_dropout = False
102
+ opt_decoder.init_type = 'xavier'
103
+ opt_decoder.init_gain = 0.02
104
+ opt_decoder.norm = 'instance'
105
+ opt_decoder.beta1 = 0.5
106
+ opt_decoder.lr = opt_encoder.lr
107
+ opt_decoder.lr_policy = 'step'
108
+ opt_decoder.lr_decay_iters = 20
109
+ opt_decoder.lambda_L = 1
110
+ opt_decoder.lambda_cross = 1e-5
111
+ opt_decoder.lambda_reg = 5e-4
112
+ opt_decoder.weight_decay = opt_decoder.parent_exp.weight_decay
113
+
114
+ opt_decoder.input_nc = 4 # 4 APs
115
+ opt_decoder.output_nc = 1 # 1-channel location heatmap
116
+ opt_decoder.save_latest_freq = 5000
117
+ opt_decoder.save_epoch_freq = 1
118
+ opt_decoder.n_epochs = opt_decoder.parent_exp.n_epochs
119
+ opt_decoder.isTrain = True
120
+ opt_decoder.continue_train = False
121
+ opt_decoder.starting_epoch_count = opt_decoder.parent_exp.starting_epoch_count
122
+ opt_decoder.name = 'decoder'
123
+ opt_decoder.loss_type = "L2_sumL1"
124
+ opt_decoder.niter = 20
125
+ opt_decoder.niter_decay = 100
126
+
127
+ opt_decoder.gpu_ids = opt_decoder.parent_exp.gpu_ids
128
+ opt_decoder.num_threads = 4
129
+ opt_decoder.checkpoints_load_dir = opt_decoder.parent_exp.load_dir
130
+ opt_decoder.checkpoints_save_dir = opt_decoder.parent_exp.checkpoints_dir
131
+ opt_decoder.results_dir = opt_decoder.parent_exp.results_dir
132
+ opt_decoder.log_dir = opt_decoder.parent_exp.log_dir
133
+ opt_decoder.verbose = False
134
+ opt_decoder.suffix = ''
135
+
136
+ # ---------- Consistency (Offset) Decoder params ----------
137
+ opt_offset_decoder = edict()
138
+ opt_offset_decoder.parent_exp = opt_exp
139
+ opt_offset_decoder.batch_size = opt_offset_decoder.parent_exp.batch_size
140
+ opt_offset_decoder.ngf = 64
141
+ opt_offset_decoder.base_model = 'resnet_decoder'
142
+ opt_offset_decoder.net = 'G'
143
+ opt_offset_decoder.resnet_blocks = 12
144
+ opt_offset_decoder.encoder_res_blocks = 6
145
+ opt_offset_decoder.no_dropout = False
146
+ opt_offset_decoder.init_type = 'xavier'
147
+ opt_offset_decoder.init_gain = 0.02
148
+ opt_offset_decoder.norm = 'instance'
149
+ opt_offset_decoder.beta1 = 0.5
150
+ opt_offset_decoder.lr = opt_encoder.lr
151
+ opt_offset_decoder.lr_policy = 'step'
152
+ opt_offset_decoder.lr_decay_iters = 50
153
+ opt_offset_decoder.lambda_L = 1
154
+ opt_offset_decoder.lambda_cross = 0
155
+ opt_offset_decoder.lambda_reg = 0
156
+ opt_offset_decoder.weight_decay = opt_offset_decoder.parent_exp.weight_decay
157
+
158
+ opt_offset_decoder.input_nc = 4 # 4 APs
159
+ opt_offset_decoder.output_nc = 4 # 4-channel consistency output
160
+ opt_offset_decoder.save_latest_freq = 5000
161
+ opt_offset_decoder.save_epoch_freq = 1
162
+ opt_offset_decoder.n_epochs = opt_offset_decoder.parent_exp.n_epochs
163
+ opt_offset_decoder.isTrain = True
164
+ opt_offset_decoder.continue_train = False
165
+ opt_offset_decoder.starting_epoch_count = opt_offset_decoder.parent_exp.starting_epoch_count
166
+ opt_offset_decoder.name = 'offset_decoder'
167
+ opt_offset_decoder.loss_type = "L2_offset_loss"
168
+ opt_offset_decoder.niter = 20
169
+ opt_offset_decoder.niter_decay = 100
170
+
171
+ opt_offset_decoder.gpu_ids = opt_offset_decoder.parent_exp.gpu_ids
172
+ opt_offset_decoder.num_threads = 4
173
+ opt_offset_decoder.checkpoints_load_dir = opt_offset_decoder.parent_exp.load_dir
174
+ opt_offset_decoder.checkpoints_save_dir = opt_offset_decoder.parent_exp.checkpoints_dir
175
+ opt_offset_decoder.results_dir = opt_offset_decoder.parent_exp.results_dir
176
+ opt_offset_decoder.log_dir = opt_offset_decoder.parent_exp.log_dir
177
+ opt_offset_decoder.verbose = False
178
+ opt_offset_decoder.suffix = ''
params_storage/params_mamba_single_gpu.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # params_mamba_single_gpu.py
2
+ # ===========================
3
+ # Mamba-DLoc: replaces ResNet bottleneck with Mamba SSM blocks.
4
+ # Single decoder (location only, no consistency decoder).
5
+ #
6
+ # To use: copy this file to ../params.py
7
+ # cp params_storage/params_mamba_single_gpu.py params.py
8
+ # Then run: python train_and_test.py
9
+ #
10
+ # Required data files in ./data/ (same as Fig 10b):
11
+ # dataset_jacobs_July28.mat (must be the FIXED 7,635-sample version)
12
+ # dataset_fov_train_jacobs_July28_2.mat
13
+ # dataset_non_fov_train_jacobs_July28_2.mat
14
+ # dataset_fov_test_jacobs_July28_2.mat
15
+ # dataset_non_fov_test_jacobs_July28_2.mat
16
+
17
+ from easydict import EasyDict as edict
18
+ import time
19
+ from os.path import join
20
+
21
+ opt_exp = edict()
22
+
23
+ # ---------- Global Experiment params ----------
24
+ opt_exp.isTrain = True
25
+ opt_exp.continue_train = False
26
+ opt_exp.starting_epoch_count = 0
27
+ opt_exp.n_epochs = 50
28
+ opt_exp.gpu_ids = ['0']
29
+ opt_exp.data = "rw_to_rw" # Same Jacobs Hall dataset as Fig 10b
30
+ opt_exp.n_decoders = 1 # Single decoder (location only)
31
+ opt_exp.model_type = "mamba" # Selects Mamba pipeline in train_and_test.py
32
+
33
+ opt_exp.batch_size = 8
34
+ opt_exp.ds_step_trn = 1
35
+ opt_exp.ds_step_tst = 1
36
+ opt_exp.weight_decay = 1e-5
37
+ opt_exp.confidence = False
38
+
39
+ # ------ Experiment save paths ----------
40
+ opt_exp.save_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
41
+ opt_exp.checkpoints_dir = join('./runs', opt_exp.save_name)
42
+ opt_exp.results_dir = opt_exp.checkpoints_dir
43
+ opt_exp.log_dir = opt_exp.checkpoints_dir
44
+ opt_exp.load_dir = opt_exp.checkpoints_dir
45
+
46
+ # ---------- Mamba model params (single model, acts as both encoder+decoder) ----------
47
+ opt_mamba = edict()
48
+ opt_mamba.parent_exp = opt_exp
49
+ opt_mamba.batch_size = opt_exp.batch_size
50
+ opt_mamba.ngf = 64
51
+ opt_mamba.base_model = 'mamba_dloc'
52
+ opt_mamba.net = 'G'
53
+ opt_mamba.no_dropout = False
54
+ opt_mamba.init_type = 'xavier'
55
+ opt_mamba.init_gain = 0.02
56
+ opt_mamba.norm = 'batch'
57
+ opt_mamba.beta1 = 0.5
58
+ opt_mamba.lr = 0.00001
59
+ opt_mamba.lr_policy = 'step'
60
+ opt_mamba.lr_decay_iters = 20
61
+ opt_mamba.lambda_L = 1
62
+ opt_mamba.lambda_cross = 0
63
+ opt_mamba.lambda_reg = 5e-4
64
+ opt_mamba.weight_decay = opt_exp.weight_decay
65
+
66
+ opt_mamba.input_nc = 4
67
+ opt_mamba.output_nc = 1
68
+ opt_mamba.save_latest_freq = 5000
69
+ opt_mamba.save_epoch_freq = 1
70
+ opt_mamba.n_epochs = opt_exp.n_epochs
71
+ opt_mamba.isTrain = True
72
+ opt_mamba.continue_train = False
73
+ opt_mamba.starting_epoch_count = opt_exp.starting_epoch_count
74
+ opt_mamba.name = 'mamba_dloc'
75
+ opt_mamba.loss_type = "L2_sumL1"
76
+ opt_mamba.niter = 20
77
+ opt_mamba.niter_decay = 100
78
+
79
+ opt_mamba.gpu_ids = opt_exp.gpu_ids
80
+ opt_mamba.num_threads = 4
81
+ opt_mamba.checkpoints_load_dir = opt_exp.load_dir
82
+ opt_mamba.checkpoints_save_dir = opt_exp.checkpoints_dir
83
+ opt_mamba.results_dir = opt_exp.results_dir
84
+ opt_mamba.log_dir = opt_exp.log_dir
85
+ opt_mamba.max_dataset_size = float("inf")
86
+ opt_mamba.verbose = False
87
+ opt_mamba.suffix = ''
88
+
89
+ # ---------- Aliases for train_and_test.py compatibility ----------
90
+ opt_encoder = opt_mamba
91
+ opt_decoder = opt_mamba
92
+ opt_offset_decoder = opt_mamba
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ easydict>=1.9
2
+ h5py>=3.1.0
3
+ hdf5storage>=0.1.15
4
+ numpy>=1.21.0
5
+ scipy>=1.7.0
6
+ scikit-learn
train_and_test.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ '''
3
+ Script for both training and evaluating the DLoc network
4
+ Automatically imports the parameters from params.py.
5
+ For further details onto which params file to load
6
+ read the README in `params_storage` folder.
7
+ '''
8
+ import sys
9
+ import torch
10
+ import warnings
11
+ with warnings.catch_warnings():
12
+ warnings.filterwarnings("ignore",category=FutureWarning)
13
+ from utils import *
14
+ from modelADT import ModelADT
15
+ from Generators import *
16
+ from data_loader import load_data, LazyMultiHDF5Dataset
17
+ from joint_model import Enc_2Dec_Network
18
+ from joint_model import Enc_Dec_Network
19
+ from joint_model import Mamba_Network
20
+ from params import *
21
+ import trainer
22
+ torch.manual_seed(0)
23
+ np.random.seed(0)
24
+
25
+ '''
26
+ Defining the paths from where to Load Data.
27
+ Assumes that the data is stored in a subfolder called data in the current data folder
28
+ '''
29
+
30
+ #####################################Final Simple Space Results################################################
31
+ if "data" in opt_exp and opt_exp.data == "rw_to_rw_atk":
32
+ # Training and testing data loaded for the Final results For Env-1 (The smaller space) in the paper (Figure 10a)
33
+ trainpath = ['./data/dataset_non_fov_train_July18.mat',
34
+ './data/dataset_fov_train_July18.mat']
35
+ testpath = ['./data/dataset_non_fov_test_July18.mat',
36
+ './data/dataset_fov_test_July18.mat']
37
+ print('Real World to Real World experiments started')
38
+
39
+ #####################################Final Complex Space Results################################################
40
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw":
41
+ # Training and testing data loaded for the Final results For Env-2 (The larger space) in the paper (Figure 10b)
42
+ trainpath = ['./data/dataset_jacobs_July28.mat',
43
+ './data/dataset_non_fov_train_jacobs_July28_2.mat',
44
+ './data/dataset_fov_train_jacobs_July28_2.mat']
45
+ testpath = ['./data/dataset_fov_test_jacobs_July28_2.mat',
46
+ './data/dataset_non_fov_test_jacobs_July28_2.mat']
47
+ print('Real World to Real World experiments started')
48
+
49
+ #########################################Generalization across Scenarios###########################################
50
+
51
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw_env2":
52
+ # Training and testing data loaded for the Final results For Env-2
53
+ # for Generalization across scenarios (Table-1) train on 1/3/4 and test on 2
54
+ trainpath = ['./data/dataset_jacobs_July28.mat',
55
+ './data/dataset_non_fov_train_jacobs_July28_2.mat',
56
+ './data/dataset_fov_train_jacobs_July28_2.mat',
57
+ './data/dataset_train_jacobs_Aug16_3.mat',
58
+ './data/dataset_train_jacobs_Aug16_4_ref.mat']
59
+ testpath = ['./data/dataset_train_jacobs_Aug16_1.mat']
60
+ print('Real World to Real World experiments started')
61
+
62
+
63
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw_env3":
64
+ # Training and testing data loaded for the Final results For Env-2
65
+ # for Generalization across scenarios (Table-1) train on 1/2/4 and test on 3
66
+ trainpath = ['./data/dataset_jacobs_July28.mat',
67
+ './data/dataset_non_fov_train_jacobs_July28_2.mat',
68
+ './data/dataset_fov_train_jacobs_July28_2.mat',
69
+ './data/dataset_train_jacobs_Aug16_1.mat',
70
+ './data/dataset_train_jacobs_Aug16_4_ref.mat']
71
+ testpath = ['./data/dataset_train_jacobs_Aug16_3.mat']
72
+ print('Real World to Real World experiments started')
73
+
74
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw_env4":
75
+ # Training and testing data loaded for the Final results For Env-2
76
+ # for Generalization across scenarios (Table-1) train on 1/2/3 and test on 4
77
+ trainpath = ['./data/dataset_jacobs_July28.mat',
78
+ './data/dataset_non_fov_train_jacobs_July28_2.mat',
79
+ './data/dataset_fov_train_jacobs_July28_2.mat',
80
+ './data/dataset_train_jacobs_Aug16_1.mat',
81
+ './data/dataset_train_jacobs_Aug16_3.mat']
82
+ testpath = ['./data/dataset_train_jacobs_Aug16_4_ref.mat']
83
+ print('Real World to Real World experiments started')
84
+
85
+ ######################################Generalization Across Bandwidth##########################################
86
+
87
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw_40":
88
+ # Training and testing data loaded for the Generalization results For Env-2 (The larger space) in the paper (Figure 13a) at 40MHz
89
+ trainpath = ['./data/dataset40_jacobs_July28.mat',
90
+ './data/dataset40_non_fov_train_jacobs_July28_2.mat',
91
+ './data/dataset40_fov_train_jacobs_July28_2.mat']
92
+ testpath = ['./data/dataset40_fov_test_jacobs_July28_2.mat',
93
+ './data/dataset40_non_fov_test_jacobs_July28_2.mat']
94
+ print('Real World to Real World experiments started')
95
+
96
+ elif "data" in opt_exp and opt_exp.data == "rw_to_rw_20":
97
+ # Training and testing data loaded for the Generalization results For Env-2 (The larger space) in the paper (Figure 13a) at 20MHz
98
+ trainpath = ['./data/dataset20_jacobs_July28.mat',
99
+ './data/dataset20_non_fov_train_jacobs_July28_2.mat',
100
+ './data/dataset20_fov_train_jacobs_July28_2.mat']
101
+ testpath = ['./data/dataset20_fov_test_jacobs_July28_2.mat',
102
+ './data/dataset20_non_fov_test_jacobs_July28_2.mat']
103
+ print('Real World to Real World experiments started')
104
+
105
+ ######################################Generalization Across Space##########################################
106
+
107
+ elif "data" in opt_exp and opt_exp.data == "data_segment":
108
+ # Training and testing data loaded for the Final results For Env-2
109
+ # for Disjoint Training and Testing(The larger space) in the paper (Figure 13b)
110
+ trainpath = ['./data/dataset_train_jacobs_July28.mat',
111
+ './data/dataset_train_jacobs_July28_2.mat']
112
+ testpath = ['./data/dataset_test_jacobs_July28.mat',
113
+ './data/dataset_test_jacobs_July28_2.mat']
114
+ print('non-FOV to non-FOV experiments started')
115
+
116
+ ######################################################################################################################
117
+ '''
118
+ Loading Training and Evaluation Data via lazy disk-backed Dataset.
119
+ Samples are read on demand from HDF5 files - uses ~0 RAM.
120
+ '''
121
+ print('Indexing training files (lazy, no data loaded into RAM)...')
122
+ train_data = LazyMultiHDF5Dataset(trainpath)
123
+ train_loader = torch.utils.data.DataLoader(
124
+ train_data, batch_size=opt_exp.batch_size, shuffle=True, num_workers=0)
125
+ print(f'# training samples = {len(train_data)}')
126
+ print(f'# training mini batch = {len(train_loader)}')
127
+
128
+ print('Indexing testing files...')
129
+ test_data = LazyMultiHDF5Dataset(testpath)
130
+ test_loader = torch.utils.data.DataLoader(
131
+ test_data, batch_size=opt_exp.batch_size, shuffle=False, num_workers=0)
132
+ print(f'# testing samples = {len(test_data)}')
133
+ print(f'# testing mini batch = {len(test_loader)}')
134
+ print('Data Loaded (lazy)')
135
+
136
+ '''
137
+ Initiate the Network and build the graph
138
+ '''
139
+
140
+ model_type = getattr(opt_exp, 'model_type', 'dloc')
141
+
142
+ if model_type == 'mamba':
143
+ # Mamba: single end-to-end model wrapped in one ModelADT
144
+ from params import opt_mamba
145
+ mamba_model = ModelADT()
146
+ mamba_model.initialize(opt_mamba)
147
+ mamba_model.setup(opt_mamba)
148
+
149
+ print('Making the Mamba joint model')
150
+ joint_model = Mamba_Network()
151
+ joint_model.initialize(opt_exp, mamba_model, gpu_ids=opt_exp.gpu_ids)
152
+
153
+ else:
154
+ # Original DLoc pipeline
155
+ # init encoder
156
+ enc_model = ModelADT()
157
+ enc_model.initialize(opt_encoder)
158
+ enc_model.setup(opt_encoder)
159
+
160
+ # init decoder1
161
+ dec_model = ModelADT()
162
+ dec_model.initialize(opt_decoder)
163
+ dec_model.setup(opt_decoder)
164
+
165
+ if opt_exp.n_decoders == 2:
166
+ # init decoder2
167
+ offset_dec_model = ModelADT()
168
+ offset_dec_model.initialize(opt_offset_decoder)
169
+ offset_dec_model.setup(opt_offset_decoder)
170
+
171
+ # join all models
172
+ print('Making the joint_model')
173
+ joint_model = Enc_2Dec_Network()
174
+ joint_model.initialize(opt_exp, enc_model, dec_model, offset_dec_model, gpu_ids=opt_exp.gpu_ids)
175
+
176
+ elif opt_exp.n_decoders == 1:
177
+ # join all models
178
+ print('Making the joint_model')
179
+ joint_model = Enc_Dec_Network()
180
+ joint_model.initialize(opt_exp, enc_model, dec_model, gpu_ids=opt_exp.gpu_ids)
181
+
182
+ else:
183
+ print('Incorrect number of Decoders specified in the parameters')
184
+ sys.exit(-1)
185
+
186
+ if getattr(opt_exp, 'isFrozen', False):
187
+ enc_model.load_networks(opt_encoder.starting_epoch_count)
188
+ dec_model.load_networks(opt_decoder.starting_epoch_count)
189
+ if opt_exp.n_decoders == 2:
190
+ offset_dec_model.load_networks(opt_offset_decoder.starting_epoch_count)
191
+
192
+ # train the model
193
+ '''
194
+ Trainig the network
195
+ '''
196
+ trainer.train(joint_model, train_loader, test_loader)
197
+
198
+ '''
199
+ Model Evaluation at the best epoch
200
+ '''
201
+
202
+ epoch = "best" # int/"best"/"last"
203
+ eval_name = opt_exp.checkpoints_dir
204
+
205
+ if model_type == 'mamba':
206
+ # Mamba: reload single model
207
+ mamba_model.load_networks(epoch, load_dir=eval_name)
208
+ joint_model.initialize(opt_exp, mamba_model, gpu_ids=opt_exp.gpu_ids)
209
+ else:
210
+ # DLoc: reload encoder + decoder(s)
211
+ enc_model.load_networks(epoch, load_dir=eval_name)
212
+ dec_model.load_networks(epoch, load_dir=eval_name)
213
+ if opt_exp.n_decoders == 2:
214
+ offset_dec_model.load_networks(epoch, load_dir=eval_name)
215
+ joint_model.initialize(opt_exp, enc_model, dec_model, offset_dec_model, gpu_ids=opt_exp.gpu_ids)
216
+ elif opt_exp.n_decoders == 1:
217
+ joint_model.initialize(opt_exp, enc_model, dec_model, gpu_ids=opt_exp.gpu_ids)
218
+
219
+ # pass data through model
220
+ total_loss, median_error = trainer.test(joint_model,
221
+ test_loader,
222
+ save_output=True,
223
+ save_dir=eval_name,
224
+ save_name=f"decoder_test_result_epoch_{epoch}",
225
+ log=False)
226
+ print(f"total_loss: {total_loss}, median_error: {median_error}")
trainer.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Scripts for the training and testing functions
3
+ train() function is called for training the network
4
+ test() function is called to evaluate the network
5
+ Both the function logs and saves the results in the files
6
+ as mentioned in the params.py file
7
+ '''
8
+ import warnings
9
+ with warnings.catch_warnings():
10
+ warnings.filterwarnings("ignore",category=FutureWarning)
11
+ import numpy as np
12
+ import os
13
+ import time
14
+ import hdf5storage
15
+ from utils import *
16
+ from Generators import *
17
+ from params import *
18
+
19
+ def train(model, train_loader, test_loader):
20
+ """Traning pipeline
21
+
22
+ Args:
23
+ model (torch.module): pytorch model
24
+ train_loader (torch.dataloader): dataloader
25
+ test_loader (torch.dataloader): dataloader
26
+ """
27
+ # set data index
28
+ offset_output_index=0
29
+ input_index=1
30
+ output_index=2
31
+
32
+ # initialization
33
+ total_steps = 0
34
+ print('Training called')
35
+ stopping_count = 0
36
+
37
+ for epoch in range(model.opt.starting_epoch_count+1, model.opt.n_epochs+1): # opt.niter + opt.niter_decay + 1):
38
+ epoch_start_time = time.time()
39
+ epoch_loss = 0
40
+ epoch_offset_loss = 0
41
+ error =[]
42
+
43
+ for i, data in enumerate(train_loader):
44
+ total_steps += model.opt.batch_size
45
+ if opt_exp.n_decoders == 2:
46
+ model.set_input(data[input_index], data[output_index], data[offset_output_index], shuffle_channel=False)
47
+ elif opt_exp.n_decoders == 1:
48
+ model.set_input(data[input_index], data[output_index], shuffle_channel=False)
49
+ model.optimize_parameters()
50
+ dec_outputs = model.decoder.output
51
+ # print(f"dec_outputs size is : {dec_outputs.shape}")
52
+ error.extend(localization_error(dec_outputs.data.cpu().numpy(),data[output_index].cpu().numpy(),scale=0.1))
53
+
54
+ write_log([str(model.decoder.loss.item())], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='loss')
55
+ if opt_exp.n_decoders == 2:
56
+ write_log([str(model.offset_decoder.loss.item())], model.offset_decoder.model_name, log_dir=model.offset_decoder.opt.log_dir, log_type='offset_loss')
57
+ if total_steps % model.decoder.opt.save_latest_freq == 0:
58
+ print('saving the latest model (epoch %d, total_steps %d)' %
59
+ (epoch, total_steps))
60
+ model.save_networks('latest')
61
+
62
+ epoch_loss += model.decoder.loss.item()
63
+ if opt_exp.n_decoders == 2:
64
+ epoch_offset_loss += model.offset_decoder.loss.item()
65
+
66
+ median_error_tr = np.median(error)
67
+ error_90th_tr = np.percentile(error,90)
68
+ error_99th_tr = np.percentile(error,99)
69
+ nighty_percentile_error_tr = np.percentile(error,90)
70
+ epoch_loss /= i
71
+ if opt_exp.n_decoders == 2:
72
+ epoch_offset_loss /= i
73
+ write_log([str(epoch_loss)], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='epoch_decoder_loss')
74
+ if opt_exp.n_decoders == 2:
75
+ write_log([str(epoch_offset_loss)], model.offset_decoder.model_name, log_dir=model.offset_decoder.opt.log_dir, log_type='epoch_offset_decoder_loss')
76
+ write_log([str(median_error_tr)], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='train_median_error')
77
+ write_log([str(error_90th_tr)], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='train_90th_error')
78
+ write_log([str(error_99th_tr)], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='train_99th_error')
79
+ write_log([str(nighty_percentile_error_tr)], model.decoder.model_name, log_dir=model.decoder.opt.log_dir, log_type='train_90_error')
80
+ if (epoch == model.opt.starting_epoch_count + 1):
81
+ min_eval_loss, median_error = test(model, test_loader, save_output=False)
82
+ else:
83
+ new_eval_loss, new_med_error = test(model, test_loader, save_output=False)
84
+ if (median_error>=new_med_error):
85
+ stopping_count = stopping_count+1
86
+ median_error = new_med_error
87
+
88
+ # generated_outputs = temp_generator_outputs
89
+ if epoch % model.encoder.opt.save_epoch_freq == 0:
90
+ print('saving the model at the end of epoch %d, iters %d' %(epoch, total_steps))
91
+ model.save_networks('latest')
92
+ model.save_networks(epoch)
93
+ if (stopping_count==2):
94
+ print('Saving best model at %d epoch' %(epoch))
95
+ model.save_networks('best')
96
+ stopping_count=0
97
+
98
+ print('End of epoch %d / %d \t Time Taken: %d sec' %
99
+ (epoch, model.decoder.opt.niter + model.decoder.opt.niter_decay, time.time() - epoch_start_time))
100
+ model.decoder.update_learning_rate()
101
+ model.encoder.update_learning_rate()
102
+ if opt_exp.n_decoders == 2:
103
+ model.offset_decoder.update_learning_rate()
104
+
105
+
106
+ def test(model, test_loader, save_output=True, save_name="decoder_test_result", save_dir="", log=True):
107
+ """Test and evaluation pipeline
108
+
109
+ Args:
110
+ model (torch.module): pytorch model
111
+ test_loader (torch.dataloader): dataloader
112
+ save_output (bool, optional): whether to save output to mat file. Defaults to True.
113
+ save_name (str, optional): name of the mat file. Defaults to "decoder_test_result".
114
+ save_dir (str, optional): directory where output mat file is saved. Defaults to "".
115
+ log (bool, optional): whether to log output. Defaults to True.
116
+
117
+ Returns:
118
+ tuple: (total_loss -> float, median_error -> float)
119
+ """
120
+ print('Evaluation Called')
121
+ model.eval()
122
+
123
+ # set data index
124
+ offset_output_index=0
125
+ input_index=1
126
+ output_index=2
127
+
128
+ # create containers
129
+ generated_outputs = []
130
+ offset_outputs = []
131
+ total_loss = 0
132
+ total_offset_loss = 0
133
+ error =[]
134
+ for i, data in enumerate(test_loader):
135
+ if opt_exp.n_decoders == 2:
136
+ model.set_input(data[input_index], data[output_index], data[offset_output_index], shuffle_channel=False)
137
+ elif opt_exp.n_decoders == 1:
138
+ model.set_input(data[input_index], data[output_index], shuffle_channel=False)
139
+ model.test()
140
+
141
+ # get model outputs
142
+ gen_outputs = model.decoder.output # gen_outputs.size = (N,1,H,W)
143
+ if opt_exp.n_decoders == 2:
144
+ off_outputs = model.offset_decoder.output # off_outputs.size = (N,n_ap,H,W)
145
+
146
+ generated_outputs.extend(gen_outputs.data.cpu().numpy())
147
+ if opt_exp.n_decoders == 2:
148
+ offset_outputs.extend(off_outputs.data.cpu().numpy())
149
+ error.extend(localization_error(gen_outputs.data.cpu().numpy(),data[output_index].cpu().numpy(),scale=0.1))
150
+ total_loss += model.decoder.loss.item()
151
+ if opt_exp.n_decoders == 2:
152
+ total_offset_loss += model.offset_decoder.loss.item()
153
+ total_loss /= i
154
+ if opt_exp.n_decoders == 2:
155
+ total_offset_loss /= i
156
+ median_error = np.median(error)
157
+ nighty_percentile_error = np.percentile(error,90)
158
+ error_99th = np.percentile(error,99)
159
+
160
+ if log:
161
+ write_log([str(median_error)], model.decoder.model_name, log_dir=model.opt.log_dir, log_type='test_median_error')
162
+ write_log([str(nighty_percentile_error)], model.decoder.model_name, log_dir=model.opt.log_dir, log_type='test_90_error')
163
+ write_log([str(error_99th)], model.decoder.model_name, log_dir=model.opt.log_dir, log_type='test_99_error')
164
+ write_log([str(total_loss)], model.decoder.model_name, log_dir=model.opt.log_dir, log_type='test_loss')
165
+ if opt_exp.n_decoders == 2:
166
+ write_log([str(total_offset_loss)], model.offset_decoder.model_name, log_dir=model.opt.log_dir, log_type='test_offset_loss')
167
+
168
+ if save_output:
169
+ if not save_dir:
170
+ save_dir = model.decoder.results_save_dir # default save directory
171
+
172
+ if not os.path.exists(save_dir):
173
+ os.makedirs(save_dir, exist_ok=True)
174
+
175
+ save_path = f"{save_dir}/{save_name}.mat"
176
+ hdf5storage.savemat(save_path,
177
+ mdict={"outputs":generated_outputs,"wo_outputs":offset_outputs, "error": error},
178
+ appendmat=True,
179
+ format='7.3',
180
+ truncate_existing=True)
181
+ print(f"result saved in {save_path}")
182
+ return total_loss, median_error
utils.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+ '''
3
+ Contains the utilities used for
4
+ loading, initating and running up the networks
5
+ for all training, validation and evaluation.
6
+ '''
7
+ import torch
8
+ import torch.nn as nn
9
+ from torch.nn import init
10
+ import functools
11
+ from torch.optim import lr_scheduler
12
+ import numpy as np
13
+ import os
14
+ from Generators import *
15
+ from mamba_model import MambaDLocNet
16
+
17
+ def write_log(log_values, model_name, log_dir="", log_type='loss', type_write='a'):
18
+ if not os.path.exists(log_dir):
19
+ os.makedirs(log_dir)
20
+ with open(log_dir+"/"+model_name+"_"+log_type+".txt", type_write) as f:
21
+ f.write(','.join(log_values)+"\n")
22
+
23
+ def get_model_funct(model_name):
24
+ if model_name == "G":
25
+ return define_G
26
+
27
+ def define_G(opt, gpu_ids):
28
+ net = None
29
+ input_nc = opt.input_nc
30
+ output_nc = opt.output_nc
31
+ ngf = opt.ngf
32
+ net_type = opt.base_model
33
+ norm = opt.norm
34
+ use_dropout = opt.no_dropout
35
+ init_type = opt.init_type
36
+ init_gain = opt.init_gain
37
+
38
+ norm_layer = get_norm_layer(norm_type=norm)
39
+
40
+ if net_type == 'resnet_encoder':
41
+ n_blocks = opt.resnet_blocks
42
+ net = ResnetEncoder(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=n_blocks)
43
+ elif net_type == 'resnet_decoder':
44
+ n_blocks = opt.resnet_blocks
45
+ net = ResnetDecoder(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=n_blocks, encoder_blocks=opt.encoder_res_blocks)
46
+ elif net_type == 'mamba_dloc':
47
+ net = MambaDLocNet(input_nc=input_nc)
48
+ else:
49
+ raise NotImplementedError('Generator model name [%s] is not recognized' % net_type)
50
+ return init_net(net, init_type, init_gain, gpu_ids)
51
+
52
+
53
+ def get_scheduler(optimizer, opt):
54
+ if opt.starting_epoch_count=='best' and opt.lr_policy == 'lambda':
55
+ def lambda_rule(epoch):
56
+ print("lambda update %s, %s, %s", (epoch, 0))
57
+ lr_l = 1.0 - max(0, epoch + 1 - opt.niter) / float(opt.niter_decay + 1)
58
+ return lr_l
59
+ scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule)
60
+ elif opt.starting_epoch_count!='best' and opt.lr_policy == 'lambda':
61
+ def lambda_rule(epoch):
62
+ print("lambda update %s, %s, %s", (epoch, opt.starting_epoch_count))
63
+ lr_l = 1.0 - max(0, epoch + 1 + opt.starting_epoch_count - opt.niter) / float(opt.niter_decay + 1)
64
+ return lr_l
65
+ scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule)
66
+ elif opt.starting_epoch_count!='best' and opt.lr_policy == 'step':
67
+ scheduler = lr_scheduler.StepLR(optimizer, step_size=opt.lr_decay_iters, gamma=0.9)
68
+ elif opt.starting_epoch_count!='best' and opt.lr_policy == 'plateau':
69
+ scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.2, threshold=0.01, patience=5)
70
+ elif opt.starting_epoch_count!='best' and opt.lr_policy == 'cosine':
71
+ scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=opt.niter, eta_min=0)
72
+ else:
73
+ return NotImplementedError('learning rate policy [%s] is not implemented', opt.lr_policy)
74
+ return scheduler
75
+
76
+
77
+ def get_norm_layer(norm_type='instance'):
78
+ if norm_type == 'batch':
79
+ norm_layer = functools.partial(nn.BatchNorm2d, affine=True)
80
+ elif norm_type == 'instance':
81
+ norm_layer = functools.partial(nn.InstanceNorm2d, affine=False, track_running_stats=False)
82
+ elif norm_type == 'none':
83
+ norm_layer = None
84
+ else:
85
+ raise NotImplementedError('normalization layer [%s] is not found' % norm_type)
86
+ return norm_layer
87
+
88
+
89
+ def init_weights(net, init_type='normal', gain=1):
90
+ def init_func(m):
91
+ classname = m.__class__.__name__
92
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
93
+ if init_type == 'normal':
94
+ init.normal_(m.weight.data, 0, gain)
95
+ elif init_type == 'xavier':
96
+ init.xavier_normal_(m.weight.data, gain=gain)
97
+ elif init_type == 'kaiming':
98
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
99
+ elif init_type == 'orthogonal':
100
+ init.orthogonal_(m.weight.data, gain=gain)
101
+ else:
102
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
103
+ if hasattr(m, 'bias') and m.bias is not None:
104
+ init.constant_(m.bias.data, 0.0)
105
+ elif classname.find('BatchNorm2d') != -1:
106
+ init.normal_(m.weight.data, 1.0, gain)
107
+ init.constant_(m.bias.data, 0.0)
108
+
109
+ print('initialize network with %s' % init_type)
110
+ net.apply(init_func)
111
+
112
+
113
+ def init_net(net, init_type='normal', init_gain=1, gpu_ids=[]):
114
+ if len(gpu_ids) > 0:
115
+ assert(torch.cuda.is_available())
116
+ device_ = torch.device('cuda:{}'.format(gpu_ids[0]))
117
+ # net.to(d)
118
+ gpu_ids_int = list(map(int,gpu_ids))
119
+ net = torch.nn.DataParallel(net, gpu_ids_int)
120
+ net.to(device_)
121
+ init_weights(net, init_type, gain=init_gain)
122
+ return net
123
+
124
+ def localization_error(output_predictions,input_labels,scale=0.1):
125
+ """
126
+ output_predictions: (N,1,H,W), model prediction
127
+ input_labels: (N,1,H,W), ground truth target
128
+ """
129
+ image_size = output_predictions.shape
130
+ error = np.zeros(image_size[0])
131
+
132
+ for i in range(image_size[0]):
133
+ label_temp = input_labels[i,:,:,:].squeeze() # ground truth label
134
+ pred_temp = output_predictions[i,:,:,:].squeeze() # model prediction
135
+ label_index = np.asarray(np.unravel_index(np.argmax(label_temp), label_temp.shape))
136
+ prediction_index = np.asarray(np.unravel_index(np.argmax(pred_temp),pred_temp.shape))
137
+ error[i] = np.sqrt( np.sum( np.power(np.multiply( label_index-prediction_index, scale ), 2)) )
138
+
139
+ return error
140
+
141
+ class Flatten(nn.Module):
142
+ def __init__(self):
143
+ super(Flatten, self).__init__()
144
+
145
+ def forward(self, x):
146
+ return x.view(x.size(0), -1)
147
+
148
+ def RGB2Gray(img):
149
+ return 0.2125*img[:,:,0] + 0.7154*img[:,:,1] + 0.0721*img[:,:,2]