File size: 7,155 Bytes
3de4238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import torch
import torch
from collections import OrderedDict

def load_t5_from_3dllm_ckpt_V2(ckpt_path, t5, device="cpu"):
    obj = torch.load(ckpt_path, map_location=device, weights_only=False)
    sd = obj.get("model", obj)

    def fit_vocab(src, tgt_shape):
        if list(src.shape) == list(tgt_shape):
            return src
        Vsrc, D = src.shape
        Vtgt, D2 = tgt_shape
        assert D == D2, f"embed dim mismatch {D} vs {D2}"
        if Vsrc > Vtgt:
            raise ValueError(f"Checkpoint vocab {Vsrc} > model vocab {Vtgt}")
        pad = torch.zeros((Vtgt - Vsrc, D), dtype=src.dtype, device=src.device)
        return torch.cat([src, pad], dim=0)

    new_sd = OrderedDict()
    for name, param in t5.state_dict().items():
        ckpt_name = name if name in sd else f"t5_model.{name}"
        if ckpt_name not in sd:
            continue
        w = sd[ckpt_name]
        if "embed_tokens.weight" in name or "shared.weight" in name or "lm_head.weight" in name:
            w = fit_vocab(w, param.shape)
        new_sd[name] = w

    t5.load_state_dict(new_sd, strict=False)
    t5.tie_weights()
    return t5


def load_t5_from_3dllm_ckpt(ckpt_path, t5, device="cpu"):
    
    obj = torch.load(ckpt_path, map_location=device, weights_only=False)
    sd = obj.get("model", obj)

    def take(key):
        # 3d llm keys start with : 't5_model.xxx'
        k = key if key in sd else f"t5_model.{key}"
        return sd[k]
    def fit_vocab(src, tgt_shape):  # (Vsrc, D) -> (Vtgt, D)
        if list(src.shape) == list(tgt_shape):
            return src
        Vsrc, D = src.shape
        Vtgt, D2 = tgt_shape
        assert D == D2, f"embed dim mismatch {D} vs {D2}"
        if Vsrc >= Vtgt:  #
            raise Exception('the source(checkpoint) must have smaller vocab size')
        pad = torch.zeros((Vtgt - Vsrc, D), dtype=src.dtype)
        return torch.cat([src, pad], dim=0)

    with torch.no_grad():
        # shared / embed_tokens / lm_head
        sw = take("shared.weight")
        t5.shared.weight.copy_(fit_vocab(sw, t5.shared.weight.shape))

        ew = take("encoder.embed_tokens.weight")
        t5.encoder.embed_tokens.weight.copy_(fit_vocab(ew, t5.encoder.embed_tokens.weight.shape))

        dw = take("decoder.embed_tokens.weight")
        t5.decoder.embed_tokens.weight.copy_(fit_vocab(dw, t5.decoder.embed_tokens.weight.shape))

        lw = take("lm_head.weight")
        t5.lm_head.weight.copy_(fit_vocab(lw, t5.lm_head.weight.shape))

    t5.tie_weights()
    return t5
    
def load_pretrained(cfg, model, logger=None, phase="train"):
    if logger is not None:
        logger.info(f"Loading pretrain model from {cfg.TRAIN.PRETRAINED}")

    if phase == "train":
        ckpt_path = cfg.TRAIN.PRETRAINED
    elif phase == "test":
        ckpt_path = cfg.TEST.CHECKPOINTS

    state_dict = torch.load(ckpt_path, map_location="cpu", weights_only=False)["state_dict"]

    ignore_prefixes = []

    # dangerous modification
    if cfg.TRAIN.get('LOAD_CKPT_WO_TP_ENC', False):
        ignore_prefixes.append("three_points_proj.")

    # GRPO validation: exclude ref_model weights from checkpoint
    if cfg.TRAIN.get('GRPO_VAL', False):
        ignore_prefixes.append("ref_model.")

    if ignore_prefixes:
        state_dict = {k: v for k, v in state_dict.items()
                      if not any(k.startswith(p) for p in ignore_prefixes)}
        if logger is not None:
            logger.info(f"Filtered out keys with prefixes: {ignore_prefixes}")
        model.load_state_dict(state_dict, strict=False)
    else:
        model.load_state_dict(state_dict, strict=False)
    return model


def load_pretrained_vae(cfg, model, logger=None):
    state_dict = torch.load(cfg.TRAIN.PRETRAINED_VAE,
                            map_location="cpu")['state_dict']
    if logger is not None:
        logger.info(f"Loading pretrain vae from {cfg.TRAIN.PRETRAINED_VAE}")
        
    # Extract encoder/decoder
    from collections import OrderedDict
    vae_dict = OrderedDict()
    for k, v in state_dict.items():
        if "motion_vae" in k:
            name = k.replace("motion_vae.", "")
            vae_dict[name] = v
        elif "vae" in k:
            name = k.replace("vae.", "")
            vae_dict[name] = v
    if hasattr(model, 'vae'):
        model.vae.load_state_dict(vae_dict, strict=True)
    else:
        model.motion_vae.load_state_dict(vae_dict, strict=True)
    
    return model


def load_pretrained_grpo_ref(cfg, model, logger=None):
    """Load GRPO reference model from checkpoint.

    Reference model is co-located with the main model on each rank's device.
    The legacy ``GRPO_REF_DEVICE`` setting is intentionally ignored: with DDP,
    Lightning recursively moves child submodules to the per-rank device, so any
    fixed device string would go stale and trigger cross-device tensor moves.
    """
    ref_path = cfg.TRAIN.GRPO_REF_MODEL_PATH
    ref_device = model.device
    if logger is not None:
        logger.info(f"Loading GRPO reference model from {ref_path}")
        logger.info(f"Reference model will be placed on {ref_device} (co-located with main model)")

    from mGPT.models.build_model import build_model

    # Create ref model with same architecture as training model
    ref_model = build_model(cfg, model.datamodule)

    # Add same special tokens as training model
    if cfg.model.params.get("dummy_motion", False):
        ref_model.lm.init_dummy_motion_token(
            cfg.model.params.p_dummy,
            cfg.model.params.per_token,
            cfg.model.params.get('use_single_span', False),
            cfg.model.params.get('span_pairs', 6),
            cfg.model.params.get('p_span', 1.0)
        )
    if cfg.model.params.get("tp_special_token", False):
        ref_model.lm.init_tp_special_token()
    if cfg.LOSS.ABLATION.get("TRAIN_ALL_AT_ONCE", False):
        ref_model.lm.init_text_special_token()
    if cfg.TRAIN.get("CHAIN_OF_THOUGHT", False):
        ref_model.lm.init_cot_special_token()

    # Load state dict (vocab size now matches checkpoint)
    state_dict = torch.load(ref_path, map_location="cpu", weights_only=False)["state_dict"]
    # If the ckpt itself was a GRPO save (contains its own nested ref_model.*
    # subtree), strip that prefix — those keys would otherwise be unexpected
    # in a fresh MotionGPT (= ref_model) which has no nested ref_model. Same
    # for three_points_proj when LOAD_CKPT_WO_TP_ENC is set.
    ignore_prefixes = ["ref_model."]
    if cfg.TRAIN.get('LOAD_CKPT_WO_TP_ENC', False):
        ignore_prefixes.append("three_points_proj.")
    state_dict = {k: v for k, v in state_dict.items()
                  if not any(k.startswith(p) for p in ignore_prefixes)}
    # strict=False to also tolerate any benign add/remove (e.g. peft wrapping
    # differences when the ckpt was full-FT but config wraps with LoRA).
    ref_model.load_state_dict(state_dict, strict=False)

    ref_model = ref_model.to(ref_device)
    ref_model.eval()

    # Freeze all parameters
    for param in ref_model.parameters():
        param.requires_grad = False

    model.ref_model = ref_model

    return model