Skill Tracer
Skills › Scientific Agent Skills › torchdrug › retrosynthesis.md

retrosynthesis.md

265 lines · skills/torchdrug/references/retrosynthesis.md at 5f2bc03

Open on GitHub
1# Retrosynthesis
2
3The official
4[TorchDrug 0.2.1 retrosynthesis tutorial](https://torchdrug.ai/docs/tutorials/retrosynthesis.html)
5implements the G2Gs workflow:
6
71. identify reaction centers,
82. split products into synthons,
93. complete synthons into reactants,
104. combine both trained tasks for end-to-end prediction.
12This is a single-step reactant prediction pipeline. Multi-step route search,
13commercial availability, conditions, yields, and cost optimization are not
14provided by `tasks.Retrosynthesis`.
15The long training/beam-search examples are source-verified illustrations, not
16completed benchmark experiments from this review.

Retrosynthesis

The official TorchDrug 0.2.1 retrosynthesis tutorial implements the G2Gs workflow:

  1. identify reaction centers,
  2. split products into synthons,
  3. complete synthons into reactants,
  4. combine both trained tasks for end-to-end prediction.

This is a single-step reactant prediction pipeline. Multi-step route search, commercial availability, conditions, yields, and cost optimization are not provided by tasks.Retrosynthesis. The long training/beam-search examples are source-verified illustrations, not completed benchmark experiments from this review.

Raw lines 1 to 17
18## Prepare synchronized datasets
20```python
21import torch
22from torchdrug import datasets
24reaction_dataset = datasets.USPTO50k(
25 "~/molecule-datasets/",
26 atom_feature="center_identification",
27 kekulize=True,
29synthon_dataset = datasets.USPTO50k(
30 "~/molecule-datasets/",
31 as_synthon=True,
32 atom_feature="synthon_completion",
33 kekulize=True,
36torch.manual_seed(1)
37reaction_train, reaction_valid, reaction_test = reaction_dataset.split()
38torch.manual_seed(1)
39synthon_train, synthon_valid, synthon_test = synthon_dataset.split()
40```
42The repeated seed follows upstream's split protocol. Verify source `"sample id"`
43sets as shown in [datasets](datasets.md#splitting-correctly), because filtering
44or different graph-conversion outcomes can break alignment. Row counts across
45the two views need not match.
47- Reaction mode stores `(reactants, product)` pairs.
48- Synthon mode stores `(reactant, synthon)` pairs.

Prepare synchronized datasets

import torch
from torchdrug import datasets

reaction_dataset = datasets.USPTO50k(
    "~/molecule-datasets/",
    atom_feature="center_identification",
    kekulize=True,
)
synthon_dataset = datasets.USPTO50k(
    "~/molecule-datasets/",
    as_synthon=True,
    atom_feature="synthon_completion",
    kekulize=True,
)

torch.manual_seed(1)
reaction_train, reaction_valid, reaction_test = reaction_dataset.split()
torch.manual_seed(1)
synthon_train, synthon_valid, synthon_test = synthon_dataset.split()

The repeated seed follows upstream's split protocol. Verify source "sample id" sets as shown in datasets, because filtering or different graph-conversion outcomes can break alignment. Row counts across the two views need not match.

  • Reaction mode stores (reactants, product) pairs.
  • Synthon mode stores (reactant, synthon) pairs.
Raw lines 18 to 49
50## Center identification
52The official tutorial uses RGCN and three feature groups:
54```python
55from torchdrug import core, models, tasks
57reaction_model = models.RGCN(
58 input_dim=reaction_dataset.node_feature_dim,
59 hidden_dims=[256, 256, 256, 256, 256, 256],
60 num_relation=reaction_dataset.num_bond_type,
61 concat_hidden=True,
63reaction_task = tasks.CenterIdentification(
64 reaction_model,
65 feature=("graph", "atom", "bond"),
68reaction_optimizer = torch.optim.Adam(
69 reaction_task.parameters(),
70 lr=1e-3,
72reaction_solver = core.Engine(
73 reaction_task,
74 reaction_train,
75 reaction_valid,
76 reaction_test,
77 reaction_optimizer,
78 batch_size=128,
80reaction_solver.train(num_epoch=50)
81reaction_solver.evaluate("valid")
82reaction_solver.save("g2gs-reaction.pth")
83```
85`CenterIdentification` predicts reaction centers. Its
86`predict_synthon(batch, k=...)` method returns **one dictionary**, despite the
87release docstring's `list of dict` annotation. Its keys are `synthon`,
88`num_synthon`, `reaction_center`, `log_likelihood`, and `reaction`; packed graph
89attributes carry product/split IDs.

Center identification

The official tutorial uses RGCN and three feature groups:

from torchdrug import core, models, tasks

reaction_model = models.RGCN(
    input_dim=reaction_dataset.node_feature_dim,
    hidden_dims=[256, 256, 256, 256, 256, 256],
    num_relation=reaction_dataset.num_bond_type,
    concat_hidden=True,
)
reaction_task = tasks.CenterIdentification(
    reaction_model,
    feature=("graph", "atom", "bond"),
)

reaction_optimizer = torch.optim.Adam(
    reaction_task.parameters(),
    lr=1e-3,
)
reaction_solver = core.Engine(
    reaction_task,
    reaction_train,
    reaction_valid,
    reaction_test,
    reaction_optimizer,
    batch_size=128,
)
reaction_solver.train(num_epoch=50)
reaction_solver.evaluate("valid")
reaction_solver.save("g2gs-reaction.pth")

CenterIdentification predicts reaction centers. Its predict_synthon(batch, k=...) method returns one dictionary, despite the release docstring's list of dict annotation. Its keys are synthon, num_synthon, reaction_center, log_likelihood, and reaction; packed graph attributes carry product/split IDs.

Raw lines 50 to 90
91## Synthon completion
93The official tutorial again uses RGCN:
95```python
96synthon_model = models.RGCN(
97 input_dim=synthon_dataset.node_feature_dim,
98 hidden_dims=[256, 256, 256, 256, 256, 256],
99 num_relation=synthon_dataset.num_bond_type,
100 concat_hidden=True,
102synthon_task = tasks.SynthonCompletion(
103 synthon_model,
104 feature=("graph",),
107synthon_optimizer = torch.optim.Adam(
108 synthon_task.parameters(),
109 lr=1e-3,
111synthon_solver = core.Engine(
112 synthon_task,
113 synthon_train,
114 synthon_valid,
115 synthon_test,
116 synthon_optimizer,
117 batch_size=128,
119synthon_solver.train(num_epoch=10)
120synthon_solver.evaluate("valid")
121synthon_solver.save("g2gs-synthon.pth")
122```
124Do not substitute a GIN constructor copied from another implementation unless
125you intentionally redesign and validate the model.

Synthon completion

The official tutorial again uses RGCN:

synthon_model = models.RGCN(
    input_dim=synthon_dataset.node_feature_dim,
    hidden_dims=[256, 256, 256, 256, 256, 256],
    num_relation=synthon_dataset.num_bond_type,
    concat_hidden=True,
)
synthon_task = tasks.SynthonCompletion(
    synthon_model,
    feature=("graph",),
)

synthon_optimizer = torch.optim.Adam(
    synthon_task.parameters(),
    lr=1e-3,
)
synthon_solver = core.Engine(
    synthon_task,
    synthon_train,
    synthon_valid,
    synthon_test,
    synthon_optimizer,
    batch_size=128,
)
synthon_solver.train(num_epoch=10)
synthon_solver.evaluate("valid")
synthon_solver.save("g2gs-synthon.pth")

Do not substitute a GIN constructor copied from another implementation unless you intentionally redesign and validate the model.

Raw lines 91 to 126
127## End-to-end task
129Combine the **tasks**, not the raw models:
131```python
132task = tasks.Retrosynthesis(
133 reaction_task,
134 synthon_task,
135 center_topk=2,
136 num_synthon_beam=5,
137 max_prediction=10,
139```
141If neither subtask has been attached to an `Engine`, preprocess them manually
142before composition:
144```python
145reaction_task.preprocess(reaction_train, None, None)
146synthon_task.preprocess(synthon_train, None, None)
147```
149The `Retrosynthesis` constructor accepts:
151- `center_identification`
152- `synthon_completion`
153- `center_topk`
154- `num_synthon_beam`
155- `max_prediction`
156- top-k metrics
158It does not accept `model=`, `synthon_model=`, or a raw GNN pair.

End-to-end task

Combine the tasks, not the raw models:

task = tasks.Retrosynthesis(
    reaction_task,
    synthon_task,
    center_topk=2,
    num_synthon_beam=5,
    max_prediction=10,
)

If neither subtask has been attached to an Engine, preprocess them manually before composition:

reaction_task.preprocess(reaction_train, None, None)
synthon_task.preprocess(synthon_train, None, None)

The Retrosynthesis constructor accepts:

  • center_identification
  • synthon_completion
  • center_topk
  • num_synthon_beam
  • max_prediction
  • top-k metrics

It does not accept model=, synthon_model=, or a raw GNN pair.

Raw lines 127 to 159
160## Checkpoint loading
162The official workflow saves each subtask and loads checkpoints without optimizer
163state when composing the pipeline:
165```python
166optimizer = torch.optim.Adam(task.parameters(), lr=1e-3)
167solver = core.Engine(
168 task,
169 reaction_train,
170 reaction_valid,
171 reaction_test,
172 optimizer,
173 batch_size=32,
175solver.load("g2gs-reaction.pth", load_optimizer=False)
176solver.load("g2gs-synthon.pth", load_optimizer=False)
177solver.evaluate("valid")
178```
180Keep model architectures, feature sets, and dataset metadata identical to the
181training run. The composite's `load_state_dict` matches the exact key set of one
182subtask and requires `strict=True`; it cannot restore its own combined state dict
183through this override. Keep the two individual solver checkpoints. Load only
184trusted files because this PyTorch 2.0 path uses pickle.

Checkpoint loading

The official workflow saves each subtask and loads checkpoints without optimizer state when composing the pipeline:

optimizer = torch.optim.Adam(task.parameters(), lr=1e-3)
solver = core.Engine(
    task,
    reaction_train,
    reaction_valid,
    reaction_test,
    optimizer,
    batch_size=32,
)
solver.load("g2gs-reaction.pth", load_optimizer=False)
solver.load("g2gs-synthon.pth", load_optimizer=False)
solver.evaluate("valid")

Keep model architectures, feature sets, and dataset metadata identical to the training run. The composite's load_state_dict matches the exact key set of one subtask and requires strict=True; it cannot restore its own combined state dict through this override. Keep the two individual solver checkpoints. Load only trusted files because this PyTorch 2.0 path uses pickle.

Raw lines 160 to 185
186## Prediction output
188The end-to-end task returns packed reactant predictions and a count per input:
190```python
191from torchdrug import data
193batch = data.graph_collate([reaction_valid[i] for i in range(min(4, len(reaction_valid)))])
194task.eval()
195with torch.no_grad():
196 predictions, num_prediction = task.predict(batch)
198top1_index = num_prediction.cumsum(0) - num_prediction
199for index, count in zip(top1_index.tolist(), num_prediction.tolist()):
200 if count == 0:
201 print("No reactant prediction")
202 continue
203 reactants = predictions[index].connected_components()[0]
204 print(reactants.to_smiles())
205```
207Call `utils.cuda` only when the task/models are on CUDA. Keep the batch on CPU
208for CPU execution.
209Validate that `len(num_prediction)` equals the number of input products and
210that `num_prediction.sum() == len(predictions)` before associating outputs with
211inputs. Empty beam-search results may also raise inside the released task;
212record these failures rather than reporting a candidate for the next product.

Prediction output

The end-to-end task returns packed reactant predictions and a count per input:

from torchdrug import data

batch = data.graph_collate([reaction_valid[i] for i in range(min(4, len(reaction_valid)))])
task.eval()
with torch.no_grad():
    predictions, num_prediction = task.predict(batch)

top1_index = num_prediction.cumsum(0) - num_prediction
for index, count in zip(top1_index.tolist(), num_prediction.tolist()):
    if count == 0:
        print("No reactant prediction")
        continue
    reactants = predictions[index].connected_components()[0]
    print(reactants.to_smiles())

Call utils.cuda only when the task/models are on CUDA. Keep the batch on CPU for CPU execution. Validate that len(num_prediction) equals the number of input products and that num_prediction.sum() == len(predictions) before associating outputs with inputs. Empty beam-search results may also raise inside the released task; record these failures rather than reporting a candidate for the next product.

Raw lines 186 to 213
214## Evaluation
216The end-to-end task supports top-k exact-match metrics such as top-1, top-3,
217top-5, and top-10. Also inspect:
219- chemical validity,
220- duplicate predictions,
221- performance by reaction class,
222- atom-map consistency,
223- stereochemistry retention,
224- uncertainty or score gaps.
226Top-k exact match against USPTO50k is not proof that a reaction is practical.

Evaluation

The end-to-end task supports top-k exact-match metrics such as top-1, top-3, top-5, and top-10. Also inspect:

  • chemical validity,
  • duplicate predictions,
  • performance by reaction class,
  • atom-map consistency,
  • stereochemistry retention,
  • uncertainty or score gaps.

Top-k exact match against USPTO50k is not proof that a reaction is practical.

Raw lines 214 to 227
228## Scope and safety
230TorchDrug's tutorial predicts reactant connectivity. It does not directly
231predict:
233- reagents, catalysts, solvent, temperature, or pressure,
234- yield or selectivity,
235- commercial availability,
236- multi-step search trees,
237- process safety or scale-up feasibility.
239Treat outputs as model proposals requiring forward validation, literature
240precedent, and expert chemistry review.

Scope and safety

TorchDrug's tutorial predicts reactant connectivity. It does not directly predict:

  • reagents, catalysts, solvent, temperature, or pressure,
  • yield or selectivity,
  • commercial availability,
  • multi-step search trees,
  • process safety or scale-up feasibility.

Treat outputs as model proposals requiring forward validation, literature precedent, and expert chemistry review.

Raw lines 228 to 241
242## Common failures

Common failures

Raw lines 242 to 243
244### Reaction and synthon samples do not align
246Reset the same seed immediately before each `split()`.

Reaction and synthon samples do not align

Reset the same seed immediately before each split().

Raw lines 244 to 247
248### Feature dimension mismatch
250Use the dedicated `center_identification` and `synthon_completion` atom features
251and derive model dimensions from each corresponding dataset.

Feature dimension mismatch

Use the dedicated center_identification and synthon_completion atom features and derive model dimensions from each corresponding dataset.

Raw lines 248 to 252
253### End-to-end constructor error
255Pass `reaction_task` and `synthon_task`, not their models.

End-to-end constructor error

Pass reaction_task and synthon_task, not their models.

Raw lines 253 to 256
257### Uninitialized metadata
259Construct each subtask's engine first or call `preprocess()` manually.

Uninitialized metadata

Construct each subtask's engine first or call preprocess() manually.

Raw lines 257 to 260
261## Source links
263- [Retrosynthesis tutorial](https://torchdrug.ai/docs/tutorials/retrosynthesis.html)
264- [Retrosynthesis tasks](https://torchdrug.ai/docs/api/tasks.html#retrosynthesis-tasks)
265- [USPTO50k dataset](https://torchdrug.ai/docs/api/datasets.html#uspto50k)