pepe-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pepe_cli-1.0.0/LICENSE +21 -0
- pepe_cli-1.0.0/MANIFEST.in +10 -0
- pepe_cli-1.0.0/PKG-INFO +137 -0
- pepe_cli-1.0.0/README.md +97 -0
- pepe_cli-1.0.0/examples/custom_model/create_example_custom_model.py +374 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/config.json +8 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/pytorch_model.pt +0 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/special_tokens_map.json +6 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/tokenizer_config.json +10 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/vocab.json +27 -0
- pepe_cli-1.0.0/examples/custom_model/example_protein_model/vocab.txt +25 -0
- pepe_cli-1.0.0/examples/custom_model/example_sequences.fasta +10 -0
- pepe_cli-1.0.0/examples/custom_model/example_substring.csv +6 -0
- pepe_cli-1.0.0/examples/embedding_options.md +41 -0
- pepe_cli-1.0.0/examples/model_selection.md +41 -0
- pepe_cli-1.0.0/pyproject.toml +57 -0
- pepe_cli-1.0.0/requirements.txt +9 -0
- pepe_cli-1.0.0/setup.cfg +4 -0
- pepe_cli-1.0.0/setup.py +66 -0
- pepe_cli-1.0.0/src/pepe/__init__.py +41 -0
- pepe_cli-1.0.0/src/pepe/__main__.py +23 -0
- pepe_cli-1.0.0/src/pepe/embedders/__init__.py +0 -0
- pepe_cli-1.0.0/src/pepe/embedders/base_embedder.py +797 -0
- pepe_cli-1.0.0/src/pepe/embedders/custom_embedder.py +647 -0
- pepe_cli-1.0.0/src/pepe/embedders/esm_embedder.py +164 -0
- pepe_cli-1.0.0/src/pepe/embedders/huggingface_embedder.py +200 -0
- pepe_cli-1.0.0/src/pepe/model_selecter.py +99 -0
- pepe_cli-1.0.0/src/pepe/parse_arguments.py +167 -0
- pepe_cli-1.0.0/src/pepe/utils.py +905 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/PKG-INFO +137 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/SOURCES.txt +35 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/dependency_links.txt +1 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/entry_points.txt +3 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/requires.txt +8 -0
- pepe_cli-1.0.0/src/pepe_cli.egg-info/top_level.txt +2 -0
- pepe_cli-1.0.0/src/tests/__init__.py +0 -0
- pepe_cli-1.0.0/src/tests/test_run.py +43 -0
pepe_cli-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Greiff Lab – Computational Systems Immunology
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include requirements.txt
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
recursive-include src *.py
|
|
6
|
+
recursive-include examples *
|
|
7
|
+
recursive-exclude * __pycache__
|
|
8
|
+
recursive-exclude * *.py[co]
|
|
9
|
+
recursive-exclude * *.so
|
|
10
|
+
recursive-exclude * .DS_Store
|
pepe_cli-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pepe-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Pipeline for Easy Protein Embedding - Extract embeddings and attention matrices from protein sequences
|
|
5
|
+
Home-page: https://github.com/csi-greifflab/pepe-cli
|
|
6
|
+
Author: Jahn Zhong
|
|
7
|
+
Author-email: Jahn Zhong <jahn.zhong@medisin.uio.no>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/csi-greifflab/pepe-cli
|
|
10
|
+
Project-URL: Bug Reports, https://github.com/csi-greifflab/pepe-cli/issues
|
|
11
|
+
Project-URL: Source, https://github.com/csi-greifflab/pepe-cli
|
|
12
|
+
Project-URL: Documentation, https://github.com/csi-greifflab/pepe-cli#readme
|
|
13
|
+
Keywords: protein,embeddings,bioinformatics,machine-learning,nlp,transformers
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: torch>=1.9.0
|
|
29
|
+
Requires-Dist: transformers>=4.20.0
|
|
30
|
+
Requires-Dist: fair-esm
|
|
31
|
+
Requires-Dist: sentencepiece
|
|
32
|
+
Requires-Dist: numpy
|
|
33
|
+
Requires-Dist: protobuf
|
|
34
|
+
Requires-Dist: rjieba
|
|
35
|
+
Requires-Dist: alive_progress
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: home-page
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
|
|
41
|
+
# PEPE
|
|
42
|
+
|
|
43
|
+
PEPE (Pipeline for Easy Protein Embedding) is a tool for extracting embeddings and attention matrices from protein sequences using pre-trained models. This tool supports various configurations for extracting embeddings and attention matrices, including options for handling CDR3 sequences. Currently implemented models are ESM2 from the 2023 paper ["Evolutionary-scale prediction of atomic-level protein structure with a language model"](https://science.org/doi/10.1126/science.ade2574) and AntiBERTa2-CSSP from the 2023 conference paper ["Enhancing Antibody Language Models with Structural Information"](https://www.mlsb.io/papers_2023/Enhancing_Antibody_Language_Models_with_Structural_Information.pdf). PEPE also supports custom PLMs from local files or from Huggingface Hub addresses.
|
|
44
|
+
|
|
45
|
+
## Quick start
|
|
46
|
+
|
|
47
|
+
1. Install PEPE \
|
|
48
|
+
From PyPI:
|
|
49
|
+
```sh
|
|
50
|
+
pip install pepe-cli
|
|
51
|
+
```
|
|
52
|
+
Or install from the GitHub repository:
|
|
53
|
+
```sh
|
|
54
|
+
git clone https://github.com/csi-greifflab/pepe-cli
|
|
55
|
+
cd pepe-cli
|
|
56
|
+
pip install .
|
|
57
|
+
```
|
|
58
|
+
2. Run the embedding script:\
|
|
59
|
+
Extract mean pooled embeddings from protein amino acid sequences in FASTA file:
|
|
60
|
+
```sh
|
|
61
|
+
pepe --experiment_name <optional_string> --fasta_path <file_path> --output_path <directory> --model_name <model_name>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## List of supported models:
|
|
65
|
+
- ESM-family models
|
|
66
|
+
- ESM1:
|
|
67
|
+
- esm1_t34_670M_UR50S
|
|
68
|
+
- esm1_t34_670M_UR50D
|
|
69
|
+
- esm1_t34_670M_UR100
|
|
70
|
+
- esm1_t12_85M_UR50S
|
|
71
|
+
- esm1_t6_43M_UR50S
|
|
72
|
+
- esm1b_t33_650M_UR50S
|
|
73
|
+
- esm1v_t33_650M_UR90S_1
|
|
74
|
+
- esm1v_t33_650M_UR90S_2
|
|
75
|
+
- esm1v_t33_650M_UR90S_3
|
|
76
|
+
- esm1v_t33_650M_UR90S_4
|
|
77
|
+
- esm1v_t33_650M_UR90S_5
|
|
78
|
+
- ESM2:
|
|
79
|
+
- esm2_t6_8M_UR50D
|
|
80
|
+
- esm2_t12_35M_UR50D
|
|
81
|
+
- esm2_t30_150M_UR50D
|
|
82
|
+
- esm2_t33_650M_UR50D
|
|
83
|
+
- esm2_t36_3B_UR50D
|
|
84
|
+
- esm2_t48_15B_UR50D
|
|
85
|
+
- Huggingface Transformer models
|
|
86
|
+
- T5 transformer models
|
|
87
|
+
- Rostlab/prot_t5_xl_half_uniref50-enc
|
|
88
|
+
- Rostlab/ProstT5
|
|
89
|
+
- RoFormer models
|
|
90
|
+
- alchemab/antiberta2-cssp
|
|
91
|
+
- alchemab/antiberta2
|
|
92
|
+
- Custom Hugging Face models
|
|
93
|
+
- Any compatible model from Hugging Face Hub: `username/model-name`
|
|
94
|
+
- Private models with authentication
|
|
95
|
+
- Local Hugging Face models
|
|
96
|
+
- Custom Models
|
|
97
|
+
- Load your own PyTorch models with custom tokenizers
|
|
98
|
+
- Create example with: `python examples/custom_model/create_example_custom_model.py`
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Arguments
|
|
102
|
+
|
|
103
|
+
### Required Arguments
|
|
104
|
+
- **`--model_name`** (str): Name of model or link to model. Choose from [List of supported models](../README.md#list-of-supported-models) or use custom models:
|
|
105
|
+
- ESM models: `esm2_t33_650M_UR50D`
|
|
106
|
+
- Hugging Face models: `username/model-name`
|
|
107
|
+
- Custom PyTorch models: `/path/to/model.pt` or `/path/to/model_directory/`
|
|
108
|
+
- Local HF models: `/path/to/local_hf_directory/`
|
|
109
|
+
- **`--fasta_path`** (str): Path to the input FASTA file. If no experiment name is provided, the output files will be named after the input file.
|
|
110
|
+
- **`--output_path`** (str): Directory for output files. Will generate a subdirectory for outputs of each output type.
|
|
111
|
+
|
|
112
|
+
### Model Configuration
|
|
113
|
+
- **`--tokenizer_from`** (str, optional): Huggingface address of the tokenizer to use. If not provided, will attempt to search for tokenizer packaged with model. If using a custom model, provide the path to the tokenizer directory.
|
|
114
|
+
- **`--disable_special_tokens`** (bool, optional): When True, PEPE disables pre- and appending BOS/CLS and EOS/SEP tokens before embedding. Default is `False`.
|
|
115
|
+
- **`--device`** (str, optional): Device to run the model on. Choose from `cuda` or `cpu`. Default is `cuda`.
|
|
116
|
+
|
|
117
|
+
### Embedding Configuration
|
|
118
|
+
- **`--layers`** (str, optional): Representation layers to extract from the model. Default is the last layer. Example: `--layers -1 6`.
|
|
119
|
+
- **`--extract_embeddings`** (str, optional): Set the embedding return types. Choose one or more from: `per_token`, `mean_pooled`, `substring_pooled`, `attention_head`, `attention_layer`, `attention_model` and `logits` (experimental). Default is `mean_pooled`.
|
|
120
|
+
- **`--substring_path`** (str, optional): Path to a CSV file with columns "sequence_id" and "substring". Only required when selecting "substring_pooled" option.
|
|
121
|
+
- **`--context`** (int, optional): Only specify when including "substring_pooled" in `--extract_embeddings` option. Number of amino acids to include before and after the substring sequence. Default is `0`.
|
|
122
|
+
|
|
123
|
+
### Processing Configuration
|
|
124
|
+
- **`--batch_size`** (int, optional): Batch size for loading sequences. Default is `1024`. Decrease if encountering out-of-memory errors.
|
|
125
|
+
- **`--max_length`** (int, optional): Length to which sequences will be padded. Default is length of longest sequence in input file. If shorter than longest sequence, will forcefully default to length of longest sequence.
|
|
126
|
+
- **`--discard_padding`** (bool, optional): Discard padding tokens from per_token embeddings output. Default is `False`.
|
|
127
|
+
|
|
128
|
+
### Output Configuration
|
|
129
|
+
- **`--experiment_name`** (str, optional): Prefix for names of output files. If not provided, name of input file will be used for prefix.
|
|
130
|
+
- **`--streaming_output`** (bool, optional): PEPE preallocates the required disk space and writes each batch of outputs concurrently. Can pose issues with file systems that do not support memory mapping (such as some distributed file systems.)
|
|
131
|
+
When False, all outputs are stored in RAM and written to disk at once after computation has finished. Default is `True`.
|
|
132
|
+
- **`--precision`** (str, optional): Precision of the output data. Choose from `float16`, `16`, `half`, `float32`, `32`, `full`. Inference during embedding is not affected. Default is `float32`.
|
|
133
|
+
- **`--flatten`** (bool, optional): Flatten 2D output arrays (per_token embeddings or attention weights) to 1D arrays per input sequence. Default is `False`.
|
|
134
|
+
|
|
135
|
+
### Performance Configuration
|
|
136
|
+
- **`--num_workers`** (int, optional): Number of workers for asynchronous data writing. Only relevant when `--streaming_output` is enabled. Default is `8`.
|
|
137
|
+
- **`--flush_batches_after`** (int, optional): Size (in MB) of outputs to accumulate in RAM per worker before flushing to disk. Default is `128`.
|
pepe_cli-1.0.0/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# PEPE
|
|
2
|
+
|
|
3
|
+
PEPE (Pipeline for Easy Protein Embedding) is a tool for extracting embeddings and attention matrices from protein sequences using pre-trained models. This tool supports various configurations for extracting embeddings and attention matrices, including options for handling CDR3 sequences. Currently implemented models are ESM2 from the 2023 paper ["Evolutionary-scale prediction of atomic-level protein structure with a language model"](https://science.org/doi/10.1126/science.ade2574) and AntiBERTa2-CSSP from the 2023 conference paper ["Enhancing Antibody Language Models with Structural Information"](https://www.mlsb.io/papers_2023/Enhancing_Antibody_Language_Models_with_Structural_Information.pdf). PEPE also supports custom PLMs from local files or from Huggingface Hub addresses.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
1. Install PEPE \
|
|
8
|
+
From PyPI:
|
|
9
|
+
```sh
|
|
10
|
+
pip install pepe-cli
|
|
11
|
+
```
|
|
12
|
+
Or install from the GitHub repository:
|
|
13
|
+
```sh
|
|
14
|
+
git clone https://github.com/csi-greifflab/pepe-cli
|
|
15
|
+
cd pepe-cli
|
|
16
|
+
pip install .
|
|
17
|
+
```
|
|
18
|
+
2. Run the embedding script:\
|
|
19
|
+
Extract mean pooled embeddings from protein amino acid sequences in FASTA file:
|
|
20
|
+
```sh
|
|
21
|
+
pepe --experiment_name <optional_string> --fasta_path <file_path> --output_path <directory> --model_name <model_name>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## List of supported models:
|
|
25
|
+
- ESM-family models
|
|
26
|
+
- ESM1:
|
|
27
|
+
- esm1_t34_670M_UR50S
|
|
28
|
+
- esm1_t34_670M_UR50D
|
|
29
|
+
- esm1_t34_670M_UR100
|
|
30
|
+
- esm1_t12_85M_UR50S
|
|
31
|
+
- esm1_t6_43M_UR50S
|
|
32
|
+
- esm1b_t33_650M_UR50S
|
|
33
|
+
- esm1v_t33_650M_UR90S_1
|
|
34
|
+
- esm1v_t33_650M_UR90S_2
|
|
35
|
+
- esm1v_t33_650M_UR90S_3
|
|
36
|
+
- esm1v_t33_650M_UR90S_4
|
|
37
|
+
- esm1v_t33_650M_UR90S_5
|
|
38
|
+
- ESM2:
|
|
39
|
+
- esm2_t6_8M_UR50D
|
|
40
|
+
- esm2_t12_35M_UR50D
|
|
41
|
+
- esm2_t30_150M_UR50D
|
|
42
|
+
- esm2_t33_650M_UR50D
|
|
43
|
+
- esm2_t36_3B_UR50D
|
|
44
|
+
- esm2_t48_15B_UR50D
|
|
45
|
+
- Huggingface Transformer models
|
|
46
|
+
- T5 transformer models
|
|
47
|
+
- Rostlab/prot_t5_xl_half_uniref50-enc
|
|
48
|
+
- Rostlab/ProstT5
|
|
49
|
+
- RoFormer models
|
|
50
|
+
- alchemab/antiberta2-cssp
|
|
51
|
+
- alchemab/antiberta2
|
|
52
|
+
- Custom Hugging Face models
|
|
53
|
+
- Any compatible model from Hugging Face Hub: `username/model-name`
|
|
54
|
+
- Private models with authentication
|
|
55
|
+
- Local Hugging Face models
|
|
56
|
+
- Custom Models
|
|
57
|
+
- Load your own PyTorch models with custom tokenizers
|
|
58
|
+
- Create example with: `python examples/custom_model/create_example_custom_model.py`
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Arguments
|
|
62
|
+
|
|
63
|
+
### Required Arguments
|
|
64
|
+
- **`--model_name`** (str): Name of model or link to model. Choose from [List of supported models](../README.md#list-of-supported-models) or use custom models:
|
|
65
|
+
- ESM models: `esm2_t33_650M_UR50D`
|
|
66
|
+
- Hugging Face models: `username/model-name`
|
|
67
|
+
- Custom PyTorch models: `/path/to/model.pt` or `/path/to/model_directory/`
|
|
68
|
+
- Local HF models: `/path/to/local_hf_directory/`
|
|
69
|
+
- **`--fasta_path`** (str): Path to the input FASTA file. If no experiment name is provided, the output files will be named after the input file.
|
|
70
|
+
- **`--output_path`** (str): Directory for output files. Will generate a subdirectory for outputs of each output type.
|
|
71
|
+
|
|
72
|
+
### Model Configuration
|
|
73
|
+
- **`--tokenizer_from`** (str, optional): Huggingface address of the tokenizer to use. If not provided, will attempt to search for tokenizer packaged with model. If using a custom model, provide the path to the tokenizer directory.
|
|
74
|
+
- **`--disable_special_tokens`** (bool, optional): When True, PEPE disables pre- and appending BOS/CLS and EOS/SEP tokens before embedding. Default is `False`.
|
|
75
|
+
- **`--device`** (str, optional): Device to run the model on. Choose from `cuda` or `cpu`. Default is `cuda`.
|
|
76
|
+
|
|
77
|
+
### Embedding Configuration
|
|
78
|
+
- **`--layers`** (str, optional): Representation layers to extract from the model. Default is the last layer. Example: `--layers -1 6`.
|
|
79
|
+
- **`--extract_embeddings`** (str, optional): Set the embedding return types. Choose one or more from: `per_token`, `mean_pooled`, `substring_pooled`, `attention_head`, `attention_layer`, `attention_model` and `logits` (experimental). Default is `mean_pooled`.
|
|
80
|
+
- **`--substring_path`** (str, optional): Path to a CSV file with columns "sequence_id" and "substring". Only required when selecting "substring_pooled" option.
|
|
81
|
+
- **`--context`** (int, optional): Only specify when including "substring_pooled" in `--extract_embeddings` option. Number of amino acids to include before and after the substring sequence. Default is `0`.
|
|
82
|
+
|
|
83
|
+
### Processing Configuration
|
|
84
|
+
- **`--batch_size`** (int, optional): Batch size for loading sequences. Default is `1024`. Decrease if encountering out-of-memory errors.
|
|
85
|
+
- **`--max_length`** (int, optional): Length to which sequences will be padded. Default is length of longest sequence in input file. If shorter than longest sequence, will forcefully default to length of longest sequence.
|
|
86
|
+
- **`--discard_padding`** (bool, optional): Discard padding tokens from per_token embeddings output. Default is `False`.
|
|
87
|
+
|
|
88
|
+
### Output Configuration
|
|
89
|
+
- **`--experiment_name`** (str, optional): Prefix for names of output files. If not provided, name of input file will be used for prefix.
|
|
90
|
+
- **`--streaming_output`** (bool, optional): PEPE preallocates the required disk space and writes each batch of outputs concurrently. Can pose issues with file systems that do not support memory mapping (such as some distributed file systems.)
|
|
91
|
+
When False, all outputs are stored in RAM and written to disk at once after computation has finished. Default is `True`.
|
|
92
|
+
- **`--precision`** (str, optional): Precision of the output data. Choose from `float16`, `16`, `half`, `float32`, `32`, `full`. Inference during embedding is not affected. Default is `float32`.
|
|
93
|
+
- **`--flatten`** (bool, optional): Flatten 2D output arrays (per_token embeddings or attention weights) to 1D arrays per input sequence. Default is `False`.
|
|
94
|
+
|
|
95
|
+
### Performance Configuration
|
|
96
|
+
- **`--num_workers`** (int, optional): Number of workers for asynchronous data writing. Only relevant when `--streaming_output` is enabled. Default is `8`.
|
|
97
|
+
- **`--flush_batches_after`** (int, optional): Size (in MB) of outputs to accumulate in RAM per worker before flushing to disk. Default is `128`.
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example script showing how to create and use a custom model with EmbedAIRR.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
import torch.nn as nn
|
|
8
|
+
import os
|
|
9
|
+
import json
|
|
10
|
+
from transformers import AutoTokenizer
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExampleProteinModel(nn.Module):
|
|
15
|
+
"""
|
|
16
|
+
Example protein model for demonstration.
|
|
17
|
+
This is a simple transformer-based model for protein sequences.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self, vocab_size=25, hidden_size=768, num_layers=6, num_heads=12, max_length=512
|
|
22
|
+
):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.hidden_size = hidden_size
|
|
25
|
+
self.num_layers = num_layers
|
|
26
|
+
self.num_heads = num_heads
|
|
27
|
+
|
|
28
|
+
# Embedding layers
|
|
29
|
+
self.token_embedding = nn.Embedding(vocab_size, hidden_size)
|
|
30
|
+
self.position_embedding = nn.Embedding(max_length, hidden_size)
|
|
31
|
+
|
|
32
|
+
# Transformer layers
|
|
33
|
+
encoder_layer = nn.TransformerEncoderLayer(
|
|
34
|
+
d_model=hidden_size,
|
|
35
|
+
nhead=num_heads,
|
|
36
|
+
dim_feedforward=hidden_size * 4,
|
|
37
|
+
dropout=0.1,
|
|
38
|
+
batch_first=True,
|
|
39
|
+
)
|
|
40
|
+
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
|
|
41
|
+
|
|
42
|
+
# Output head
|
|
43
|
+
self.output_head = nn.Linear(hidden_size, vocab_size)
|
|
44
|
+
|
|
45
|
+
# Layer normalization
|
|
46
|
+
self.layer_norm = nn.LayerNorm(hidden_size)
|
|
47
|
+
|
|
48
|
+
def forward(
|
|
49
|
+
self,
|
|
50
|
+
input_ids,
|
|
51
|
+
attention_mask=None,
|
|
52
|
+
output_hidden_states=False,
|
|
53
|
+
output_attentions=False,
|
|
54
|
+
return_dict=True,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
Forward pass compatible with EmbedAIRR custom embedder.
|
|
58
|
+
"""
|
|
59
|
+
batch_size, seq_len = input_ids.shape
|
|
60
|
+
|
|
61
|
+
# Create position ids
|
|
62
|
+
position_ids = (
|
|
63
|
+
torch.arange(seq_len, device=input_ids.device)
|
|
64
|
+
.unsqueeze(0)
|
|
65
|
+
.expand(batch_size, -1)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Embeddings
|
|
69
|
+
token_embeddings = self.token_embedding(input_ids)
|
|
70
|
+
position_embeddings = self.position_embedding(position_ids)
|
|
71
|
+
hidden_states = self.layer_norm(token_embeddings + position_embeddings)
|
|
72
|
+
|
|
73
|
+
# Store hidden states if requested
|
|
74
|
+
all_hidden_states = []
|
|
75
|
+
if output_hidden_states:
|
|
76
|
+
all_hidden_states.append(hidden_states)
|
|
77
|
+
|
|
78
|
+
# Apply transformer layers
|
|
79
|
+
for layer in self.transformer.layers:
|
|
80
|
+
hidden_states = layer(
|
|
81
|
+
hidden_states,
|
|
82
|
+
src_key_padding_mask=(
|
|
83
|
+
~attention_mask.bool() if attention_mask is not None else None
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
if output_hidden_states:
|
|
87
|
+
all_hidden_states.append(hidden_states)
|
|
88
|
+
|
|
89
|
+
# Output logits
|
|
90
|
+
logits = self.output_head(hidden_states)
|
|
91
|
+
|
|
92
|
+
# Create output object
|
|
93
|
+
class ModelOutput:
|
|
94
|
+
def __init__(self):
|
|
95
|
+
self.hidden_states = all_hidden_states if output_hidden_states else None
|
|
96
|
+
self.logits = logits
|
|
97
|
+
self.attentions = None # Not implemented in this example
|
|
98
|
+
|
|
99
|
+
return ModelOutput()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def create_example_model_and_tokenizer(
|
|
103
|
+
save_path="./examples/custom_model/example_protein_model",
|
|
104
|
+
):
|
|
105
|
+
"""
|
|
106
|
+
Create and save an example protein model and tokenizer.
|
|
107
|
+
"""
|
|
108
|
+
# Create model
|
|
109
|
+
model = ExampleProteinModel(
|
|
110
|
+
vocab_size=25,
|
|
111
|
+
hidden_size=384, # Smaller for example
|
|
112
|
+
num_layers=6,
|
|
113
|
+
num_heads=12,
|
|
114
|
+
max_length=512,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Initialize weights (in practice, you would train the model)
|
|
118
|
+
for param in model.parameters():
|
|
119
|
+
if param.dim() > 1:
|
|
120
|
+
nn.init.xavier_uniform_(param)
|
|
121
|
+
|
|
122
|
+
# Create save directory
|
|
123
|
+
os.makedirs(save_path, exist_ok=True)
|
|
124
|
+
|
|
125
|
+
# Save model
|
|
126
|
+
torch.save(
|
|
127
|
+
{
|
|
128
|
+
"model": model.state_dict(),
|
|
129
|
+
"config": {
|
|
130
|
+
"num_layers": 6,
|
|
131
|
+
"num_attention_heads": 12,
|
|
132
|
+
"hidden_size": 384,
|
|
133
|
+
"vocab_size": 25,
|
|
134
|
+
"max_position_embeddings": 512,
|
|
135
|
+
"model_type": "protein_transformer",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
os.path.join(save_path, "pytorch_model.pt"),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Save config
|
|
142
|
+
config = {
|
|
143
|
+
"num_layers": 6,
|
|
144
|
+
"num_attention_heads": 12,
|
|
145
|
+
"hidden_size": 384,
|
|
146
|
+
"vocab_size": 25,
|
|
147
|
+
"max_position_embeddings": 512,
|
|
148
|
+
"model_type": "protein_transformer",
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
with open(os.path.join(save_path, "config.json"), "w") as f:
|
|
152
|
+
json.dump(config, f, indent=2)
|
|
153
|
+
|
|
154
|
+
# Create tokenizer files
|
|
155
|
+
_create_tokenizer_files(save_path)
|
|
156
|
+
|
|
157
|
+
print(f"Example model saved to: {save_path}")
|
|
158
|
+
print(f"Model config: {config}")
|
|
159
|
+
|
|
160
|
+
return save_path
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _create_tokenizer_files(save_path):
|
|
164
|
+
"""
|
|
165
|
+
Create tokenizer files compatible with AutoTokenizer.from_pretrained().
|
|
166
|
+
"""
|
|
167
|
+
# Define protein vocabulary
|
|
168
|
+
vocab = {
|
|
169
|
+
"<pad>": 0,
|
|
170
|
+
"<cls>": 1,
|
|
171
|
+
"<sep>": 2,
|
|
172
|
+
"<unk>": 3,
|
|
173
|
+
"A": 4,
|
|
174
|
+
"R": 5,
|
|
175
|
+
"N": 6,
|
|
176
|
+
"D": 7,
|
|
177
|
+
"C": 8,
|
|
178
|
+
"Q": 9,
|
|
179
|
+
"E": 10,
|
|
180
|
+
"G": 11,
|
|
181
|
+
"H": 12,
|
|
182
|
+
"I": 13,
|
|
183
|
+
"L": 14,
|
|
184
|
+
"K": 15,
|
|
185
|
+
"M": 16,
|
|
186
|
+
"F": 17,
|
|
187
|
+
"P": 18,
|
|
188
|
+
"S": 19,
|
|
189
|
+
"T": 20,
|
|
190
|
+
"W": 21,
|
|
191
|
+
"Y": 22,
|
|
192
|
+
"V": 23,
|
|
193
|
+
"X": 24, # Unknown amino acid
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Create tokenizer_config.json
|
|
197
|
+
tokenizer_config = {
|
|
198
|
+
"tokenizer_class": "BertTokenizer",
|
|
199
|
+
"model_max_length": 512,
|
|
200
|
+
"do_lower_case": False,
|
|
201
|
+
"cls_token": "<cls>",
|
|
202
|
+
"sep_token": "<sep>",
|
|
203
|
+
"pad_token": "<pad>",
|
|
204
|
+
"unk_token": "<unk>",
|
|
205
|
+
"model_type": "protein_transformer",
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
with open(os.path.join(save_path, "tokenizer_config.json"), "w") as f:
|
|
209
|
+
json.dump(tokenizer_config, f, indent=2)
|
|
210
|
+
|
|
211
|
+
# Create vocab.json
|
|
212
|
+
with open(os.path.join(save_path, "vocab.json"), "w") as f:
|
|
213
|
+
json.dump(vocab, f, indent=2)
|
|
214
|
+
|
|
215
|
+
# Create vocab.txt (for BertTokenizer compatibility)
|
|
216
|
+
vocab_txt_content = []
|
|
217
|
+
for token, id in sorted(vocab.items(), key=lambda x: x[1]):
|
|
218
|
+
vocab_txt_content.append(token)
|
|
219
|
+
|
|
220
|
+
with open(os.path.join(save_path, "vocab.txt"), "w") as f:
|
|
221
|
+
f.write("\n".join(vocab_txt_content))
|
|
222
|
+
|
|
223
|
+
# Create special_tokens_map.json
|
|
224
|
+
special_tokens_map = {
|
|
225
|
+
"cls_token": "<cls>",
|
|
226
|
+
"sep_token": "<sep>",
|
|
227
|
+
"pad_token": "<pad>",
|
|
228
|
+
"unk_token": "<unk>",
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
with open(os.path.join(save_path, "special_tokens_map.json"), "w") as f:
|
|
232
|
+
json.dump(special_tokens_map, f, indent=2)
|
|
233
|
+
|
|
234
|
+
print(f"✓ Tokenizer files created in {save_path}")
|
|
235
|
+
print(" - tokenizer_config.json")
|
|
236
|
+
print(" - vocab.json")
|
|
237
|
+
print(" - vocab.txt")
|
|
238
|
+
print(" - special_tokens_map.json")
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def create_example_fasta(filename="./examples/custom_model/example_sequences.fasta"):
|
|
242
|
+
"""
|
|
243
|
+
Create an example FASTA file with protein sequences.
|
|
244
|
+
"""
|
|
245
|
+
sequences = [
|
|
246
|
+
(
|
|
247
|
+
"seq1",
|
|
248
|
+
"MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKRQTLGQHDFSAGEGLYTHMKALRPDEDRLSLEVGQIA",
|
|
249
|
+
),
|
|
250
|
+
(
|
|
251
|
+
"seq2",
|
|
252
|
+
"MRIILLGAPGAGKGTQAQFIMEKYGIPQISTGDMLRAAVKSGSELGKQAKDIMDAGKLVTDELVIALVKERIAQEDCRNGFLLDGFPRTIPQADAMKEAGINVDYVLEFDVPDELIVDRIVGRRVHAPSGRVYHVKFNPPKVEGKDDVTGEELTTRKDDQEETVRKRLVEYHQMTAPLIGYYSKEAEAGNTKYAKVDGTKPVAEVRADLEKILG",
|
|
253
|
+
),
|
|
254
|
+
(
|
|
255
|
+
"seq3",
|
|
256
|
+
"MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG",
|
|
257
|
+
),
|
|
258
|
+
(
|
|
259
|
+
"seq4",
|
|
260
|
+
"MHHHHHHSSGVDLGTENLYFQSMKKWVTFISLLFLFSSAYSRGVFRRDAHKSEVAHRFKDLGEQHFKGLVLIAFSQYLQQCPFDEHVKLVNELTEFAKTCVADESHAGCEKSLHTLFGDELCKVASLRETARDLLHIQEKLLESYIFQGPRDTHYSQKFPQTLKLLDRKQLAGDLSSQFQEAFEQATRQRQAKVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQ",
|
|
261
|
+
),
|
|
262
|
+
("seq5", "ARNDCEQGHILKMFPSTWYV"), # All amino acids
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
with open(filename, "w") as f:
|
|
266
|
+
for seq_id, sequence in sequences:
|
|
267
|
+
f.write(f">{seq_id}\n{sequence}\n")
|
|
268
|
+
|
|
269
|
+
print(f"Example FASTA file created: {filename}")
|
|
270
|
+
return filename
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def create_example_substring(filename="./examples/custom_model/example_substring.csv"):
|
|
274
|
+
"""
|
|
275
|
+
Create an example substring file.
|
|
276
|
+
"""
|
|
277
|
+
substring_data = [
|
|
278
|
+
(
|
|
279
|
+
"seq1",
|
|
280
|
+
"AKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKRQTLGQHDFSAGEGLYTHMKALRPDEDRLSLEVGQIA",
|
|
281
|
+
),
|
|
282
|
+
(
|
|
283
|
+
"seq2",
|
|
284
|
+
"DGKLVTDELVIALVKERIAQEDCRNGFLLDGFPRTIPQADAMKEAGINVDYVLEFDVPDELIVDRIVGRRVHAPSGRVYHVKFNPPKVEGKDDVTGEELTTRKDDQEETVRKRLVEYHQMTAPLIGYYSKEAEAGNTKYAKVDGTKPVAEVRADLEKILG",
|
|
285
|
+
),
|
|
286
|
+
("seq3", "DKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG"),
|
|
287
|
+
(
|
|
288
|
+
"seq4",
|
|
289
|
+
"TCVADESHAGCEKSLHTLFGDELCKVASLRETARDLLHIQEKLLESYIFQGPRDTHYSQKFPQTLKLLDRKQLAGDLSSQFQEAFEQATRQRQAKVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQVQWLKRQFRQAGNTDVQRQFQFSQIRLQAGRQAEFQWLQRQFQARAGQIEQTQRQAQ",
|
|
290
|
+
),
|
|
291
|
+
("seq5", "ARNDCEQGHILKMFPSTWYV"),
|
|
292
|
+
]
|
|
293
|
+
|
|
294
|
+
with open(filename, "w") as f:
|
|
295
|
+
f.write("sequence_id,substring_aa\n")
|
|
296
|
+
for seq_id, substring in substring_data:
|
|
297
|
+
f.write(f"{seq_id},{substring}\n")
|
|
298
|
+
|
|
299
|
+
print(f"Example substring file created: {filename}")
|
|
300
|
+
return filename
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def main():
|
|
304
|
+
"""
|
|
305
|
+
Main function to create example files and demonstrate usage.
|
|
306
|
+
"""
|
|
307
|
+
print("Creating example custom protein model...")
|
|
308
|
+
|
|
309
|
+
# Create example model
|
|
310
|
+
model_path = create_example_model_and_tokenizer()
|
|
311
|
+
|
|
312
|
+
# Create example data
|
|
313
|
+
fasta_file = create_example_fasta()
|
|
314
|
+
substring_file = create_example_substring()
|
|
315
|
+
|
|
316
|
+
# Test loading the model
|
|
317
|
+
print("\nTesting model loading...")
|
|
318
|
+
try:
|
|
319
|
+
model_data = torch.load(
|
|
320
|
+
os.path.join(model_path, "pytorch_model.pt"), map_location="cpu"
|
|
321
|
+
)
|
|
322
|
+
print(f"✓ Model loaded successfully")
|
|
323
|
+
print(f"✓ Model config: {model_data.get('config', {})}")
|
|
324
|
+
|
|
325
|
+
# Test creating the model
|
|
326
|
+
model = ExampleProteinModel(
|
|
327
|
+
vocab_size=25, hidden_size=384, num_layers=6, num_heads=12, max_length=512
|
|
328
|
+
)
|
|
329
|
+
model.load_state_dict(model_data["model"])
|
|
330
|
+
print(f"✓ Model architecture created and weights loaded")
|
|
331
|
+
|
|
332
|
+
# Test tokenizer loading
|
|
333
|
+
try:
|
|
334
|
+
tokenizer = AutoTokenizer.from_pretrained(model_path)
|
|
335
|
+
print(
|
|
336
|
+
f"✓ Tokenizer loaded successfully with AutoTokenizer.from_pretrained()"
|
|
337
|
+
)
|
|
338
|
+
print(f"✓ Tokenizer vocab size: {len(tokenizer.get_vocab())}")
|
|
339
|
+
|
|
340
|
+
# Test tokenization
|
|
341
|
+
test_sequence = "ARNDCEQGHILKMFPSTWYV"
|
|
342
|
+
tokens = tokenizer(test_sequence, return_tensors="pt")
|
|
343
|
+
print(f"✓ Tokenization test successful")
|
|
344
|
+
print(f"✓ Input sequence: {test_sequence}")
|
|
345
|
+
print(f"✓ Tokenized shape: {tokens['input_ids'].shape}")
|
|
346
|
+
|
|
347
|
+
except Exception as e:
|
|
348
|
+
print(f"✗ Error testing tokenizer: {e}")
|
|
349
|
+
|
|
350
|
+
# Test forward pass
|
|
351
|
+
dummy_input = torch.randint(0, 25, (1, 10))
|
|
352
|
+
dummy_mask = torch.ones(1, 10)
|
|
353
|
+
|
|
354
|
+
with torch.no_grad():
|
|
355
|
+
output = model(
|
|
356
|
+
dummy_input, attention_mask=dummy_mask, output_hidden_states=True
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
print(f"✓ Forward pass successful")
|
|
360
|
+
print(f"✓ Output logits shape: {output.logits.shape}")
|
|
361
|
+
print(
|
|
362
|
+
f"✓ Number of hidden states: {len(output.hidden_states) if output.hidden_states else 0}"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
except Exception as e:
|
|
366
|
+
print(f"✗ Error testing model: {e}")
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
print("\nAll tests passed! The custom model is ready to use with EmbedAIRR.")
|
|
370
|
+
return True
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
if __name__ == "__main__":
|
|
374
|
+
main()
|