File size: 24,243 Bytes
a27dedf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
"""isort:skip_file"""

import logging
from hydra.core.config_store import ConfigStore
from TDATR_utils.dataclass import HulkConfig
from omegaconf import DictConfig, OmegaConf


logger = logging.getLogger(__name__)


def _hijack_hydra_configure_logging():
    import sys
    import hydra
    from typing import Union, Sequence

    def _configure_log(
        log_config: DictConfig,
        verbose_config: Union[bool, str, Sequence[str]] = False,
    ) -> None:
        assert isinstance(verbose_config, (bool, str)) or OmegaConf.is_list(verbose_config)
        if log_config is not None:
            conf: Dict[str, Any] = OmegaConf.to_container(  # type: ignore
                log_config, resolve=True
            )
            if conf["root"] is not None:
                file_name = conf.get('handlers', {}).get('file', {}).get('filename')
                conf['handlers']['file']['filename'] = file_name + ".tempfile"
                logging.config.dictConfig(conf)
        else:
            # default logging to stdout
            root = logging.getLogger()
            root.setLevel(logging.INFO)
            handler = logging.StreamHandler(sys.stdout)
            formatter = logging.Formatter(
                "[%(asctime)s][%(name)s][%(levelname)s] - %(message)s"
            )
            handler.setFormatter(formatter)
            root.addHandler(handler)
        if isinstance(verbose_config, bool):
            if verbose_config:
                logging.getLogger().setLevel(logging.DEBUG)
        else:
            if isinstance(verbose_config, str):
                verbose_list = OmegaConf.create([verbose_config])
            elif OmegaConf.is_list(verbose_config):
                verbose_list = verbose_config  # type: ignore
            else:
                assert False

            for logger in verbose_list:
                logging.getLogger(logger).setLevel(logging.DEBUG)

    def _try(fn, src_fn):
        def exec_fn(*args, **kwargs):
            try:
                ret = fn(*args, **kwargs)
            except Exception as e:
                print(f'error: {e}')
                ret = src_fn(*args, **kwargs)
            return ret
        return exec_fn

    org_configure_log_fn = hydra.core.utils.configure_log
    hydra.core.utils.configure_log = _try(_configure_log, org_configure_log_fn)


def hydra_init(cfg_name="config") -> None:
    _hijack_hydra_configure_logging()
    cs = ConfigStore.instance()
    cs.store(name=f"{cfg_name}", node=HulkConfig)
    
    for k in HulkConfig.__dataclass_fields__:
        v = HulkConfig.__dataclass_fields__[k].default
        try:
            cs.store(name=k, node=v)
        except BaseException:
            logger.error(f"{k} - {v}")
            raise



import os
import logging
import socket
import time
from argparse import Namespace

import torch
from torch.backends import cudnn
import torch.distributed as dist

from TDATR_utils.global_context import global_context as gpc
from TDATR_utils.global_variables import ParallelMode


logger = logging.getLogger(__name__)


def _check_model_parallel_topo(cfg: HulkConfig) -> None:
    # Distributed args.
    dist_cfg = cfg.distributed_training
    mpu_cfg = cfg.model_parallel
    world_size = dist_cfg.distributed_world_size
    pp_size = mpu_cfg.pipeline_model_parallel_size
    tp_size = mpu_cfg.tensor_model_parallel_size
    sp_size = mpu_cfg.sequence_parallel_size
    mp_size = pp_size * tp_size
    
    assert mp_size * sp_size <= world_size, \
        f"world size ({world_size}) is less than `tensor model parallel size({tp_size}) * " \
        f"pipeline model parallel size({pp_size}) * sequence parallel size({sp_size})`!" \
    
    assert world_size % (mp_size * sp_size) == 0, \
        f"world size({world_size}) is not divisible by `model parallel size({mp_size}) * sequence parallel size({sp_size})`"
    
    mpu_cfg.data_parallel_size = world_size // mp_size // sp_size
    if (not torch.cuda.is_available() or cfg.common.cpu):
        virtual_pp_size = mpu_cfg.virtual_pipeline_model_parallel_size
        assert (mp_size == 1 and virtual_pp_size is None), \
            f"model parallelism isn't supported using cpu traing or cuda is unavailable."


def _check_model_parallel_cfgs(cfg: HulkConfig) -> None:
    dist_cfg = cfg.distributed_training
    mpu_cfg = cfg.model_parallel
    assert mpu_cfg.micro_batch_size >= 1, \
        f"Required micro_batch_size >= 1, but got {mpu_cfg.micro_batch_size}."
    if mpu_cfg.global_batch_size is None and mpu_cfg.num_micro_batch is not None:
        assert mpu_cfg.micro_batch_size > 0 and mpu_cfg.num_micro_batch > 0, \
                        f"Micro_batch_size({mpu_cfg.micro_batch_size}) <= 0 " \
                        f"or num_micro_batch({mpu_cfg.num_micro_batch}) <= 0"
        mpu_cfg.global_batch_size = mpu_cfg.micro_batch_size * \
                                    mpu_cfg.num_micro_batch * \
                                    mpu_cfg.data_parallel_size
    elif mpu_cfg.global_batch_size is not None and mpu_cfg.num_micro_batch is None:
        mpu_cfg.num_micro_batch = mpu_cfg.global_batch_size / \
                                    mpu_cfg.data_parallel_size / \
                                    mpu_cfg.micro_batch_size
    elif mpu_cfg.global_batch_size is not None and mpu_cfg.num_micro_batch is not None:
        global_batch_size_2 = mpu_cfg.micro_batch_size * \
                                mpu_cfg.num_micro_batch * \
                                mpu_cfg.data_parallel_size
        assert mpu_cfg.global_batch_size == global_batch_size_2, \
                        f"Required global_batch_size == micro_batch_size * num_micro_batch * data_parallel_size, " \
                        f"bug got global_batch_size = {mpu_cfg.global_batch_size} " \
                        f"and micro_batch_size * num_micro_batch * data_parallel_size = {global_batch_size_2}"
    else:
        raise ValueError(f"Got global_batch_size and num_micro_batch are None,"
                            f" you need to set one of them to a valid value.")
    logger.warning(
        "Set batch_size({})=micro_batch_size({}) in model parallel training mode." \
        "".format(cfg.dataset.batch_size, mpu_cfg.micro_batch_size)
        )
    cfg.dataset.batch_size = mpu_cfg.micro_batch_size

    if mpu_cfg.pipeline_model_parallel_size != 1 and \
       cfg.distributed_training.ddp_backend in ["c10d", "pytorch_ddp"]:
        raise ValueError(f"c10d/pytorch_ddp is not supported when using pipeline parallel!")

    if mpu_cfg.virtual_pipeline_model_parallel_size is not None:
        if int(mpu_cfg.virtual_pipeline_model_parallel_size) <= 1:
            mpu_cfg.virtual_pipeline_model_parallel_size = None
            logger.warning(
                "Ignore invalid config of virtual_pipeline_model_parallel_size <= 1."
            )
        if cfg.task._name == "ipt_rlhf_task":
            policy_num_micro_batch = mpu_cfg.num_micro_batch+cfg.rlhf.policy_num_micro_batch
            assert policy_num_micro_batch % mpu_cfg.pipeline_model_parallel_size == 0, \
                'Number of microbatches+policy_num_micro_batch({}) is not divisible by pipeline-parallel ' \
                'size({}) when using interleaved schedule'.format(
                policy_num_micro_batch, mpu_cfg.pipeline_model_parallel_size)

            assert cfg.rlhf.critic_num_micro_batch % mpu_cfg.pipeline_model_parallel_size == 0, \
                'critic_num_micro_batch({}) is not divisible by pipeline-parallel ' \
                'size({}) when using interleaved schedule'.format(
                cfg.rlhf.critic_num_micro_batch, mpu_cfg.pipeline_model_parallel_size)
        else:
            assert mpu_cfg.num_micro_batch % mpu_cfg.pipeline_model_parallel_size == 0, \
                'Number of microbatches({}) is not divisible by pipeline-parallel ' \
                'size({}) when using interleaved schedule'.format(
                mpu_cfg.num_micro_batch, mpu_cfg.pipeline_model_parallel_size)

            if cfg.dataset.batch_size_valid != mpu_cfg.micro_batch_size:
                logger.warning(
                    "Detected batch_size_valid({}) != micro_batch_size({}) when using pipeline "
                    "interleaved schedule, we will set batch_size_valid=micro_batch_size, "
                    "if you mind this, don't pass --num-layers-per-virtual-pipeline-stage to "
                    "TDATR_utils.".format(cfg.dataset.batch_size_valid, mpu_cfg.micro_batch_size)
                )
                cfg.dataset.batch_size_valid = mpu_cfg.micro_batch_size

    logger.info(
        f'using global_batch_size: {mpu_cfg.global_batch_size}, ' \
        f'micro_batch_size: {mpu_cfg.micro_batch_size}, ' \
        f'num_micro_batches {mpu_cfg.num_micro_batch}'
    )

    # check sequence parallel
    if mpu_cfg.tensor_model_parallel_size == 1:
        mpu_cfg.sequence_parallel = False
        logger.info(
            "Disable sequence parallel when tensor parallel = 1 " \
            "to avoid change in numerics when sequence parallel is enabled"
        )
    
    # check async_tensor_model_parallel_allreduce
    if mpu_cfg.sequence_parallel:
        if mpu_cfg.async_tensor_model_parallel_allreduce:
            mpu_cfg.async_tensor_model_parallel_allreduce = False
            logger.info(
                "disable async_tensor_model_parallel_allreduce when " \
                "sequence parallel is enabled."
            )
        if mpu_cfg.scatter_gather_tensors_in_pipeline:
            mpu_cfg.scatter_gather_tensors_in_pipeline = False
            logger.info(
                "If sequence_parallel enabled, we should set " \
                "scatter_gather_tensors_in_pipeline to false" \
                "otherwise it will cause the transmitted tensor between pipeline stages to be destroyed."
            )

    # check ema
    assert not cfg.ema.store_ema, \
        "EMA is incompatible with model parallelism."
    
    # check update_freq
    assert tuple(cfg.optimization.update_freq) == (1,), \
        "Detected optimization.update_freq != [1], when using model parallel " \
        "traning mode, you should use --num-micro-batch, instead of --update-freq."
    cfg.optimization.update_freq = [mpu_cfg.num_micro_batch]

    assert not cfg.distributed_training.cpu_offload, "`cpu offload` is not supported!"
    assert not cfg.distributed_training.use_sharded_state, "`use_sharded_state` is not supported!"
    if all([
        cfg.distributed_training.ddp_backend == 'fully_sharded',
        cfg.distributed_training.zero_sharding == 'os'
    ]):
        raise ValueError("`fully_sharded` and `os`cannot be used at the same time")

    logger.info(
        f'using world size: {dist_cfg.distributed_world_size}, '\
        f'data-parallel-size: {mpu_cfg.data_parallel_size}, ' \
        f'sequence-parallel-size: {mpu_cfg.sequence_parallel_size}, ' \
        f'tensor-model-parallel size: {mpu_cfg.tensor_model_parallel_size}, ' \
        f'pipeline-model-parallel size: {mpu_cfg.pipeline_model_parallel_size}.')


def _check_other_cfgs(cfg: HulkConfig) -> None:
    if cfg.common.fp16 and cfg.common.bf16:
        raise ValueError(f"fp16 and bf16 can not both be True")
    
    if cfg.common.memory_efficient_bf16 and cfg.common.memory_efficient_fp16:
        raise ValueError(f"memory_efficient_bf16 and memory_efficient_fp16 can not both be True ")
    
    if (cfg.common.fp16 and cfg.common.memory_efficient_bf16) \
        or (cfg.common.bf16 and cfg.common.memory_efficient_fp16):
        raise ValueError(f"cfg.common.fp16(cfg.common.bf16) is only paired with" \
                         f"cfg.common.memory_efficient_fp16(cfg.common.memory_efficient_bf16) for use")

    if cfg.common.memory_efficient_fp16 and not cfg.common.fp16:
        cfg.common.fp16 = True
        logger.info(f"common.fp16 is enabled because cfg.common.memory_efficient_fp16 is True")

    if cfg.common.memory_efficient_bf16 and not cfg.common.bf16:
        cfg.common.bf16 = True
        logger.info(f"common.bf16 is enabled because cfg.common.memory_efficient_bf16 is True")

    if cfg.common.bf16:
        assert cfg.distributed_training.ddp_backend == "megatron_ddp" and \
            cfg.distributed_training.accumulate_allreduce_grads_in_fp32, \
                f"Please use *megatron_ddp* and enable accumulate_allreduce_grads_in_fp32 when training with bf16"
    
    if cfg.common.bf16 == False and cfg.common.fp16 == False:
        assert cfg.distributed_training.ddp_backend != "megatron_ddp", "`megatron_ddp` has been disabled in fp32 mode."

    assert cfg.common.fp16_no_flatten_grads == True, "`fp16_no_flatten_grads=false` has been disabled for use!"

    if cfg.common.amp and (cfg.common.fp16 or cfg.common.bf16):
        raise ValueError(f"fp16 and bf16 must be false when amp is enabeld")

    if cfg.common.fp32_residual_connection:
        assert cfg.common.fp16 or cfg.common.bf16, "residual connection in fp32 only supported when using fp16 or bf16."
    
    if cfg.lora.apply_lora:
        if cfg.model_parallel.tensor_model_parallel_size != 1:
            raise ValueError("LoRA does not support tensor parallelism.")
        if cfg.model.from_pretrained is None:
            raise ValueError("Loading pre-trained weights is necessary when using LoRA fine-tuning.")
        if "bias_dropout_fusion" in cfg.model and cfg.model.bias_dropout_fusion:
            cfg.model.bias_dropout_fusion = False
            logger.info("LoRA does not support bias_dropout_fusion")

    # if "using_streaming_iterator" in cfg.task and cfg.task.using_streaming_iterator:
    if getattr(cfg.task, "using_streaming_iterator", False):
        assert getattr(cfg.task, "offline_batches_path", None) is not None and \
            os.path.exists(cfg.task.offline_batches_path), \
            f"offline_batches_path({cfg.task.offline_batches_path} is not exist!)"
        assert cfg.dataset.num_parts == 1, f"num_parts can only be 1 when using streaming iterator"
    
def check_cfgs(cfg: HulkConfig) -> None:
    _check_model_parallel_topo(cfg)
    _check_model_parallel_cfgs(cfg)
    _check_other_cfgs(cfg)


def init_distributed(cfg: HulkConfig) -> None:
    # setting for debug, which enable the same initialization in the same machine
    cudnn.benchmark = True if cfg.common.cudnn_benchmark else False
    cudnn.deterministic = True if cfg.common.cudnn_deterministic else False
    cudnn.enabled = True if cfg.common.cudnn_enabled else False

    if isinstance(cfg, Namespace):
        from TDATR_utils.utils import convert_namespace_to_omegaconf

        cfg = convert_namespace_to_omegaconf(cfg)

    dist_cfg = cfg.distributed_training

    if torch.distributed.is_initialized():
        raise RuntimeError(
            "Distributed is already initialized, cannot initialize twice!"
        )
    assert torch.cuda.is_available()
    device = dist_cfg.distributed_rank % torch.cuda.device_count()
    if dist_cfg.distributed_local_rank is not None:
        assert dist_cfg.distributed_local_rank == device, \
            'expected local-rank to be the same as rank % device-count.'
    else:
        dist_cfg.distributed_local_rank = device
    dist_cfg.device_id = dist_cfg.distributed_local_rank

    logger.info(
        "distributed init (rank {}): {}".format(
            dist_cfg.distributed_rank,
            dist_cfg.distributed_init_method,
        )
    )
    torch.cuda.set_device(device)

    logger.warning(
        "[TDATR_utils_log] sleep success, distributed init (rank {}): {}".format(
            dist_cfg.distributed_rank,
            dist_cfg.distributed_init_method,
        )
    )
    # init global context
    gpc.config = cfg
    gpc.init_global_dist(
        rank=dist_cfg.distributed_rank,
        world_size=dist_cfg.distributed_world_size,
        backend=dist_cfg.distributed_backend,
        host=dist_cfg.distributed_master_addr,
        port=dist_cfg.distributed_master_port
    )

    logger.warning(
        "[TDATR_utils_log] init_global_dist success (rank {}): {}".format(
            dist_cfg.distributed_rank,
            dist_cfg.distributed_init_method,
        )
    )

    # gpc.set_device(device)
    gpc.init_parallel_groups()
    # gather all workers using GLOO group
    gpc.gather_workers()

    logger.info(
        "initialized host {} as rank {}".format(
            socket.gethostname(),
            dist_cfg.distributed_rank,
        )
    )

    # perform a dummy all-reduce to initialize the NCCL communicator
    if torch.cuda.is_available():
        logger.info(
            "{} | {}/{} | Perform a dummy all-reduce to initialize the NCCL communicator".format(
                socket.gethostname(), dist_cfg.distributed_rank, dist_cfg.distributed_world_size
            )
        )
        dist.all_reduce(
            torch.zeros(gpc.get_world_size(ParallelMode.GLOBAL)).cuda(),
            group=gpc.get_group(ParallelMode.GLOBAL))
        if gpc.get_world_size(ParallelMode.DATA) > 1:
            dist.all_reduce(
                torch.zeros(gpc.get_world_size(ParallelMode.DATA)).cuda(),
                group=gpc.get_group(ParallelMode.DATA))
        if gpc.get_world_size(ParallelMode.TENSOR) > 1:
            dist.all_reduce(
                torch.zeros(gpc.get_world_size(ParallelMode.TENSOR)).cuda(),
                group=gpc.get_group(ParallelMode.TENSOR))
        if gpc.get_world_size(ParallelMode.PIPELINE) > 1:
            dist.all_reduce(
                torch.zeros(gpc.get_world_size(ParallelMode.PIPELINE)).cuda(),
                group=gpc.get_group(ParallelMode.PIPELINE))
        logger.info(
            "{} | {}/{} | NCCL communicator initialization succeeded!".format(
                socket.gethostname(), dist_cfg.distributed_rank, dist_cfg.distributed_world_size
            )
        )

    dist_cfg.distributed_rank = torch.distributed.get_rank()

    # init rng seed manager
    gpc.set_seed(cfg.common.seed)
    _set_jit_fusion_options()


def _set_jit_fusion_options():
    """Set PyTorch JIT layer fusion options."""
    # flags required to enable jit fusion kernels
    TORCH_MAJOR = int(torch.__version__.split('.')[0])
    TORCH_MINOR = int(torch.__version__.split('.')[1])
    if (TORCH_MAJOR > 1) or (TORCH_MAJOR == 1 and TORCH_MINOR >= 10):
        # nvfuser
        torch._C._jit_set_profiling_executor(True)
        torch._C._jit_set_profiling_mode(True)
        torch._C._jit_override_can_fuse_on_cpu(False)
        torch._C._jit_override_can_fuse_on_gpu(False)
        torch._C._jit_set_texpr_fuser_enabled(False)
        #torch._C._jit_set_nvfuser_enabled(True)
        torch._C._debug_set_autodiff_subgraph_inlining(False)
    else:
        # legacy pytorch fuser
        torch._C._jit_set_profiling_mode(False)
        torch._C._jit_set_profiling_executor(False)
        torch._C._jit_override_can_fuse_on_cpu(True)
        torch._C._jit_override_can_fuse_on_gpu(True)


def initialize_logging(cfg: OmegaConf) -> None:
    file_name = None
    job_logging_cfg = None
    use_hydra = HydraConfig.initialized() or "job_logging_cfg" in cfg

    if use_hydra:
        if HydraConfig.initialized():
            hydra_config = HydraConfig.get()
            cfg.common.experiment_dir = \
                hydra_config.get("run", {}).get("dir", "./")
        if "job_logging_cfg" in cfg:
            job_logging_cfg = OmegaConf.to_container(cfg.job_logging_cfg)
            file_name = (
                job_logging_cfg
                .get('handlers', {})
                .get('file', {})
                .get('filename', None)
            )
            if file_name is not None:
                cfg.common.log_file = file_name
    else:
        file_name = cfg.common.log_file

    rank = dist.get_rank() if dist.is_initialized() else 0

    # if not using hydra, save config.yaml to exp dir.
    if not use_hydra: 
        os.makedirs(cfg.common.experiment_dir, exist_ok=True)
        os.chdir(cfg.common.experiment_dir)
        if rank == 0:
            cfg_file = "config.yaml"
            if os.path.exists(cfg_file):
                _backup(cfg_file)
            OmegaConf.save(cfg, os.path.join(cfg.common.experiment_dir, cfg_file))

    # setup log file handler
    if file_name is not None:
        # backup history log file
        if rank == 0 and os.path.exists(file_name):
            _backup(file_name)
            assert not os.path.exists(file_name)
        # Wait for backup to be completed
        if dist.is_initialized():
            dist.barrier()

        if use_hydra and job_logging_cfg is not None:
            # first, copy temp log file to dist log file
            temp_file = file_name + ".tempfile"
            if rank == 0 and os.path.exists(temp_file):
                shutil.copyfile(temp_file, file_name)

            # then, remove source file handler(temp file)
            src_file_handler = None
            for handler in logging.root.handlers:
                if (
                    isinstance(handler, logging.FileHandler) \
                    and \
                    temp_file in handler.baseFilename
                ):
                    src_file_handler = handler
                    break

            if src_file_handler is not None:
                logging.root.removeHandler(src_file_handler)
            
            # finally, add new file handler to logging
            # add new file handler to logging from `hydra`
            job_logging_cfg['handlers']['file']['filename'] = file_name
            logging.config.dictConfig(job_logging_cfg)

            if dist.is_initialized():
                dist.barrier()

            # remove source temp log file
            if rank == 0 and os.path.exists(temp_file):
                try:
                    os.remove(temp_file)
                except:
                    pass
        else:
            # add file handler from `cfg.common.log_file`
            format="%(asctime)s | %(levelname)s | %(name)s | %(message)s"
            datefmt="%Y-%m-%d %H:%M:%S"
            file_handler = logging.FileHandler(file_name)
            file_handler.setLevel(getattr(logging, 'INFO'))
            formatter = logging.Formatter(format, datefmt=datefmt)
            file_handler.setFormatter(formatter)
            logging.root.addHandler(file_handler)
        
    
     # set stream/file handler level, only master's level set to `INFO`
    for handler in logging.root.handlers:
        level = logging.INFO if rank == 0 else logging.WARNING
        if (
            isinstance(handler, logging.StreamHandler) \
                and \
            handler.stream.name in {'<stdout>', '<stderr>'}
        ):
            handler.setLevel(level)
        if (
            isinstance(handler, logging.FileHandler) \
            and \
            file_name is not None and file_name in handler.baseFilename
        ):
            handler.setLevel(level)

    if file_name is not None and not cfg.common.disable_dist_logging:
        # Back up log files with the same name
        os.makedirs("logs", exist_ok=True)
        log_name, ext = os.path.splitext(os.path.basename(file_name))
        dist_log_file = os.path.join("logs", f"{log_name}-rank#{rank}{ext}")
        if os.path.exists(dist_log_file):
            _backup(dist_log_file)
            assert not os.path.exists(dist_log_file)

        # add dist logging file handler
        format="%(asctime)s | %(levelname)s | %(name)s | %(message)s"
        datefmt="%Y-%m-%d %H:%M:%S"
        file_handler = logging.FileHandler(dist_log_file)
        file_handler.setLevel(getattr(logging, 'INFO'))
        formatter = logging.Formatter(format, datefmt=datefmt)
        file_handler.setFormatter(formatter)
        logging.root.addHandler(file_handler)

def initialize_hulk(cfg: HulkConfig) -> None:
    logger.warning(
        "[TDATR_utils_log] host {} | rank {} has been started!".format(
            socket.gethostname(),
            cfg.distributed_training.distributed_rank,
        )
    )
    check_cfgs(cfg)
    init_distributed(cfg)
    # initialize_logging(cfg)