File size: 6,626 Bytes
872b0a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Copyright (c) Meta Platforms, Inc. and affiliates.
"""

import math
import os
import random

# import shutil

import numpy as np
import torch

# import torch.nn as nn
# import torch.nn.functional as F
from torch.optim import Optimizer
from utils.manifold_utils import MANIFOLD_BUCKET, pathmgr


def init_seed(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)


def weight_parameters(module):
    return [param for name, param in module.named_parameters() if ".weight" in name]


def bias_parameters(module):
    return [param for name, param in module.named_parameters() if ".bias" in name]


def other_parameters(module):
    return [
        param
        for name, param in module.named_parameters()
        if ".bias" not in name and ".weight" not in name
    ]


def load_checkpoint(model_path):
    # weights = torch.load(model_path)

    if "manifold" not in model_path:
        model_path = os.path.join("manifold://" + MANIFOLD_BUCKET, model_path)
    with pathmgr.open(model_path, "rb") as f:
        for i in range(3):
            try:
                weights = torch.load(f)
                break
            except Exception:
                if i == 2:
                    raise Exception

    epoch = None
    if "epoch" in weights:
        epoch = weights.pop("epoch")
    if "state_dict" in weights:
        state_dict = weights["state_dict"]
    else:
        state_dict = weights
    return epoch, state_dict


def save_checkpoint(save_path, states, file_prefixes, is_best, filename="ckpt.pth.tar"):
    def run_one_sample(save_path, state, prefix, is_best, filename):
        # torch.save(state, os.path.join(save_path, "{}_{}".format(prefix, filename)))

        if "manifold" not in save_path:
            save_path = os.path.join("manifold://" + MANIFOLD_BUCKET, save_path)
        save_path = os.path.join(save_path, "{}_{}".format(prefix, filename))
        with pathmgr.open(save_path, "wb") as f:
            for i in range(3):
                try:
                    torch.save(state, f)
                    return
                except Exception:
                    if i == 2:
                        raise Exception

    if not isinstance(file_prefixes, str):
        for (prefix, state) in zip(file_prefixes, states):
            run_one_sample(save_path, state, prefix, is_best, filename)

    else:
        run_one_sample(save_path, states, file_prefixes, is_best, filename)


def restore_model(model, pretrained_file):
    epoch, weights = load_checkpoint(pretrained_file)

    model_keys = set(model.state_dict().keys())
    weight_keys = set(weights.keys())

    # load weights by name
    weights_not_in_model = sorted(weight_keys - model_keys)
    model_not_in_weights = sorted(model_keys - weight_keys)
    if len(model_not_in_weights):
        print("Warning: There are weights in model but not in pre-trained.")
        for key in model_not_in_weights:
            print(key)
            weights[key] = model.state_dict()[key]
    if len(weights_not_in_model):
        print("Warning: There are pre-trained weights not in model.")
        for key in weights_not_in_model:
            print(key)
        from collections import OrderedDict

        new_weights = OrderedDict()
        for key in model_keys:
            new_weights[key] = weights[key]
        weights = new_weights

    model.load_state_dict(weights)
    return model


class AdamW(Optimizer):
    """Implements AdamW algorithm.

    It has been proposed in `Fixing Weight Decay Regularization in Adam`_.

    Arguments:
        params (iterable): iterable of parameters to optimize or dicts defining
            parameter groups
        lr (float, optional): learning rate (default: 1e-3)
        betas (Tuple[float, float], optional): coefficients used for computing
            running averages of gradient and its square (default: (0.9, 0.999))
        eps (float, optional): term added to the denominator to improve
            numerical stability (default: 1e-8)
        weight_decay (float, optional): weight decay (L2 penalty) (default: 0)

    .. Fixing Weight Decay Regularization in Adam:
    https://arxiv.org/abs/1711.05101
    """

    def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0):
        defaults = {"lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay}
        super(AdamW, self).__init__(params, defaults)

    def step(self, closure=None):
        """Performs a single optimization step.

        Arguments:
            closure (callable, optional): A closure that reevaluates the model
                and returns the loss.
        """
        loss = None
        if closure is not None:
            loss = closure()

        for group in self.param_groups:
            for p in group["params"]:
                if p.grad is None:
                    continue
                grad = p.grad.data
                if grad.is_sparse:
                    raise RuntimeError(
                        "AdamW does not support sparse gradients, please consider SparseAdam instead"
                    )

                state = self.state[p]

                # State initialization
                if len(state) == 0:
                    state["step"] = 0
                    # Exponential moving average of gradient values
                    state["exp_avg"] = torch.zeros_like(p.data)
                    # Exponential moving average of squared gradient values
                    state["exp_avg_sq"] = torch.zeros_like(p.data)

                exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"]
                beta1, beta2 = group["betas"]

                state["step"] += 1

                # according to the paper, this penalty should come after the bias correction
                # if group['weight_decay'] != 0:
                #     grad = grad.add(group['weight_decay'], p.data)

                # Decay the first and second moment running average coefficient
                exp_avg.mul_(beta1).add_(1 - beta1, grad)
                exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad)

                denom = exp_avg_sq.sqrt().add_(group["eps"])

                bias_correction1 = 1 - beta1 ** state["step"]
                bias_correction2 = 1 - beta2 ** state["step"]
                step_size = group["lr"] * math.sqrt(bias_correction2) / bias_correction1

                p.data.addcdiv_(-step_size, exp_avg, denom)

                if group["weight_decay"] != 0:
                    p.data.add_(-group["weight_decay"], p.data)

        return loss