kelu01 commited on
Commit
cf604be
·
verified ·
1 Parent(s): 4792a76

Update pipe.py

Browse files
Files changed (1) hide show
  1. pipe.py +56 -43
pipe.py CHANGED
@@ -78,54 +78,67 @@ class SmilesDiffusionPipe(Pipeline):
78
  return torch.multinomial(probs, 1)
79
 
80
 
81
- def unmask_partial_smiles(self, input_ids, model, voc, steps, k):
82
- """
83
- Iteratively unmask a single SMILES string using a diffusion model.
84
- Always fills the masked token with highest confidence first until done.
85
- """
86
- pad_token = voc.vocab["[PAD]"]
87
- mask_token = voc.vocab["[MASK]"]
88
-
89
- # Encode input SMILES
90
- encoded = voc.encode(voc.tokenize(input_ids))
91
- unmasked = torch.tensor(encoded, dtype=torch.long).unsqueeze(0).to(device)
92
-
93
  with torch.no_grad():
94
- while (unmasked == mask_token).any():
95
- # Estimate diffusion time t
96
- if pad_token is not None:
97
- valid_mask = unmasked != pad_token
98
- frac_masked = ((unmasked == mask_token).sum().float() / valid_mask.sum())
99
- else:
100
- frac_masked = ((unmasked == mask_token).sum().float() / unmasked.size(1))
101
- t_val = torch.tensor([frac_masked], device=device)
102
-
103
- # Forward pass
104
- logits = model.model(unmasked, t=t_val)
105
- probs = F.softmax(logits, dim=-1)
106
 
107
- mask_positions = (unmasked == mask_token)
108
- masked_probs = probs[mask_positions]
 
 
 
 
109
 
110
- if masked_probs.size(0) == 0:
111
- break # safety check
 
 
 
 
 
 
 
 
 
112
 
113
- # Pick the mask with highest confidence
114
- masked_confidence = masked_probs.max(dim=-1).values
115
- best_idx = torch.argmax(masked_confidence)
116
  mask_indices = mask_positions.nonzero(as_tuple=False)
117
- pos = mask_indices[best_idx]
118
 
119
- # Unmask the selected token
120
- sampled_id = torch.multinomial(masked_probs[best_idx], num_samples=1).item()
121
- unmasked[0, pos[1]] = sampled_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
- # ---- decode ----
124
- decoded = [
125
- t for t in unmasked[0].tolist()
126
- if t not in (pad_token, voc.vocab.get("<s>"), voc.vocab.get("</s>"))
127
- ]
128
- if len(decoded) > 2:
129
- decoded = decoded[1:-1]
130
 
131
- return self.decode(decoded).replace(" ", "")
 
 
78
  return torch.multinomial(probs, 1)
79
 
80
 
81
+ def unmask_partial_smiles(self, input_ids, model, voc, steps=30, k=3):
82
+ model.eval()
 
 
 
 
 
 
 
 
 
 
83
  with torch.no_grad():
84
+ sequences = torch.tensor(input_ids, dtype=torch.long, device=self.device).unsqueeze(0)
85
+
86
+ mask_token = voc.vocab['[MASK]']
87
+ pad_token = voc.vocab.get('[PAD]', None)
88
+
89
+ total_tokens = sequences.size(1)
90
+ original_num_masked = (sequences == mask_token).sum().item()
91
+ print(f"Original number of masked tokens: {original_num_masked}")
 
 
 
 
92
 
93
+ if total_tokens == 0:
94
+ raise ValueError("Encoded SMILES has no tokens.")
95
+ if original_num_masked == 0:
96
+ print("No masked tokens found. Returning original SMILES.")
97
+ input_ids = input_ids[1:-1]
98
+ return self.decode(input_ids)
99
 
100
+ filled_tokens_confidence = {}
101
+
102
+ # --- ITERATION LOGIC: unmask one token at a time based on highest confidence ---
103
+ num_masks = (sequences == mask_token).sum().item()
104
+ for _ in range(num_masks):
105
+ # Estimate t per sequence
106
+ frac_masked = (sequences == mask_token).sum().item() / total_tokens
107
+ t = torch.tensor([frac_masked], device=self.device)
108
+
109
+ logits = model(sequences, t=t)
110
+ probs = F.softmax(logits, dim=-1)
111
 
112
+ mask_positions = (sequences == mask_token)
 
 
113
  mask_indices = mask_positions.nonzero(as_tuple=False)
 
114
 
115
+ if len(mask_indices) == 0:
116
+ print("All tokens filled.")
117
+ break
118
+
119
+ masked_probs = probs[mask_positions] # (#masked, vocab)
120
+ sampled_ids = torch.multinomial(masked_probs, num_samples=1).squeeze(-1)
121
+ masked_confidence = torch.max(masked_probs, dim=-1).values
122
+
123
+ best_idx = torch.argmax(masked_confidence).item()
124
+ chosen_pos = mask_indices[best_idx] # [batch=0, position]
125
+ chosen_token = sampled_ids[best_idx].item()
126
+ chosen_conf = masked_confidence[best_idx].item()
127
+
128
+ sequences[0, chosen_pos[1]] = chosen_token
129
+ filled_tokens_confidence[chosen_pos[1].item()] = chosen_conf
130
+
131
+ print(f"Filled index {chosen_pos[1].item()} with token {chosen_token} (conf={chosen_conf:.4f})")
132
+
133
+ # Print confidence for all filled tokens
134
+ for idx, confidence in sorted(filled_tokens_confidence.items(), key=lambda x: x[0]):
135
+ print(f"Final confidence for token at index {idx}: {confidence:.3f}")
136
+
137
+ # Decode, removing <s> and </s>
138
+ decoded_tokens = [t for t in sequences[0].tolist() if t not in (voc.vocab.get('<s>'), voc.vocab.get('</s>'))]
139
 
140
+ if len(decoded_tokens) > 2:
141
+ decoded_tokens = decoded_tokens[1:-1]
 
 
 
 
 
142
 
143
+ decoded = self.decode(decoded_tokens).replace(" ", "")
144
+ return decoded