Instructions to use Synthyra/Boltz2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Synthyra/Boltz2 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="Synthyra/Boltz2", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Synthyra/Boltz2", trust_remote_code=True, dtype="auto") - Notebooks
- Google Colab
- Kaggle
| from pathlib import Path | |
| from typing import List, Optional | |
| import numpy as np | |
| import torch | |
| from .minimal_structures import ProteinStructureTemplate | |
| def _confidence_per_atom( | |
| plddt: Optional[torch.Tensor], | |
| atom_to_residue: List[int], | |
| num_atoms: int, | |
| sample_index: int, | |
| ) -> np.ndarray: | |
| if plddt is None: | |
| return np.ones((num_atoms,), dtype=np.float32) * 100.0 | |
| values = plddt.detach().cpu() | |
| if values.ndim == 1: | |
| values = values.unsqueeze(0) | |
| assert values.ndim == 2, "Expected pLDDT with shape [samples, tokens/atoms]." | |
| assert sample_index < values.shape[0], "sample_index out of range for pLDDT." | |
| selected = values[sample_index] | |
| if selected.shape[0] == num_atoms: | |
| return (selected.numpy() * 100.0).astype(np.float32) | |
| num_residues = max(atom_to_residue) + 1 | |
| if selected.shape[0] == num_residues: | |
| expanded = np.zeros((num_atoms,), dtype=np.float32) | |
| selected_np = selected.numpy() | |
| for atom_idx, residue_idx in enumerate(atom_to_residue): | |
| expanded[atom_idx] = selected_np[residue_idx] * 100.0 | |
| return expanded | |
| return np.ones((num_atoms,), dtype=np.float32) * 100.0 | |
| def write_cif( | |
| structure_template: ProteinStructureTemplate, | |
| atom_coords: torch.Tensor, | |
| atom_mask: torch.Tensor, | |
| output_path: str, | |
| plddt: Optional[torch.Tensor] = None, | |
| sample_index: int = 0, | |
| ) -> str: | |
| coords = atom_coords.detach().cpu() | |
| if coords.ndim == 2: | |
| coords = coords.unsqueeze(0) | |
| assert coords.ndim == 3, "Expected coordinates with shape [samples, atoms, 3]." | |
| assert sample_index < coords.shape[0], "sample_index out of range." | |
| selected_coords_tensor = coords[sample_index] | |
| all_non_finite = torch.logical_not(torch.isfinite(selected_coords_tensor)) | |
| assert not torch.any(all_non_finite), ( | |
| "CIF export received non-finite coordinates. " | |
| f"Non-finite count: {int(all_non_finite.sum().item())}" | |
| ) | |
| selected_coords = selected_coords_tensor.numpy() | |
| mask = atom_mask.detach().cpu() | |
| if mask.ndim == 2: | |
| mask = mask[0] | |
| assert mask.ndim == 1, "Expected atom mask with shape [atoms]." | |
| assert mask.shape[0] == selected_coords.shape[0], "Atom mask/coord size mismatch." | |
| assert torch.any(mask > 0), "Atom mask has no valid atoms for CIF export." | |
| valid_non_finite = torch.logical_not(torch.isfinite(selected_coords_tensor[mask > 0])) | |
| assert not torch.any(valid_non_finite), ( | |
| "CIF export has non-finite coordinates in unmasked atoms. " | |
| f"Non-finite count: {int(valid_non_finite.sum().item())}" | |
| ) | |
| b_iso = _confidence_per_atom( | |
| plddt=plddt, | |
| atom_to_residue=structure_template.atom_residue_index, | |
| num_atoms=structure_template.num_atoms, | |
| sample_index=sample_index, | |
| ) | |
| assert b_iso.shape[0] == structure_template.num_atoms | |
| lines = [ | |
| "data_boltz2_prediction", | |
| "#", | |
| "loop_", | |
| "_atom_site.group_PDB", | |
| "_atom_site.id", | |
| "_atom_site.type_symbol", | |
| "_atom_site.label_atom_id", | |
| "_atom_site.label_comp_id", | |
| "_atom_site.label_asym_id", | |
| "_atom_site.label_seq_id", | |
| "_atom_site.Cartn_x", | |
| "_atom_site.Cartn_y", | |
| "_atom_site.Cartn_z", | |
| "_atom_site.occupancy", | |
| "_atom_site.B_iso_or_equiv", | |
| "_atom_site.pdbx_PDB_model_num", | |
| ] | |
| atom_id = 1 | |
| for idx in range(structure_template.num_atoms): | |
| if mask[idx] <= 0: | |
| continue | |
| residue_idx = structure_template.atom_residue_index[idx] | |
| residue_name = structure_template.residue_names[residue_idx] | |
| atom_name = structure_template.atom_names[idx] | |
| element = structure_template.atom_elements[idx] | |
| chain_id = structure_template.atom_chain_id[idx] | |
| x_val, y_val, z_val = selected_coords[idx].tolist() | |
| b_factor = float(b_iso[idx]) | |
| line = ( | |
| f"ATOM {atom_id} {element} {atom_name} {residue_name} {chain_id} " | |
| f"{residue_idx + 1} {x_val:.3f} {y_val:.3f} {z_val:.3f} 1.00 {b_factor:.2f} 1" | |
| ) | |
| lines.append(line) | |
| atom_id += 1 | |
| lines.append("#") | |
| text = "\n".join(lines) + "\n" | |
| out_path = Path(output_path) | |
| out_path.parent.mkdir(parents=True, exist_ok=True) | |
| out_path.write_text(text, encoding="utf-8") | |
| return str(out_path) | |