Skip to content

Commit a59ed24

Browse files
committed
[update] 20260312
1 parent 3f9153c commit a59ed24

12 files changed

Lines changed: 93 additions & 44 deletions

File tree

.github/workflows/probot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
python-version: ['3.9', '3.10', '3.11', '3.12']
11+
python-version: ['3.10', '3.11', '3.12', '3.13']
1212

1313
steps:
1414
- uses: actions/checkout@v1
@@ -19,8 +19,8 @@ jobs:
1919
- name: Install dependencies
2020
run: |
2121
python -m pip install --upgrade pip
22-
pip install -r requirements.txt
2322
pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu
23+
pip install -r requirements.txt
2424
- name: Lint with flake8
2525
run: |
2626
pip install flake8

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ python:
66
- "3.10"
77
- "3.11"
88
- "3.12"
9+
- "3.13"
910

1011
install:
11-
- pip install -r requirements.txt
12+
- python -m pip install --upgrade pip
1213
- pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu
14+
- pip install -r requirements.txt
1315

1416
script:
1517
- python -m unittest discover test

circle.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ version: 2.1
33
workflows:
44
test:
55
jobs:
6-
- job-py38
76
- job-py39
87
- job-py310
98
- job-py311
109
- job-py312
10+
- job-py313
1111

1212
jobs:
13-
job-py38: &job-template
13+
job-py39: &job-template
1414
docker:
15-
- image: cimg/python:3.8
15+
- image: cimg/python:3.9
1616

1717
working_directory: ~/repo
1818

@@ -25,8 +25,8 @@ jobs:
2525
python -m venv venv
2626
. venv/bin/activate
2727
pip install --upgrade pip
28-
pip install -r requirements.txt > /dev/null
2928
pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu
29+
pip install -r requirements.txt
3030
3131
- run:
3232
name: run unittest
@@ -50,11 +50,6 @@ jobs:
5050
path: test-reports
5151
destination: test-reports
5252

53-
job-py39:
54-
<<: *job-template
55-
docker:
56-
- image: cimg/python:3.9
57-
5853
job-py310:
5954
<<: *job-template
6055
docker:
@@ -69,3 +64,8 @@ jobs:
6964
<<: *job-template
7065
docker:
7166
- image: cimg/python:3.12
67+
68+
job-py313:
69+
<<: *job-template
70+
docker:
71+
- image: cimg/python:3.13

configs/BaseConfig.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def dict(self):
2525
for key in list(value_dict.keys()):
2626
if not self._values(key):
2727
value_dict.pop(key, None)
28+
elif isinstance(value_dict[key], BaseConfig):
29+
value_dict[key] = value_dict[key].dict()
2830
return value_dict
2931

3032
def __eq__(self, other):

datasets/BaseDataset.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
class BaseDataset(Dataset, metaclass=abc.ABCMeta):
1919

2020
logger: utils.Logger
21+
wandb: utils.Wandb
2122
summary: utils.Summary
2223

2324
def __init__(self, cfg, **kwargs):
@@ -55,8 +56,15 @@ def set_logger(self, logger):
5556
if hasattr(self, 'super_dataset') and isinstance(self.super_dataset, BaseDataset):
5657
self.super_dataset.set_logger(logger)
5758

59+
def set_wandb(self, wandb):
60+
self.wandb = wandb
61+
if hasattr(self, 'super_dataset') and isinstance(self.super_dataset, BaseDataset):
62+
self.super_dataset.set_wandb(wandb)
63+
5864
def set_summary(self, summary):
5965
self.summary = summary
66+
if hasattr(self, 'super_dataset') and isinstance(self.super_dataset, BaseDataset):
67+
self.super_dataset.set_summary(summary)
6068

6169
@staticmethod
6270
def need_norm(data_shape):
@@ -153,17 +161,17 @@ def _get_args(self, norm_func, data, name: str, **kwargs):
153161
def _recover(self, index):
154162
index_dict = dict()
155163
for key, value in self.cfg.dict().items():
156-
if key not in ['out', 'kernel'] and isinstance(value, configs.BaseConfig):
157-
if hasattr(value, 'width') and hasattr(value, 'height'):
158-
if hasattr(value, 'time'):
159-
if hasattr(value, 'patch'):
160-
index_dict[key] = [0, value.patch, 0, value.time, 0, value.width, 0, value.height]
164+
if key not in ['out', 'kernel'] and isinstance(value, dict):
165+
if 'width' in value and 'height' in value:
166+
if 'time' in value:
167+
if 'patch' in value:
168+
index_dict[key] = [0, value['patch'], 0, value['time'], 0, value['width'], 0, value['height']]
161169
else:
162-
index_dict[key] = [0, value.time, 0, value.width, 0, value.height]
170+
index_dict[key] = [0, value['time'], 0, value['width'], 0, value['height']]
163171
else:
164-
index_dict[key] = [0, value.width, 0, value.height]
165-
elif hasattr(value, 'elements'):
166-
index_dict[key] = [0, value.elements]
172+
index_dict[key] = [0, value['width'], 0, value['height']]
173+
elif 'elements' in value:
174+
index_dict[key] = [0, value['elements']]
167175
return [index], index_dict
168176

169177
def recover(self, index):

main.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ def split(self, index_cross):
5151

5252
self.logger = utils.Logger(self.path, utils.path.get_filename(self.model_cfg._path))
5353
self.dataset.set_logger(self.logger)
54+
self.wandb = utils.Wandb(self.model_cfg, self.dataset_cfg, self.run_cfg)
55+
self.dataset.set_wandb(self.wandb)
5456
self.summary = utils.Summary(self.path, dataset=self.dataset)
5557
self.dataset.set_summary(self.summary)
5658

@@ -97,7 +99,8 @@ def split(self, index_cross):
9799
)
98100

99101
self.model = models.functional.common.find(self.model_cfg.name)(
100-
self.model_cfg, self.dataset.cfg, self.run_cfg, logger=self.logger, summary=self.summary, main_msg=self.msg)
102+
self.model_cfg, self.dataset.cfg, self.run_cfg,
103+
logger=self.logger, wandb=self.wandb, summary=self.summary, main_msg=self.msg)
101104
self.start_epoch = self.model.load(self.args.test_epoch)
102105

103106
if not self.run_cfg.distributed or (self.run_cfg.distributed and self.run_cfg.local_rank == 0):
@@ -121,7 +124,7 @@ def train(self, epoch):
121124
if self.run_cfg.distributed:
122125
self.train_loader.sampler.set_epoch(epoch)
123126
self.train_loader = self.model.train_loader_hook(self.train_loader)
124-
batch_per_epoch, count_data = len(self.train_loader), len(self.train_loader.dataset)
127+
batch_per_epoch, count_data = len(self.train_loader), len(self.train_loader.sampler)
125128
log_step = 1#max(int(np.power(10, np.floor(np.log10(batch_per_epoch / 10)))), 1) if batch_per_epoch > 0 else 1
126129
epoch_info = {'epoch': epoch, 'batch_per_epoch': batch_per_epoch, 'count_data': count_data}
127130
epoch_info['local_rank'] = self.run_cfg.local_rank if self.run_cfg.distributed else 1
@@ -165,8 +168,10 @@ def train(self, epoch):
165168
if self.run_cfg.distributed:
166169
with utils.ddp.sequence():
167170
self.logger.info_scalars('Train Epoch: {} rank {}\t', (epoch, self.run_cfg.local_rank), loss_all)
171+
self.wandb.info(loss_all)
168172
else:
169173
self.logger.info_scalars('Train Epoch: {}\t', (epoch,), loss_all)
174+
self.wandb.info(loss_all)
170175
if epoch % self.run_cfg.save_step == 0:
171176
self.model.save(epoch)
172177

@@ -182,7 +187,7 @@ def test(self, epoch, data_loader=None, log_text='Test'):
182187
if self.run_cfg.distributed:
183188
data_loader.sampler.set_epoch(epoch)
184189
data_loader = self.model.test_loader_hook(data_loader)
185-
batch_per_epoch, count_data = len(data_loader), len(data_loader.dataset)
190+
batch_per_epoch, count_data = len(data_loader), len(data_loader.sampler)
186191
log_step = max(int(np.power(10, np.floor(np.log10(batch_per_epoch / 10)))), 1)
187192
epoch_info = {'epoch': epoch, 'batch_per_epoch': batch_per_epoch, 'count_data': count_data, 'log_text': log_text}
188193
epoch_info['local_rank'] = self.run_cfg.local_rank if self.run_cfg.distributed else 1
@@ -269,6 +274,7 @@ def test(self, epoch, data_loader=None, log_text='Test'):
269274
msgs_dict[name] = 100. * value / count
270275
accuracy.append(msgs_dict[name])
271276
self.logger.info(log_msg.format(log_text, epoch, *accuracy))
277+
self.wandb.info({f'{log_text}_accuracy': accuracy})
272278
self.summary.add_scalars('Accuracy', msgs_dict, epoch)
273279

274280
# TODO do not support chain norm and renorm
@@ -277,7 +283,7 @@ def test(self, epoch, data_loader=None, log_text='Test'):
277283
# dataset.append(dataset[-1].super_dataset)
278284
# dataset_cfg.append(dataset[-1].cfg)
279285
for name, value in predict.items():
280-
predict[name] = np.array(value.cpu())
286+
predict[name] = value.cpu().numpy()
281287
for d_cfg, d in zip(dataset_cfg, dataset):
282288
if d_cfg.norm and d.need_norm(value.shape):
283289
data_type, data_cfg = self._get_type(d_cfg, name, test=False)
@@ -339,17 +345,22 @@ def run():
339345
main.split(index_cross)
340346
main.model.process_pre_hook()
341347
if args.test_epoch is None:
348+
main.model.main_msg.update(dict(only_test=False))
342349
if main.start_epoch == 0:
343-
main.val_test(main.start_epoch) # TODO set flag only_test=False
350+
main.model.process_test_msg_pre_hook(main.model.main_msg)
351+
while main.model.main_msg['test_flag']:
352+
main.val_test(main.start_epoch)
353+
main.model.process_test_msg_hook(main.model.main_msg)
344354
for epoch in range(main.start_epoch + 1, main.run_cfg.epochs + 1):
345355
main.train(epoch)
346356
if epoch % main.run_cfg.save_step == 0:
347-
main.model.main_msg.update(dict(test_idx=1, test_flag=True, only_test=False))
357+
main.model.process_test_msg_pre_hook(main.model.main_msg)
348358
while main.model.main_msg['test_flag']:
349359
main.val_test(epoch)
350360
main.model.process_test_msg_hook(main.model.main_msg)
351361
else:
352-
main.model.main_msg.update(dict(test_idx=1, test_flag=True, only_test=True))
362+
main.model.main_msg.update(dict(only_test=True))
363+
main.model.process_test_msg_pre_hook(main.model.main_msg)
353364
while main.model.main_msg['test_flag']:
354365
main.val_test(main.start_epoch)
355366
main.model.process_test_msg_hook(main.model.main_msg)

models/BaseModel.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import torch
55
import torch.nn as nn
6+
from torch.optim import Optimizer
7+
from torch.optim.lr_scheduler import LRScheduler
68
from torch.utils.data import DataLoader
79

810
import configs
@@ -23,6 +25,9 @@ def process_hook(self):
2325
def process_msg_hook(self, msg: dict):
2426
msg.update(dict(while_flag=False))
2527

28+
def process_test_msg_pre_hook(self, msg: dict):
29+
msg.update(dict(test_flag=True, test_idx=1))
30+
2631
def process_test_msg_hook(self, msg: dict):
2732
msg.update(dict(test_flag=False))
2833

@@ -83,6 +88,7 @@ def test_return_hook(self, epoch_info: dict, return_all: dict):
8388
class BaseModel(_ProcessHook, _MainHook, metaclass=abc.ABCMeta):
8489

8590
logger: utils.Logger
91+
wandb: utils.Wandb
8692
summary: utils.Summary
8793
main_msg: dict
8894

@@ -145,7 +151,7 @@ def summary_models(self, shapes):
145151
def load(self, start_epoch=None, path=None):
146152
assert start_epoch is None or (isinstance(start_epoch, int) and start_epoch >= 0)
147153
path = path or self.path
148-
load_optimizer = start_epoch is None
154+
load_optimizer_scheduler = start_epoch is None
149155
if start_epoch is None:
150156
main_msg = ('_' + str(self.main_msg['while_idx'])) if self.main_msg['while_idx'] > 1 else ''
151157
check_path = os.path.join(path, self.name + main_msg + configs.env.paths.check_file)
@@ -159,16 +165,24 @@ def load(self, start_epoch=None, path=None):
159165
if start_epoch > 0:
160166
msg = ('_' + '-'.join(self.msg.values())) if self.msg else ''
161167
for name, value in self.__dict__.items():
162-
if isinstance(value, (nn.Module, torch.optim.Optimizer)) or name in self._save_list:
163-
epoch_msg = ('_' + str(start_epoch)) if not isinstance(value, torch.optim.Optimizer) else ''
168+
if isinstance(value, (nn.Module, Optimizer, LRScheduler)) or name in self._save_list:
169+
epoch_msg = ('_' + str(start_epoch)) if not isinstance(value, (Optimizer, LRScheduler)) else ''
164170
load_path = os.path.join(path, self.name + '_' + name + epoch_msg + msg + '.pth')
165-
if not (load_optimizer and os.path.exists(load_path)) and isinstance(value, torch.optim.Optimizer):
166-
if not os.path.exists(load_path):
167-
self.logger.info(f"IGNORE! Optimizer weight `{load_path}` not found!")
171+
if not load_optimizer_scheduler and isinstance(value, (Optimizer, LRScheduler)):
168172
continue
173+
if not os.path.exists(load_path):
174+
if isinstance(value, Optimizer):
175+
self.logger.info(f"IGNORE! Optimizer `{load_path}` not found!")
176+
continue
177+
elif isinstance(value, LRScheduler):
178+
self.logger.info(f"IGNORE! LRScheduler `{load_path}` not found!")
179+
for _ in range(start_epoch):
180+
value.step()
181+
self.logger.info(f"LRScheduler `step()` has been executed automatically {start_epoch} times!")
182+
continue
169183
map_location = {'cuda:%d' % 0: 'cuda:%d' % self.run.local_rank} if self.run.distributed else self.device
170184
load_value = torch.load(load_path, map_location=map_location)
171-
if isinstance(value, (nn.Module, torch.optim.Optimizer)):
185+
if isinstance(value, (nn.Module, Optimizer, LRScheduler)):
172186
self.__dict__[name].load_state_dict(load_value)
173187
else:
174188
self.__dict__[name] = load_value
@@ -182,9 +196,9 @@ def save(self, epoch, path=None):
182196
msg = ('_' + '-'.join(self.msg.values())) if self.msg else ''
183197
for name, value in self.__dict__.items():
184198
# TODO remove criterion, change criterion super object to `torch.nn.modules.loss._Loss`?
185-
if isinstance(value, (nn.Module, torch.optim.Optimizer)) or name in self._save_list:
186-
save_value = value.state_dict() if isinstance(value, (nn.Module, torch.optim.Optimizer)) else value
187-
epoch_msg = ('_' + str(epoch)) if not isinstance(value, torch.optim.Optimizer) else ''
199+
if isinstance(value, (nn.Module, Optimizer, LRScheduler)) or name in self._save_list:
200+
save_value = value.state_dict() if isinstance(value, (nn.Module, Optimizer, LRScheduler)) else value
201+
epoch_msg = ('_' + str(epoch)) if not isinstance(value, (Optimizer, LRScheduler)) else ''
188202
torch.save(save_value, os.path.join(path, self.name + '_' + name + epoch_msg + msg + '.pth'))
189203
main_msg = ('_' + str(self.main_msg['while_idx'])) if self.main_msg['while_idx'] > 1 else ''
190204
torch.save(dict(epoch=epoch, msg=self.msg, main_msg=self.main_msg),

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ scikit-image
44
imageio
55
h5py
66
tensorboard
7+
argcomplete
8+
wandb

res/env/log.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"summary": false
2+
"summary": false,
3+
"wandb": false
34
}

run.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,23 @@ def choices(prefix, parsed_args, **kwargs):
2626
argcomplete.autocomplete(parser)
2727
args = parser.parse_args()
2828

29+
2930
process = [
3031
'python3', '-m', 'main',
3132
'-m', str(args.model_config_path),
3233
'-d', str(args.dataset_config_path),
3334
'-r', str(args.run_config_path),
34-
'-g', str(args.gpus),
3535
]
36+
gpus = str(args.gpus)
37+
if gpus == 'cpu':
38+
os.environ['CUDA_VISIBLE_DEVICES'] = ''
39+
process.extend(['-g', 'cpu'])
40+
else:
41+
os.environ['CUDA_VISIBLE_DEVICES'] = gpus
42+
process.extend(['-g', ','.join([str(idx) for idx in range(len(gpus.split(',')))])])
3643
if args.test_epoch is not None:
3744
process.append('-t')
3845
process.append(str(args.test_epoch))
3946
if args.ci:
4047
process.append('--ci')
41-
subprocess.run(process, check=True)
48+
subprocess.run(process, env=os.environ, check=True)

0 commit comments

Comments
 (0)