Download scripts/inverse_folding/sample_sequences.py from OneScience-Group/ESM: direct link, hf CLI and curl.
- Browser
- Download file 4.83 kB
-
https://huggingface.co/OneScience-Group/ESM/resolve/main/scripts/inverse_folding/sample_sequences.py
- Command line
-
hf download hf://OneScience-Group/ESM/scripts/inverse_folding/sample_sequences.py
-
curl -L -o sample_sequences.py https://huggingface.co/OneScience-Group/ESM/resolve/main/scripts/inverse_folding/sample_sequences.py
4.83 kB
| from pathlib import Path | |
| import sys | |
| _PROJECT_FILE = Path(__file__).resolve() | |
| for _PROJECT_ROOT in _PROJECT_FILE.parents: | |
| if (_PROJECT_ROOT / "model").is_dir(): | |
| if str(_PROJECT_ROOT) not in sys.path: | |
| sys.path.insert(0, str(_PROJECT_ROOT)) | |
| break | |
| # Copyright (c) Meta Platforms, Inc. and affiliates. | |
| # | |
| # This source code is licensed under the MIT license found in the | |
| # LICENSE file in the root directory of this source tree. | |
| # | |
| # Sample sequences based on a given structure (multinomial sampling, no beam search). | |
| # | |
| # usage: sample_sequences.py [-h] [--chain CHAIN] [--temperature TEMPERATURE] | |
| # [--outpath OUTPATH] [--num-samples NUM_SAMPLES] pdbfile | |
| import argparse | |
| import numpy as np | |
| from pathlib import Path | |
| import torch | |
| import model.esm as esm | |
| import model.esm.inverse_folding | |
| def sample_seq_singlechain(model, alphabet, args): | |
| if torch.cuda.is_available() and not args.nogpu: | |
| model = model.cuda() | |
| print("Transferred model to GPU") | |
| device = next(model.parameters()).device | |
| coords, native_seq = esm.inverse_folding.util.load_coords(args.pdbfile, args.chain) | |
| print('Native sequence loaded from structure file:') | |
| print(native_seq) | |
| print(f'Saving sampled sequences to {args.outpath}.') | |
| Path(args.outpath).parent.mkdir(parents=True, exist_ok=True) | |
| with open(args.outpath, 'w') as f: | |
| for i in range(args.num_samples): | |
| print(f'\nSampling.. ({i+1} of {args.num_samples})') | |
| sampled_seq = model.sample(coords, temperature=args.temperature, device=device) | |
| print('Sampled sequence:') | |
| print(sampled_seq) | |
| f.write(f'>sampled_seq_{i+1}\n') | |
| f.write(sampled_seq + '\n') | |
| recovery = np.mean([(a==b) for a, b in zip(native_seq, sampled_seq)]) | |
| print('Sequence recovery:', recovery) | |
| def sample_seq_multichain(model, alphabet, args): | |
| if torch.cuda.is_available() and not args.nogpu: | |
| model = model.cuda() | |
| print("Transferred model to GPU") | |
| structure = esm.inverse_folding.util.load_structure(args.pdbfile) | |
| coords, native_seqs = esm.inverse_folding.multichain_util.extract_coords_from_complex(structure) | |
| target_chain_id = args.chain | |
| native_seq = native_seqs[target_chain_id] | |
| print('Native sequence loaded from structure file:') | |
| print(native_seq) | |
| print('\n') | |
| print(f'Saving sampled sequences to {args.outpath}.') | |
| Path(args.outpath).parent.mkdir(parents=True, exist_ok=True) | |
| with open(args.outpath, 'w') as f: | |
| for i in range(args.num_samples): | |
| print(f'\nSampling.. ({i+1} of {args.num_samples})') | |
| sampled_seq = esm.inverse_folding.multichain_util.sample_sequence_in_complex( | |
| model, coords, target_chain_id, temperature=args.temperature) | |
| print('Sampled sequence:') | |
| print(sampled_seq) | |
| f.write(f'>sampled_seq_{i+1}\n') | |
| f.write(sampled_seq + '\n') | |
| recovery = np.mean([(a==b) for a, b in zip(native_seq, sampled_seq)]) | |
| print('Sequence recovery:', recovery) | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description='Sample sequences based on a given structure.' | |
| ) | |
| parser.add_argument( | |
| 'pdbfile', type=str, | |
| help='input filepath, either .pdb or .cif', | |
| ) | |
| parser.add_argument( | |
| '--chain', type=str, | |
| help='chain id for the chain of interest', default=None, | |
| ) | |
| parser.add_argument( | |
| '--temperature', type=float, | |
| help='temperature for sampling, higher for more diversity', | |
| default=1., | |
| ) | |
| parser.add_argument( | |
| '--outpath', type=str, | |
| help='output filepath for saving sampled sequences', | |
| default='output/sampled_seqs.fasta', | |
| ) | |
| parser.add_argument( | |
| '--num-samples', type=int, | |
| help='number of sequences to sample', | |
| default=1, | |
| ) | |
| parser.set_defaults(multichain_backbone=False) | |
| parser.add_argument( | |
| '--multichain-backbone', action='store_true', | |
| help='use the backbones of all chains in the input for conditioning' | |
| ) | |
| parser.add_argument( | |
| '--singlechain-backbone', dest='multichain_backbone', | |
| action='store_false', | |
| help='use the backbone of only target chain in the input for conditioning' | |
| ) | |
| parser.add_argument("--nogpu", action="store_true", help="Do not use GPU even if available") | |
| args = parser.parse_args() | |
| model, alphabet = esm.pretrained.esm_if1_gvp4_t16_142M_UR50() | |
| model = model.eval() | |
| if args.multichain_backbone: | |
| sample_seq_multichain(model, alphabet, args) | |
| else: | |
| sample_seq_singlechain(model, alphabet, args) | |
| if __name__ == '__main__': | |
| main() | |