4242from cppmega_v4 .jsonrpc .schema import VerifyParams
4343
4444
45- StageStatus = Literal ["ok" , "skipped" , "fail" ]
45+ StageStatus = Literal ["ok" , "skipped" , "fail" , "cancelled" ]
4646
4747
4848@dataclass
@@ -119,6 +119,36 @@ def _fail(name: str, t0: float, exc: BaseException) -> StageResult:
119119 )
120120
121121
122+ def _cancelled_train_result (
123+ t0 : float ,
124+ * ,
125+ abort_token : str ,
126+ step : int ,
127+ losses : list [float ],
128+ lr_trajectory : list [float ],
129+ schedule_kind_label : str ,
130+ optimizer_kind : str ,
131+ weight_delta_norm : float = 0.0 ,
132+ ) -> StageResult :
133+ clear_abort (abort_token )
134+ return StageResult (
135+ name = "train" , status = "cancelled" ,
136+ elapsed_ms = (time .perf_counter () - t0 ) * 1000.0 ,
137+ extras = {
138+ "losses" : [round (loss_item , 4 ) for loss_item in losses ],
139+ "lr_trajectory" : [
140+ round (lr_item , 6 ) for lr_item in lr_trajectory
141+ ],
142+ "weight_delta_norm" : round (weight_delta_norm , 6 ),
143+ "num_steps" : step ,
144+ "schedule_kind" : schedule_kind_label ,
145+ "optimizer_kind" : optimizer_kind ,
146+ "aborted" : True ,
147+ "abort_token" : abort_token ,
148+ },
149+ )
150+
151+
122152def stage_parse (ctx : StageContext ) -> StageResult :
123153 """Materialise loss/optim/graph from the wire-form spec."""
124154 t0 = time .perf_counter ()
@@ -726,7 +756,14 @@ def loss_fn(model: nn.Module, emb: mx.array, tgt: mx.array) -> mx.array:
726756 token_count = len (tokens )
727757 except Exception :
728758 pass
759+ train_token_embedding = None
760+ train_input_source = "random"
761+ if data_source != "synthetic" :
762+ train_token_embedding = nn .Embedding (vocab_size , hidden )
763+ train_input_source = "token_embedding"
729764 all_modules = nn .Sequential (* modules , * lm_heads )
765+ if train_token_embedding is not None :
766+ all_modules .train_token_embedding = train_token_embedding
730767 if side_channel_token_embedding is not None :
731768 all_modules .side_channel_token_embedding = side_channel_token_embedding
732769 opt , optimizer_kind = _build_optimizer (spec_optim , lr )
@@ -939,21 +976,14 @@ def _count(tree: Any) -> int:
939976 for step in range (n_steps ):
940977 if abort_token is not None and abort_token in _ABORT_TOKENS :
941978 # Stop early; return partial extras with cancellation flag.
942- return StageResult (
943- name = "train" , status = "ok" ,
944- elapsed_ms = (time .perf_counter () - t0 ) * 1000.0 ,
945- extras = {
946- "losses" : [round (loss_item , 4 )
947- for loss_item in losses ],
948- "lr_trajectory" : [round (lr_item , 6 )
949- for lr_item in lr_trajectory ],
950- "weight_delta_norm" : 0.0 ,
951- "num_steps" : step ,
952- "schedule_kind" : schedule_kind_label ,
953- "optimizer_kind" : optimizer_kind ,
954- "aborted" : True ,
955- "abort_token" : abort_token ,
956- },
979+ return _cancelled_train_result (
980+ t0 ,
981+ abort_token = str (abort_token ),
982+ step = step ,
983+ losses = losses ,
984+ lr_trajectory = lr_trajectory ,
985+ schedule_kind_label = schedule_kind_label ,
986+ optimizer_kind = optimizer_kind ,
957987 )
958988 # If a schedule callable exists, override optimizer's
959989 # learning_rate per step. MLX optimizers accept a fresh
@@ -965,8 +995,11 @@ def _count(tree: Any) -> int:
965995 else :
966996 lr_trajectory .append (lr )
967997
968- emb = mx .random .normal (shape = (batch , seq , hidden ), key = rng_key )
969- rng_key , _ = mx .random .split (rng_key )
998+ if train_token_embedding is None :
999+ emb = mx .random .normal (shape = (batch , seq , hidden ), key = rng_key )
1000+ rng_key , _ = mx .random .split (rng_key )
1001+ else :
1002+ emb = train_token_embedding (targets )
9701003 loss , grads = loss_and_grad (all_modules , emb , targets )
9711004 mx .eval (loss , grads )
9721005 if probe_key is None :
@@ -1002,6 +1035,25 @@ def _count(tree: Any) -> int:
10021035 opt .update (all_modules , grads )
10031036 mx .eval (all_modules .parameters (), opt .state )
10041037 losses .append (float (loss .item ()))
1038+ if abort_token is not None and abort_token in _ABORT_TOKENS :
1039+ partial_delta = 0.0
1040+ if probe_key is not None and probe_before is not None :
1041+ after_flat = dict (
1042+ nn .utils .tree_flatten (all_modules .parameters ()))
1043+ partial_delta = float (
1044+ mx .linalg .norm (
1045+ after_flat [probe_key ] - probe_before ).item ()
1046+ )
1047+ return _cancelled_train_result (
1048+ t0 ,
1049+ abort_token = str (abort_token ),
1050+ step = step + 1 ,
1051+ losses = losses ,
1052+ lr_trajectory = lr_trajectory ,
1053+ schedule_kind_label = schedule_kind_label ,
1054+ optimizer_kind = optimizer_kind ,
1055+ weight_delta_norm = partial_delta ,
1056+ )
10051057
10061058 try :
10071059 if hasattr (mx , "metal" ):
@@ -1110,6 +1162,7 @@ def _count(tree: Any) -> int:
11101162 "schedule_kind" : schedule_kind_label ,
11111163 "optimizer_kind" : optimizer_kind ,
11121164 "data_source" : data_source ,
1165+ "train_input_source" : train_input_source ,
11131166 "token_count" : token_count ,
11141167 "tokenizer_used" : tokenizer_used ,
11151168 "loss_kind" : (
0 commit comments