CoolFace
Apppublic

RabbitRUI/ruispace

sourceHugging Facemitupdated 3y agoView on Hugging Face
0likes
base_model.py317 linesDownload Raw Back to models
1"""This script defines the base network model for Deep3DFaceRecon_pytorch2"""3 4import os5import numpy as np6import torch7from collections import OrderedDict8from abc import ABC, abstractmethod9from . import networks10 11 12class BaseModel(ABC):13    """This class is an abstract base class (ABC) for models.14    To create a subclass, you need to implement the following five functions:15        -- <__init__>:                      initialize the class; first call BaseModel.__init__(self, opt).16        -- <set_input>:                     unpack data from dataset and apply preprocessing.17        -- <forward>:                       produce intermediate results.18        -- <optimize_parameters>:           calculate losses, gradients, and update network weights.19        -- <modify_commandline_options>:    (optionally) add model-specific options and set default options.20    """21 22    def __init__(self, opt):23        """Initialize the BaseModel class.24 25        Parameters:26            opt (Option class)-- stores all the experiment flags; needs to be a subclass of BaseOptions27 28        When creating your custom class, you need to implement your own initialization.29        In this fucntion, you should first call <BaseModel.__init__(self, opt)>30        Then, you need to define four lists:31            -- self.loss_names (str list):          specify the training losses that you want to plot and save.32            -- self.model_names (str list):         specify the images that you want to display and save.33            -- self.visual_names (str list):        define networks used in our training.34            -- self.optimizers (optimizer list):    define and initialize optimizers. You can define one optimizer for each network. If two networks are updated at the same time, you can use itertools.chain to group them. See cycle_gan_model.py for an example.35        """36        self.opt = opt37        self.isTrain = False38        self.device = torch.device('cpu') 39        self.save_dir = " " # os.path.join(opt.checkpoints_dir, opt.name)  # save all the checkpoints to save_dir40        self.loss_names = []41        self.model_names = []42        self.visual_names = []43        self.parallel_names = []44        self.optimizers = []45        self.image_paths = []46        self.metric = 0  # used for learning rate policy 'plateau'47 48    @staticmethod49    def dict_grad_hook_factory(add_func=lambda x: x):50        saved_dict = dict()51 52        def hook_gen(name):53            def grad_hook(grad):54                saved_vals = add_func(grad)55                saved_dict[name] = saved_vals56            return grad_hook57        return hook_gen, saved_dict58 59    @staticmethod60    def modify_commandline_options(parser, is_train):61        """Add new model-specific options, and rewrite default values for existing options.62 63        Parameters:64            parser          -- original option parser65            is_train (bool) -- whether training phase or test phase. You can use this flag to add training-specific or test-specific options.66 67        Returns:68            the modified parser.69        """70        return parser71 72    @abstractmethod73    def set_input(self, input):74        """Unpack input data from the dataloader and perform necessary pre-processing steps.75 76        Parameters:77            input (dict): includes the data itself and its metadata information.78        """79        pass80 81    @abstractmethod82    def forward(self):83        """Run forward pass; called by both functions <optimize_parameters> and <test>."""84        pass85 86    @abstractmethod87    def optimize_parameters(self):88        """Calculate losses, gradients, and update network weights; called in every training iteration"""89        pass90 91    def setup(self, opt):92        """Load and print networks; create schedulers93 94        Parameters:95            opt (Option class) -- stores all the experiment flags; needs to be a subclass of BaseOptions96        """97        if self.isTrain:98            self.schedulers = [networks.get_scheduler(optimizer, opt) for optimizer in self.optimizers]99        100        if not self.isTrain or opt.continue_train:101            load_suffix = opt.epoch102            self.load_networks(load_suffix)103 104            105        # self.print_networks(opt.verbose)106 107    def parallelize(self, convert_sync_batchnorm=True):108        if not self.opt.use_ddp:109            for name in self.parallel_names:110                if isinstance(name, str):111                    module = getattr(self, name)112                    setattr(self, name, module.to(self.device))113        else:114            for name in self.model_names:115                if isinstance(name, str):116                    module = getattr(self, name)117                    if convert_sync_batchnorm:118                        module = torch.nn.SyncBatchNorm.convert_sync_batchnorm(module)119                    setattr(self, name, torch.nn.parallel.DistributedDataParallel(module.to(self.device),120                        device_ids=[self.device.index], 121                        find_unused_parameters=True, broadcast_buffers=True))122            123            # DistributedDataParallel is not needed when a module doesn't have any parameter that requires a gradient.124            for name in self.parallel_names:125                if isinstance(name, str) and name not in self.model_names:126                    module = getattr(self, name)127                    setattr(self, name, module.to(self.device))128            129        # put state_dict of optimizer to gpu device130        if self.opt.phase != 'test':131            if self.opt.continue_train:132                for optim in self.optimizers:133                    for state in optim.state.values():134                        for k, v in state.items():135                            if isinstance(v, torch.Tensor):136                                state[k] = v.to(self.device)137 138    def data_dependent_initialize(self, data):139        pass140 141    def train(self):142        """Make models train mode"""143        for name in self.model_names:144            if isinstance(name, str):145                net = getattr(self, name)146                net.train()147 148    def eval(self):149        """Make models eval mode"""150        for name in self.model_names:151            if isinstance(name, str):152                net = getattr(self, name)153                net.eval()154 155    def test(self):156        """Forward function used in test time.157 158        This function wraps <forward> function in no_grad() so we don't save intermediate steps for backprop159        It also calls <compute_visuals> to produce additional visualization results160        """161        with torch.no_grad():162            self.forward()163            self.compute_visuals()164 165    def compute_visuals(self):166        """Calculate additional output images for visdom and HTML visualization"""167        pass168 169    def get_image_paths(self, name='A'):170        """ Return image paths that are used to load current data"""171        return self.image_paths if name =='A' else self.image_paths_B172 173    def update_learning_rate(self):174        """Update learning rates for all the networks; called at the end of every epoch"""175        for scheduler in self.schedulers:176            if self.opt.lr_policy == 'plateau':177                scheduler.step(self.metric)178            else:179                scheduler.step()180 181        lr = self.optimizers[0].param_groups[0]['lr']182        print('learning rate = %.7f' % lr)183 184    def get_current_visuals(self):185        """Return visualization images. train.py will display these images with visdom, and save the images to a HTML"""186        visual_ret = OrderedDict()187        for name in self.visual_names:188            if isinstance(name, str):189                visual_ret[name] = getattr(self, name)[:, :3, ...]190        return visual_ret191 192    def get_current_losses(self):193        """Return traning losses / errors. train.py will print out these errors on console, and save them to a file"""194        errors_ret = OrderedDict()195        for name in self.loss_names:196            if isinstance(name, str):197                errors_ret[name] = float(getattr(self, 'loss_' + name))  # float(...) works for both scalar tensor and float number198        return errors_ret199 200    def save_networks(self, epoch):201        """Save all the networks to the disk.202 203        Parameters:204            epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name)205        """206        if not os.path.isdir(self.save_dir):207            os.makedirs(self.save_dir)208 209        save_filename = 'epoch_%s.pth' % (epoch)210        save_path = os.path.join(self.save_dir, save_filename)211        212        save_dict = {}213        for name in self.model_names:214            if isinstance(name, str):215                net = getattr(self, name)216                if isinstance(net, torch.nn.DataParallel) or isinstance(net,217                        torch.nn.parallel.DistributedDataParallel):218                    net = net.module219                save_dict[name] = net.state_dict()220                221 222        for i, optim in enumerate(self.optimizers):223            save_dict['opt_%02d'%i] = optim.state_dict()224 225        for i, sched in enumerate(self.schedulers):226            save_dict['sched_%02d'%i] = sched.state_dict()227        228        torch.save(save_dict, save_path)229 230    def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0):231        """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)"""232        key = keys[i]233        if i + 1 == len(keys):  # at the end, pointing to a parameter/buffer234            if module.__class__.__name__.startswith('InstanceNorm') and \235                    (key == 'running_mean' or key == 'running_var'):236                if getattr(module, key) is None:237                    state_dict.pop('.'.join(keys))238            if module.__class__.__name__.startswith('InstanceNorm') and \239               (key == 'num_batches_tracked'):240                state_dict.pop('.'.join(keys))241        else:242            self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1)243 244    def load_networks(self, epoch):245        """Load all the networks from the disk.246 247        Parameters:248            epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name)249        """250        if self.opt.isTrain and self.opt.pretrained_name is not None:251            load_dir = os.path.join(self.opt.checkpoints_dir, self.opt.pretrained_name)252        else:253            load_dir = self.save_dir    254        load_filename = 'epoch_%s.pth' % (epoch)255        load_path = os.path.join(load_dir, load_filename)256        state_dict = torch.load(load_path, map_location=self.device)257        print('loading the model from %s' % load_path)258 259        for name in self.model_names:260            if isinstance(name, str):261                net = getattr(self, name)262                if isinstance(net, torch.nn.DataParallel):263                    net = net.module264                net.load_state_dict(state_dict[name])265        266        if self.opt.phase != 'test':267            if self.opt.continue_train:268                print('loading the optim from %s' % load_path)269                for i, optim in enumerate(self.optimizers):270                    optim.load_state_dict(state_dict['opt_%02d'%i])271 272                try:273                    print('loading the sched from %s' % load_path)274                    for i, sched in enumerate(self.schedulers):275                        sched.load_state_dict(state_dict['sched_%02d'%i])276                except:277                    print('Failed to load schedulers, set schedulers according to epoch count manually')278                    for i, sched in enumerate(self.schedulers):279                        sched.last_epoch = self.opt.epoch_count - 1280                    281 282            283 284    def print_networks(self, verbose):285        """Print the total number of parameters in the network and (if verbose) network architecture286 287        Parameters:288            verbose (bool) -- if verbose: print the network architecture289        """290        print('---------- Networks initialized -------------')291        for name in self.model_names:292            if isinstance(name, str):293                net = getattr(self, name)294                num_params = 0295                for param in net.parameters():296                    num_params += param.numel()297                if verbose:298                    print(net)299                print('[Network %s] Total number of parameters : %.3f M' % (name, num_params / 1e6))300        print('-----------------------------------------------')301 302    def set_requires_grad(self, nets, requires_grad=False):303        """Set requies_grad=Fasle for all the networks to avoid unnecessary computations304        Parameters:305            nets (network list)   -- a list of networks306            requires_grad (bool)  -- whether the networks require gradients or not307        """308        if not isinstance(nets, list):309            nets = [nets]310        for net in nets:311            if net is not None:312                for param in net.parameters():313                    param.requires_grad = requires_grad314 315    def generate_visuals_for_evaluation(self, data, mode):316        return {}317