@@ -1297,6 +1297,9 @@ def __init__(
12971297 label_threshold = 0. ,
12981298 label_epsilon = 0. ,
12991299 pos_weight = None ,
1300+ gij_guidance = 0 ,
1301+ gij_cutoff = 6 ,
1302+ gij_noise = 0.15 ,
13001303 focal_loss = 0. ,
13011304 shard_size = 2048
13021305 ):
@@ -1348,6 +1351,12 @@ def __init__(
13481351 else :
13491352 self .pos_weight = None
13501353 self .alpha = alpha
1354+
1355+ # gating guided by inter-chain contact
1356+ self .gij_guidance = gij_guidance
1357+ self .gij_cutoff = gij_cutoff
1358+ self .gij_noise = gij_noise
1359+
13511360 self .focal_loss = focal_loss
13521361 self .shard_size = env ('profold2_fitness_shard_size' , defval = shard_size , dtype = int )
13531362 self .return_motifs = env ('profold2_fitness_return_motifs' , defval = True , dtype = bool )
@@ -1452,6 +1461,44 @@ def loss(self, value, batch):
14521461 num_class = self .mask .shape [0 ]
14531462 avg_error_motif = 0
14541463
1464+ avg_error_gij = 0
1465+ if self .gij_guidance > 0 and 'pseudo_beta' in batch :
1466+ positions = batch ['pseudo_beta' ]
1467+ mask = batch ['pseudo_beta_mask' ]
1468+ seq_color = batch ["seq_color" ]
1469+ assert positions .shape [- 1 ] == 3
1470+
1471+ targets = F .sigmoid (self .gij_cutoff - torch .cdist (positions , positions ))
1472+ targets = targets * mask [..., :, None ] * mask [..., None , :] * (
1473+ seq_color [..., :, None ] != seq_color [..., None , :]
1474+ ) * (targets >= self .gij_noise )
1475+ targets = repeat (targets , "...->... t" , t = self .task_num )
1476+ if 'variant_task_mask' in batch :
1477+ variant_task_mask = batch ['variant_task_mask' ][..., 0 , :, :]
1478+ targets = targets * (
1479+ variant_task_mask [..., :, None , :] * variant_task_mask [..., None , :, :]
1480+ )
1481+ targets = torch .clamp (
1482+ 1. - torch .exp (
1483+ torch .sum (torch .log (torch .clamp (1 - targets , min = 1e-10 , max = 1. )), dim = - 2 )
1484+ ), min = 0
1485+ )
1486+
1487+ mask = mask [..., None ] * torch .any (
1488+ seq_color [..., :, None ] != seq_color [..., None , :], dim = - 1 , keepdim = True
1489+ )
1490+ if 'variant_task_mask' in batch :
1491+ mask = mask * batch ['variant_task_mask' ][..., 0 , :, :]
1492+
1493+ logger .info ('FitnessHead.gij.loss.targets: %s' , torch .sum (targets >= 0.5 , dim = - 2 ))
1494+ logger .info ('FitnessHead.gij.loss.masked: %s' , torch .sum (mask , dim = - 2 ))
1495+
1496+ errors = sigmoid_cross_entropy (gating , targets , gammar = self .focal_loss )
1497+
1498+ avg_error_gij = functional .masked_mean (value = errors , mask = mask , epsilon = 1e-6 )
1499+ logger .info ('FitnessHead.gij.loss: %s' , avg_error_gij )
1500+ avg_error_gij = self .gij_guidance * avg_error_gij
1501+
14551502 if 'variant' in batch :
14561503 variant_mask = batch ['variant_mask' ]
14571504 variant_label = batch ['variant_label' ]
@@ -1581,7 +1628,7 @@ def loss(self, value, batch):
15811628 value = errors , mask = variant_label_mask * self .task_weight
15821629 )
15831630 logger .debug ('FitnessHead.loss: %s' , avg_error_fitness )
1584- return dict (loss = avg_error_motif + avg_error_fitness )
1631+ return dict (loss = avg_error_gij + avg_error_motif + avg_error_fitness )
15851632
15861633
15871634class SequenceProfileHead (nn .Module ):
0 commit comments