@@ -399,83 +399,144 @@ def create(self) -> "Model":
399399 if is_stream_forcing (si ):
400400 continue
401401
402- # extract and setup relevant parameters
403- etc = si ["embed_target_coords" ]
404- tr = si ["target_readout" ]
405- num_layers = tr ["num_layers" ]
406- tr_mlp_hidden_factor = tr ["mlp_hidden_factor" ] if "mlp_hidden_factor" in tr else 2
407- tr_dim_head_proj = tr ["dim_head_proj" ] if "dim_head_proj" in tr else None
408- softcap = tr ["softcap" ] if "softcap" in tr else 0.0
409-
410- dims_embed = [si ["embed_target_coords" ]["dim_embed" ] for _ in range (num_layers + 1 )]
411-
412- if is_root ():
413- logger .info ("{} :: coord embed: :: {}" .format (si ["name" ], dims_embed ))
414-
415- dim_coord_in = self .targets_coords_size [i_stream ]
416-
417- # embedding network for coordinates
418- if etc ["net" ] == "linear" :
419- self .embed_target_coords [stream_name ] = NamedLinear (
420- f"embed_target_coords_{ stream_name } " ,
421- in_features = dim_coord_in ,
422- out_features = dims_embed [0 ],
423- bias = False ,
402+ # skip for the moment to ensure target embedding and tte exist (ordering of
403+ # cf.streams is random)
404+ if si .get ("pred_spatial_shared" ) is None :
405+ # extract and setup relevant parameters
406+ etc = si ["embed_target_coords" ]
407+ tr = si ["target_readout" ]
408+ num_layers = tr ["num_layers" ]
409+ tr_mlp_hidden_factor = (
410+ tr ["mlp_hidden_factor" ] if "mlp_hidden_factor" in tr else 2
424411 )
425- elif etc ["net" ] == "mlp" :
426- self .embed_target_coords [stream_name ] = MLP (
427- dim_coord_in ,
428- dims_embed [0 ],
429- hidden_factor = 8 ,
430- with_residual = False ,
431- dropout_rate = dropout_rate ,
432- norm_eps = self .cf .mlp_norm_eps ,
433- stream_name = f"embed_target_coords_{ stream_name } " ,
434- )
435- else :
436- assert False
412+ tr_dim_head_proj = tr ["dim_head_proj" ] if "dim_head_proj" in tr else None
413+ softcap = tr ["softcap" ] if "softcap" in tr else 0.0
414+
415+ dims_embed = [
416+ si ["embed_target_coords" ]["dim_embed" ] for _ in range (num_layers + 1 )
417+ ]
437418
438- if cf .decoder_type == "Linear" :
439- tte = BilinearDecoder (
440- stream_name ,
441- dims_embed [0 ],
442- cf .ae_global_dim_embed ,
419+ if is_root ():
420+ logger .info ("{} :: coord embed: :: {}" .format (si ["name" ], dims_embed ))
421+
422+ dim_coord_in = self .targets_coords_size [i_stream ]
423+
424+ # embedding network for coordinates
425+ if etc ["net" ] == "linear" :
426+ self .embed_target_coords [stream_name ] = NamedLinear (
427+ f"embed_target_coords_{ stream_name } " ,
428+ in_features = dim_coord_in ,
429+ out_features = dims_embed [0 ],
430+ bias = False ,
431+ )
432+ elif etc ["net" ] == "mlp" :
433+ self .embed_target_coords [stream_name ] = MLP (
434+ dim_coord_in ,
435+ dims_embed [0 ],
436+ hidden_factor = 8 ,
437+ with_residual = False ,
438+ dropout_rate = dropout_rate ,
439+ norm_eps = self .cf .mlp_norm_eps ,
440+ stream_name = f"embed_target_coords_{ stream_name } " ,
441+ )
442+ else :
443+ assert False
444+
445+ if cf .decoder_type == "Linear" :
446+ tte = BilinearDecoder (
447+ stream_name ,
448+ dims_embed [0 ],
449+ cf .ae_global_dim_embed ,
450+ self .targets_num_channels [i_stream ],
451+ )
452+ else :
453+ # target prediction engines
454+ tte_version = (
455+ TargetPredictionEngine
456+ if cf .decoder_type != "PerceiverIOCoordConditioning"
457+ else TargetPredictionEngineClassic
458+ )
459+ tte = tte_version (
460+ cf ,
461+ dims_embed ,
462+ dim_coord_in ,
463+ tr_dim_head_proj ,
464+ tr_mlp_hidden_factor ,
465+ softcap ,
466+ stream_config = si ,
467+ )
468+
469+ self .target_token_engines [stream_name ] = tte
470+
471+ # ensemble prediction heads to provide probabilistic prediction
472+ final_activation = si ["pred_head" ].get ("final_activation" , "Identity" )
473+ if is_root ():
474+ logger .debug (
475+ f"{ final_activation } activation of pred head of { si ['name' ]} stream"
476+ )
477+ self .pred_heads [stream_name ] = EnsPredictionHead (
478+ dims_embed [- 1 ],
443479 self .targets_num_channels [i_stream ],
444- )
445- else :
446- # target prediction engines
447- tte_version = (
448- TargetPredictionEngine
449- if cf .decoder_type != "PerceiverIOCoordConditioning"
450- else TargetPredictionEngineClassic
451- )
452- tte = tte_version (
453- cf ,
454- dims_embed ,
455- dim_coord_in ,
456- tr_dim_head_proj ,
457- tr_mlp_hidden_factor ,
458- softcap ,
480+ si ["pred_head" ]["num_layers" ],
481+ si ["pred_head" ]["ens_size" ],
482+ norm_type = cf .norm_type ,
483+ final_activation = final_activation ,
459484 stream_name = stream_name ,
460485 )
461486
462- self .target_token_engines [stream_name ] = tte
487+ # iterate again to setup shared spatial pred heads if specified in config
488+ for i_stream , si in enumerate (cf .streams ):
489+ stream_name = self .stream_names [i_stream ]
463490
464- # ensemble prediction heads to provide probabilistic prediction
465- final_activation = si ["pred_head" ].get ("final_activation" , "Identity" )
466- if is_root ():
491+ # skip decoder if channels are empty
492+ if is_stream_forcing (si ):
493+ continue
494+
495+ pred_spatial_shared = si .get ("pred_spatial_shared" )
496+ if pred_spatial_shared is not None :
497+ if pred_spatial_shared not in self .stream_names :
498+ msg = f"Stream { stream_name } has pred_spatial_shared={ pred_spatial_shared } "
499+ msg += " but no stream with that name found."
500+ raise ValueError (msg )
501+ if pred_spatial_shared == stream_name :
502+ msg = f"Stream { stream_name } has pred_spatial_shared={ pred_spatial_shared } "
503+ msg += "but cannot share with itself."
504+ raise ValueError (msg )
467505 logger .debug (
468- f"{ final_activation } activation of predictionhead of { si ['name' ]} stream"
506+ f"{ stream_name } shares spatial prediction head with { pred_spatial_shared } ."
507+ )
508+
509+ self .embed_target_coords [stream_name ] = self .embed_target_coords [
510+ pred_spatial_shared
511+ ]
512+ self .target_token_engines [stream_name ] = self .target_token_engines [
513+ pred_spatial_shared
514+ ]
515+
516+ idx_shared_s = [
517+ i for i , so in enumerate (cf .streams ) if so ["name" ] == pred_spatial_shared
518+ ]
519+ assert (len (idx_shared_s )) == 1
520+ si_other = cf .streams [idx_shared_s [0 ]]
521+ dims_embed = [
522+ si_other ["embed_target_coords" ]["dim_embed" ] for _ in range (num_layers + 1 )
523+ ]
524+
525+ # ensemble prediction heads to provide probabilistic prediction
526+ final_activation = si ["pred_head" ].get ("final_activation" , "Identity" )
527+ if is_root ():
528+ logger .debug (
529+ f"{ final_activation } activation of pred head of { si ['name' ]} stream"
530+ )
531+ self .pred_heads [stream_name ] = EnsPredictionHead (
532+ dims_embed [- 1 ],
533+ self .targets_num_channels [i_stream ],
534+ si ["pred_head" ]["num_layers" ],
535+ si ["pred_head" ]["ens_size" ],
536+ norm_type = cf .norm_type ,
537+ final_activation = final_activation ,
538+ stream_name = stream_name ,
469539 )
470- self .pred_heads [stream_name ] = EnsPredictionHead (
471- dims_embed [- 1 ],
472- self .targets_num_channels [i_stream ],
473- si ["pred_head" ]["num_layers" ],
474- si ["pred_head" ]["ens_size" ],
475- norm_type = cf .norm_type ,
476- final_activation = final_activation ,
477- stream_name = stream_name ,
478- )
479540
480541 # Latent heads for losses
481542 self .latent_heads = nn .ModuleDict ()
0 commit comments