pepe-cli 1.0.4__tar.gz → 1.1__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.
Files changed (44) hide show
  1. {pepe_cli-1.0.4/src/pepe_cli.egg-info → pepe_cli-1.1}/PKG-INFO +151 -8
  2. pepe_cli-1.1/README.md +242 -0
  3. {pepe_cli-1.0.4 → pepe_cli-1.1}/pyproject.toml +0 -2
  4. {pepe_cli-1.0.4 → pepe_cli-1.1}/requirements.txt +0 -1
  5. {pepe_cli-1.0.4 → pepe_cli-1.1}/setup.py +0 -2
  6. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/__init__.py +6 -1
  7. pepe_cli-1.1/src/pepe/api.py +118 -0
  8. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/embedders/base_embedder.py +269 -26
  9. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/embedders/custom_embedder.py +8 -6
  10. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/embedders/esm_embedder.py +9 -5
  11. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/embedders/huggingface_embedder.py +14 -9
  12. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/parse_arguments.py +26 -6
  13. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/utils.py +105 -42
  14. {pepe_cli-1.0.4 → pepe_cli-1.1/src/pepe_cli.egg-info}/PKG-INFO +151 -8
  15. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe_cli.egg-info/SOURCES.txt +7 -1
  16. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe_cli.egg-info/requires.txt +0 -2
  17. pepe_cli-1.1/src/tests/test_api_unittest.py +117 -0
  18. pepe_cli-1.1/src/tests/test_device_logic.py +107 -0
  19. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/tests/test_run.py +11 -9
  20. pepe_cli-1.1/src/tests/test_splitting.py +206 -0
  21. pepe_cli-1.1/src/tests/verify_cross_tool_consistency.py +132 -0
  22. pepe_cli-1.1/src/tests/verify_readme.py +65 -0
  23. pepe_cli-1.0.4/README.md +0 -97
  24. {pepe_cli-1.0.4 → pepe_cli-1.1}/LICENSE +0 -0
  25. {pepe_cli-1.0.4 → pepe_cli-1.1}/MANIFEST.in +0 -0
  26. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/create_example_custom_model.py +0 -0
  27. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/config.json +0 -0
  28. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/pytorch_model.pt +0 -0
  29. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/special_tokens_map.json +0 -0
  30. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/tokenizer_config.json +0 -0
  31. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/vocab.json +0 -0
  32. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_protein_model/vocab.txt +0 -0
  33. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_sequences.fasta +0 -0
  34. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/custom_model/example_substring.csv +0 -0
  35. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/embedding_options.md +0 -0
  36. {pepe_cli-1.0.4 → pepe_cli-1.1}/examples/model_selection.md +0 -0
  37. {pepe_cli-1.0.4 → pepe_cli-1.1}/setup.cfg +0 -0
  38. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/__main__.py +0 -0
  39. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/embedders/__init__.py +0 -0
  40. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe/model_selecter.py +0 -0
  41. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe_cli.egg-info/dependency_links.txt +0 -0
  42. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe_cli.egg-info/entry_points.txt +0 -0
  43. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/pepe_cli.egg-info/top_level.txt +0 -0
  44. {pepe_cli-1.0.4 → pepe_cli-1.1}/src/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pepe-cli
3
- Version: 1.0.4
3
+ Version: 1.1
4
4
  Summary: Pipeline for Easy Protein Embedding - Extract embeddings and attention matrices from protein sequences
5
5
  Home-page: https://github.com/csi-greifflab/pepe-cli
6
6
  Author: Jahn Zhong
@@ -27,11 +27,9 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: torch>=1.9.0
29
29
  Requires-Dist: transformers>=4.20.0
30
- Requires-Dist: fair-esm
31
30
  Requires-Dist: sentencepiece
32
31
  Requires-Dist: numpy
33
32
  Requires-Dist: protobuf
34
- Requires-Dist: rjieba
35
33
  Requires-Dist: alive_progress
36
34
  Dynamic: author
37
35
  Dynamic: home-page
@@ -49,6 +47,10 @@ PEPE (Pipeline for Easy Protein Embedding) is a tool for extracting embeddings a
49
47
  ```sh
50
48
  pip install pepe-cli
51
49
  ```
50
+ From Conda:
51
+ ```sh
52
+ conda install -c jahn_zhong pepe-cli
53
+ ```
52
54
  Or install from the GitHub repository:
53
55
  ```sh
54
56
  git clone https://github.com/csi-greifflab/pepe-cli
@@ -61,6 +63,135 @@ PEPE (Pipeline for Easy Protein Embedding) is a tool for extracting embeddings a
61
63
  pepe --experiment_name <optional_string> --fasta_path <file_path> --output_path <directory> --model_name <model_name>
62
64
  ```
63
65
 
66
+ ## Quick start with Library
67
+
68
+ PEPE can also be used as a Python library. This allows for programmatic access to protein embeddings without using the command-line interface.
69
+
70
+ 1. Install PEPE (see [Quick start with CLI](#quick-start-with-cli) for details).
71
+ 2. Use the `pepe.embed()` function in your script:
72
+
73
+ ```python
74
+ import pepe
75
+
76
+ # Example: Embed sequences from a dictionary
77
+ sequences = {
78
+ "prot1": "MADKQKNGIKVNFKIRHNIEDGSVQLADHYQQNTPIGDGPVLLPDNHYLSTQSALSKDPNEKRDHMVLLEFVTAAGITHGMDELYK",
79
+ "prot2": "MERIKELRDLMSQSRTREILTKLAEAGIDVPRLFK"
80
+ }
81
+
82
+ results = pepe.embed(
83
+ model_name="facebook/esm2_t6_8M_UR50D",
84
+ sequences=sequences,
85
+ output_path="my_embeddings",
86
+ extract_embeddings=["mean_pooled"],
87
+ device="cpu" # Use "cuda", "cuda:0", "cuda:1", etc. if available
88
+ )
89
+
90
+ # Or from a FASTA file
91
+ pepe.embed(
92
+ model_name="facebook/esm2_t6_8M_UR50D",
93
+ fasta_path="path/to/fasta",
94
+ output_path="my_embeddings",
95
+ extract_embeddings=["mean_pooled"],
96
+ device="cpu" # Use "cuda" if available
97
+ )
98
+ ```
99
+
100
+ ### Advanced Usage
101
+
102
+ For more control, you can use the embedder classes directly:
103
+
104
+ ```python
105
+ from pepe.model_selecter import select_model
106
+
107
+ # Select the appropriate model class
108
+ # This acts as a factory returning the correct subclass (ESMEmbedder, HuggingfaceEmbedder, etc.)
109
+ ModelClass = select_model("esm2_t6_8M_UR50D")
110
+
111
+ # Initialize the embedder
112
+ embedder = ModelClass(
113
+ model_name="facebook/esm2_t6_8M_UR50D",
114
+ fasta_path="path/to/sequences.fasta",
115
+ output_path="output_directory",
116
+ extract_embeddings=["mean_pooled", "attention_head"],
117
+ layers=[[-1], [6]] # Layers are expected as a list of lists of ints
118
+ )
119
+
120
+ # Run the embedding pipeline
121
+ embedder.run()
122
+ ```
123
+
124
+ ### Memory Management & Large Scale Processing
125
+
126
+ PEPE is designed to handle protein datasets of any size by utilizing **streamed outputs** and **memory mapping**. This feature is enabled by default (`streaming_output=True`).
127
+
128
+ - **CLI Usage**: No action needed. PEPE automatically streams batches to disk to avoid OOM errors.
129
+ - **Library Usage**: When using `pepe.embed()` or the embedder classes, the returned object does **not** hold the full embeddings in RAM. Instead, it provides `numpy.memmap` handles to the data on disk.
130
+
131
+ ```python
132
+ import pepe
133
+
134
+ # Returns an embedder object
135
+ results = pepe.embed(
136
+ model_name="facebook/esm2_t6_8M_UR50D",
137
+ sequences=sequences,
138
+ output_path="large_dataset_output"
139
+ # streaming_output=True <-- Default
140
+ )
141
+
142
+ # The embeddings are NOT loaded into RAM here.
143
+ # 'data' is a numpy.memmap object pointing to the file on disk.
144
+ data = results.mean_pooled["output_data"][-1]
145
+
146
+ # You can slice it like a normal array, which only loads those specific rows into RAM
147
+ first_100_embeddings = data[:100]
148
+
149
+ # Optimizing RAM usage:
150
+ # If you are done with the model but want to keep working with the data,
151
+ # you can delete the embedder object to free up GPU/CPU memory while keeping the memmaps.
152
+ del results
153
+ ```
154
+
155
+ ### Handling Long Sequences (Splitting & Reconstruction)
156
+
157
+ Some models have strict architectural limits on input length (e.g., 1024 for ESM-2, 256 for AntiBERTa2). PEPE can automatically detect sequences that exceed these limits and handle them through chunking and reconstruction.
158
+
159
+ - **Automatic Detection**: When `--split_long_sequences` is enabled, PEPE automatically identifies sequences exceeding the model's capacity.
160
+ - **Overlapping Chunks**: Use `--split_overlap` to maintain context between chunks.
161
+ - **Reconstruction**:
162
+ - In **Library mode**, sequences are reconstructed in memory automatically after `embed()`.
163
+ - In **CLI mode**, sequences are reconstructed if `streaming_output=False`. If `streaming_output=True`, chunks are exported individually to maximize efficiency and minimize RAM usage.
164
+
165
+ ```python
166
+ # Library Example: Process a 2000 AA protein with ESM-2 (1024 limit)
167
+ results = pepe.embed(
168
+ model_name="facebook/esm2_t33_650M_UR50D",
169
+ sequences={"long_prot": "M" * 2000},
170
+ split_long_sequences=True,
171
+ split_overlap=50
172
+ )
173
+
174
+ # 'results.per_token' will contain a single reconstructed tensor of length ~2002
175
+ # (including special tokens) despite the model's 1024 limit.
176
+ ```
177
+
178
+
179
+ #### Performance Optimization
180
+
181
+ If you have sufficient RAM to hold the entire dataset in memory, you can disable streaming output for faster execution. This avoids the overhead of writing to disk during the embedding process.
182
+
183
+ ```python
184
+ results = pepe.embed(
185
+ model_name="facebook/esm2_t6_8M_UR50D",
186
+ sequences=sequences,
187
+ output_path="output",
188
+ streaming_output=False # Store everything in valid RAM for speed
189
+ )
190
+
191
+ # Now 'results.mean_pooled["output_data"]' is a standard Numpy object
192
+ # accessible immediately in memory.
193
+ ```
194
+
64
195
  ## List of supported models:
65
196
  - ESM-family models
66
197
  - ESM1:
@@ -112,23 +243,35 @@ PEPE (Pipeline for Easy Protein Embedding) is a tool for extracting embeddings a
112
243
  ### Model Configuration
113
244
  - **`--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
245
  - **`--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`.
246
+ - **`--device`** (str, optional): Device to run the model on. Choose from `cuda`, `cpu`, or specific GPU indices like `cuda:0`, `cuda:1`. Default is `cuda`.
116
247
 
117
248
  ### Embedding Configuration
118
249
  - **`--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`.
250
+ - **`--extract_embeddings`** (str, optional): Set the embedding return types. Choose one or more from:
251
+ - `per_token`: Extracts embeddings for each token (amino acid) in the sequence. Output shape: `(num_sequences, max_length, embedding_size)`.
252
+ - `mean_pooled`: Computes the average embedding across all tokens in a sequence, excluding special tokens (BOS, EOS, padding). Output shape: `(num_sequences, embedding_size)`.
253
+ - `substring_pooled`: Computes the average embedding for a specific substring within each sequence (e.g., a CDR3 region). Requires `--substring_path`. Output shape: `(num_sequences, embedding_size)`.
254
+ - `attention_head`: Extracts raw attention weights for every individual head in the specified layers. Output shape: `(num_sequences, max_length, max_length)` per head.
255
+ - `attention_layer`: Extracts the average attention weights across all heads within each specified layer. Output shape: `(num_sequences, max_length, max_length)` per layer.
256
+ - `attention_model`: Extracts the average attention weights across all heads and all specified layers. Output shape: `(num_sequences, max_length, max_length)`.
257
+ - `logits`: Extracts the raw language model output (logits). (Experimental)
258
+ Default is `mean_pooled`.
120
259
  - **`--substring_path`** (str, optional): Path to a CSV file with columns "sequence_id" and "substring". Only required when selecting "substring_pooled" option.
121
260
  - **`--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
261
 
123
262
  ### Processing Configuration
124
263
  - **`--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`.
264
+ - **`--max_length`** (int, optional): Length to which sequences will be padded. Default is length of longest sequence in input file + special token(s). If shorter than longest sequence, will forcefully default to length of longest sequence + special token(s).
265
+ - **`--split_long_sequences`** (bool, optional): When True, automatically detect sequences exceeding the model's maximum allowed length and split them into chunks for processing. Default is `False`.
266
+ - **`--split_overlap`** (int, optional): Number of tokens to overlap when splitting long sequences. This helps maintain context across chunk boundaries. Default is `0`.
267
+ - **`--force_split_length`** (int, optional): Explicitly force sequence splitting at a specific length, overriding the model's auto-detected limits. Default is `None`.
268
+ - **`--discard_padding`** (bool, optional): Discard padding tokens from per_token embeddings output. **Note**: Setting this to `True` will automatically disable `--streaming_output`. Default is `False`.
269
+
127
270
 
128
271
  ### Output Configuration
129
272
  - **`--experiment_name`** (str, optional): Prefix for names of output files. If not provided, name of input file will be used for prefix.
130
273
  - **`--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`.
274
+ When False, all outputs are stored in RAM and written to disk at once after computation has finished. **Note**: Automatically disabled if `--discard_padding` is `True`. Default is `True`.
132
275
  - **`--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
276
  - **`--flatten`** (bool, optional): Flatten 2D output arrays (per_token embeddings or attention weights) to 1D arrays per input sequence. Default is `False`.
134
277
 
pepe_cli-1.1/README.md ADDED
@@ -0,0 +1,242 @@
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
+ From Conda:
13
+ ```sh
14
+ conda install -c jahn_zhong pepe-cli
15
+ ```
16
+ Or install from the GitHub repository:
17
+ ```sh
18
+ git clone https://github.com/csi-greifflab/pepe-cli
19
+ cd pepe-cli
20
+ pip install .
21
+ ```
22
+ 2. Run the embedding script:\
23
+ Extract mean pooled embeddings from protein amino acid sequences in FASTA file:
24
+ ```sh
25
+ pepe --experiment_name <optional_string> --fasta_path <file_path> --output_path <directory> --model_name <model_name>
26
+ ```
27
+
28
+ ## Quick start with Library
29
+
30
+ PEPE can also be used as a Python library. This allows for programmatic access to protein embeddings without using the command-line interface.
31
+
32
+ 1. Install PEPE (see [Quick start with CLI](#quick-start-with-cli) for details).
33
+ 2. Use the `pepe.embed()` function in your script:
34
+
35
+ ```python
36
+ import pepe
37
+
38
+ # Example: Embed sequences from a dictionary
39
+ sequences = {
40
+ "prot1": "MADKQKNGIKVNFKIRHNIEDGSVQLADHYQQNTPIGDGPVLLPDNHYLSTQSALSKDPNEKRDHMVLLEFVTAAGITHGMDELYK",
41
+ "prot2": "MERIKELRDLMSQSRTREILTKLAEAGIDVPRLFK"
42
+ }
43
+
44
+ results = pepe.embed(
45
+ model_name="facebook/esm2_t6_8M_UR50D",
46
+ sequences=sequences,
47
+ output_path="my_embeddings",
48
+ extract_embeddings=["mean_pooled"],
49
+ device="cpu" # Use "cuda", "cuda:0", "cuda:1", etc. if available
50
+ )
51
+
52
+ # Or from a FASTA file
53
+ pepe.embed(
54
+ model_name="facebook/esm2_t6_8M_UR50D",
55
+ fasta_path="path/to/fasta",
56
+ output_path="my_embeddings",
57
+ extract_embeddings=["mean_pooled"],
58
+ device="cpu" # Use "cuda" if available
59
+ )
60
+ ```
61
+
62
+ ### Advanced Usage
63
+
64
+ For more control, you can use the embedder classes directly:
65
+
66
+ ```python
67
+ from pepe.model_selecter import select_model
68
+
69
+ # Select the appropriate model class
70
+ # This acts as a factory returning the correct subclass (ESMEmbedder, HuggingfaceEmbedder, etc.)
71
+ ModelClass = select_model("esm2_t6_8M_UR50D")
72
+
73
+ # Initialize the embedder
74
+ embedder = ModelClass(
75
+ model_name="facebook/esm2_t6_8M_UR50D",
76
+ fasta_path="path/to/sequences.fasta",
77
+ output_path="output_directory",
78
+ extract_embeddings=["mean_pooled", "attention_head"],
79
+ layers=[[-1], [6]] # Layers are expected as a list of lists of ints
80
+ )
81
+
82
+ # Run the embedding pipeline
83
+ embedder.run()
84
+ ```
85
+
86
+ ### Memory Management & Large Scale Processing
87
+
88
+ PEPE is designed to handle protein datasets of any size by utilizing **streamed outputs** and **memory mapping**. This feature is enabled by default (`streaming_output=True`).
89
+
90
+ - **CLI Usage**: No action needed. PEPE automatically streams batches to disk to avoid OOM errors.
91
+ - **Library Usage**: When using `pepe.embed()` or the embedder classes, the returned object does **not** hold the full embeddings in RAM. Instead, it provides `numpy.memmap` handles to the data on disk.
92
+
93
+ ```python
94
+ import pepe
95
+
96
+ # Returns an embedder object
97
+ results = pepe.embed(
98
+ model_name="facebook/esm2_t6_8M_UR50D",
99
+ sequences=sequences,
100
+ output_path="large_dataset_output"
101
+ # streaming_output=True <-- Default
102
+ )
103
+
104
+ # The embeddings are NOT loaded into RAM here.
105
+ # 'data' is a numpy.memmap object pointing to the file on disk.
106
+ data = results.mean_pooled["output_data"][-1]
107
+
108
+ # You can slice it like a normal array, which only loads those specific rows into RAM
109
+ first_100_embeddings = data[:100]
110
+
111
+ # Optimizing RAM usage:
112
+ # If you are done with the model but want to keep working with the data,
113
+ # you can delete the embedder object to free up GPU/CPU memory while keeping the memmaps.
114
+ del results
115
+ ```
116
+
117
+ ### Handling Long Sequences (Splitting & Reconstruction)
118
+
119
+ Some models have strict architectural limits on input length (e.g., 1024 for ESM-2, 256 for AntiBERTa2). PEPE can automatically detect sequences that exceed these limits and handle them through chunking and reconstruction.
120
+
121
+ - **Automatic Detection**: When `--split_long_sequences` is enabled, PEPE automatically identifies sequences exceeding the model's capacity.
122
+ - **Overlapping Chunks**: Use `--split_overlap` to maintain context between chunks.
123
+ - **Reconstruction**:
124
+ - In **Library mode**, sequences are reconstructed in memory automatically after `embed()`.
125
+ - In **CLI mode**, sequences are reconstructed if `streaming_output=False`. If `streaming_output=True`, chunks are exported individually to maximize efficiency and minimize RAM usage.
126
+
127
+ ```python
128
+ # Library Example: Process a 2000 AA protein with ESM-2 (1024 limit)
129
+ results = pepe.embed(
130
+ model_name="facebook/esm2_t33_650M_UR50D",
131
+ sequences={"long_prot": "M" * 2000},
132
+ split_long_sequences=True,
133
+ split_overlap=50
134
+ )
135
+
136
+ # 'results.per_token' will contain a single reconstructed tensor of length ~2002
137
+ # (including special tokens) despite the model's 1024 limit.
138
+ ```
139
+
140
+
141
+ #### Performance Optimization
142
+
143
+ If you have sufficient RAM to hold the entire dataset in memory, you can disable streaming output for faster execution. This avoids the overhead of writing to disk during the embedding process.
144
+
145
+ ```python
146
+ results = pepe.embed(
147
+ model_name="facebook/esm2_t6_8M_UR50D",
148
+ sequences=sequences,
149
+ output_path="output",
150
+ streaming_output=False # Store everything in valid RAM for speed
151
+ )
152
+
153
+ # Now 'results.mean_pooled["output_data"]' is a standard Numpy object
154
+ # accessible immediately in memory.
155
+ ```
156
+
157
+ ## List of supported models:
158
+ - ESM-family models
159
+ - ESM1:
160
+ - esm1_t34_670M_UR50S
161
+ - esm1_t34_670M_UR50D
162
+ - esm1_t34_670M_UR100
163
+ - esm1_t12_85M_UR50S
164
+ - esm1_t6_43M_UR50S
165
+ - esm1b_t33_650M_UR50S
166
+ - esm1v_t33_650M_UR90S_1
167
+ - esm1v_t33_650M_UR90S_2
168
+ - esm1v_t33_650M_UR90S_3
169
+ - esm1v_t33_650M_UR90S_4
170
+ - esm1v_t33_650M_UR90S_5
171
+ - ESM2:
172
+ - esm2_t6_8M_UR50D
173
+ - esm2_t12_35M_UR50D
174
+ - esm2_t30_150M_UR50D
175
+ - esm2_t33_650M_UR50D
176
+ - esm2_t36_3B_UR50D
177
+ - esm2_t48_15B_UR50D
178
+ - Huggingface Transformer models
179
+ - T5 transformer models
180
+ - Rostlab/prot_t5_xl_half_uniref50-enc
181
+ - Rostlab/ProstT5
182
+ - RoFormer models
183
+ - alchemab/antiberta2-cssp
184
+ - alchemab/antiberta2
185
+ - Custom Hugging Face models
186
+ - Any compatible model from Hugging Face Hub: `username/model-name`
187
+ - Private models with authentication
188
+ - Local Hugging Face models
189
+ - Custom Models
190
+ - Load your own PyTorch models with custom tokenizers
191
+ - Create example with: `python examples/custom_model/create_example_custom_model.py`
192
+
193
+
194
+ ## Arguments
195
+
196
+ ### Required Arguments
197
+ - **`--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:
198
+ - ESM models: `esm2_t33_650M_UR50D`
199
+ - Hugging Face models: `username/model-name`
200
+ - Custom PyTorch models: `/path/to/model.pt` or `/path/to/model_directory/`
201
+ - Local HF models: `/path/to/local_hf_directory/`
202
+ - **`--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.
203
+ - **`--output_path`** (str): Directory for output files. Will generate a subdirectory for outputs of each output type.
204
+
205
+ ### Model Configuration
206
+ - **`--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.
207
+ - **`--disable_special_tokens`** (bool, optional): When True, PEPE disables pre- and appending BOS/CLS and EOS/SEP tokens before embedding. Default is `False`.
208
+ - **`--device`** (str, optional): Device to run the model on. Choose from `cuda`, `cpu`, or specific GPU indices like `cuda:0`, `cuda:1`. Default is `cuda`.
209
+
210
+ ### Embedding Configuration
211
+ - **`--layers`** (str, optional): Representation layers to extract from the model. Default is the last layer. Example: `--layers -1 6`.
212
+ - **`--extract_embeddings`** (str, optional): Set the embedding return types. Choose one or more from:
213
+ - `per_token`: Extracts embeddings for each token (amino acid) in the sequence. Output shape: `(num_sequences, max_length, embedding_size)`.
214
+ - `mean_pooled`: Computes the average embedding across all tokens in a sequence, excluding special tokens (BOS, EOS, padding). Output shape: `(num_sequences, embedding_size)`.
215
+ - `substring_pooled`: Computes the average embedding for a specific substring within each sequence (e.g., a CDR3 region). Requires `--substring_path`. Output shape: `(num_sequences, embedding_size)`.
216
+ - `attention_head`: Extracts raw attention weights for every individual head in the specified layers. Output shape: `(num_sequences, max_length, max_length)` per head.
217
+ - `attention_layer`: Extracts the average attention weights across all heads within each specified layer. Output shape: `(num_sequences, max_length, max_length)` per layer.
218
+ - `attention_model`: Extracts the average attention weights across all heads and all specified layers. Output shape: `(num_sequences, max_length, max_length)`.
219
+ - `logits`: Extracts the raw language model output (logits). (Experimental)
220
+ Default is `mean_pooled`.
221
+ - **`--substring_path`** (str, optional): Path to a CSV file with columns "sequence_id" and "substring". Only required when selecting "substring_pooled" option.
222
+ - **`--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`.
223
+
224
+ ### Processing Configuration
225
+ - **`--batch_size`** (int, optional): Batch size for loading sequences. Default is `1024`. Decrease if encountering out-of-memory errors.
226
+ - **`--max_length`** (int, optional): Length to which sequences will be padded. Default is length of longest sequence in input file + special token(s). If shorter than longest sequence, will forcefully default to length of longest sequence + special token(s).
227
+ - **`--split_long_sequences`** (bool, optional): When True, automatically detect sequences exceeding the model's maximum allowed length and split them into chunks for processing. Default is `False`.
228
+ - **`--split_overlap`** (int, optional): Number of tokens to overlap when splitting long sequences. This helps maintain context across chunk boundaries. Default is `0`.
229
+ - **`--force_split_length`** (int, optional): Explicitly force sequence splitting at a specific length, overriding the model's auto-detected limits. Default is `None`.
230
+ - **`--discard_padding`** (bool, optional): Discard padding tokens from per_token embeddings output. **Note**: Setting this to `True` will automatically disable `--streaming_output`. Default is `False`.
231
+
232
+
233
+ ### Output Configuration
234
+ - **`--experiment_name`** (str, optional): Prefix for names of output files. If not provided, name of input file will be used for prefix.
235
+ - **`--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.)
236
+ When False, all outputs are stored in RAM and written to disk at once after computation has finished. **Note**: Automatically disabled if `--discard_padding` is `True`. Default is `True`.
237
+ - **`--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`.
238
+ - **`--flatten`** (bool, optional): Flatten 2D output arrays (per_token embeddings or attention weights) to 1D arrays per input sequence. Default is `False`.
239
+
240
+ ### Performance Configuration
241
+ - **`--num_workers`** (int, optional): Number of workers for asynchronous data writing. Only relevant when `--streaming_output` is enabled. Default is `8`.
242
+ - **`--flush_batches_after`** (int, optional): Size (in MB) of outputs to accumulate in RAM per worker before flushing to disk. Default is `128`.
@@ -29,11 +29,9 @@ keywords = ["protein", "embeddings", "bioinformatics", "machine-learning", "nlp"
29
29
  dependencies = [
30
30
  "torch>=1.9.0",
31
31
  "transformers>=4.20.0",
32
- "fair-esm",
33
32
  "sentencepiece",
34
33
  "numpy",
35
34
  "protobuf",
36
- "rjieba",
37
35
  "alive_progress",
38
36
  ]
39
37
 
@@ -5,5 +5,4 @@ fair-esm
5
5
  sentencepiece
6
6
  numpy
7
7
  protobuf
8
- rjieba
9
8
  alive_progress
@@ -43,11 +43,9 @@ setup(
43
43
  install_requires=[
44
44
  "torch>=1.9.0",
45
45
  "transformers>=4.20.0",
46
- "fair-esm",
47
46
  "sentencepiece",
48
47
  "numpy",
49
48
  "protobuf",
50
- "rjieba",
51
49
  "alive_progress",
52
50
  ],
53
51
  entry_points={
@@ -1,8 +1,13 @@
1
1
  import logging
2
2
  import sys
3
3
 
4
+ try:
5
+ from pepe.api import embed # Exported to top-level; requires torch at runtime
6
+ except ImportError:
7
+ pass
8
+
4
9
  # Package metadata - single source of truth
5
- __version__ = "1.0.4"
10
+ __version__ = "1.1"
6
11
  __package_name__ = "pepe-cli"
7
12
  __module_name__ = "pepe"
8
13
  __author__ = "Jahn Zhong"
@@ -0,0 +1,118 @@
1
+ import os
2
+ import tempfile
3
+ import logging
4
+ from types import SimpleNamespace
5
+ from typing import Dict, List, Optional, Union, Any
6
+
7
+ from pepe.model_selecter import select_model
8
+ import pepe.utils
9
+
10
+ logger = logging.getLogger("pepe.api")
11
+
12
+ def embed(
13
+ model_name: str,
14
+ sequences: Optional[Union[Dict[str, str], List[str]]] = None,
15
+ fasta_path: Optional[str] = None,
16
+ output_path: Optional[str] = None,
17
+ extract_embeddings: List[str] = ["mean_pooled"],
18
+ layers: Union[List[int], List[List[int]]] = [[-1]],
19
+ batch_size: int = 1024,
20
+ device: str = "cuda",
21
+ precision: str = "32",
22
+ streaming_output: bool = True,
23
+ discard_padding: bool = False,
24
+ max_input_length: str = "max_length",
25
+ experiment_name: Optional[str] = None,
26
+ **kwargs
27
+ ) -> Dict[str, Any]:
28
+ """
29
+ High-level API for generating protein embeddings.
30
+
31
+ Args:
32
+ model_name: Model name or path to custom model.
33
+ sequences: Dictionary mapping labels to protein sequences, or a list of sequences.
34
+ fasta_path: Path to a FASTA file. Used if 'sequences' is not provided.
35
+ output_path: Directory for output files. If not provided, a temporary directory will be used.
36
+ extract_embeddings: List of embedding types to extract.
37
+ layers: Representation layers to extract. Default is the last layer ([-1]).
38
+ batch_size: Number of tokens per batch. Default is 1024.
39
+ device: Device to run the model on ('cuda' or 'cpu'). Default is 'cuda'.
40
+ precision: Output precision (e.g., '32', '16'). Default is '32'.
41
+ streaming_output: Whether to stream outputs to disk. Default is True.
42
+ discard_padding: Whether to discard padding tokens. Default is False.
43
+ max_input_length: Length to which sequences will be padded. Default is "max_length".
44
+ experiment_name: Optional prefix for output files.
45
+ **kwargs: Additional arguments supported by the embedders.
46
+
47
+ Returns:
48
+ A dictionary containing the results and/or the output path.
49
+ """
50
+ # Create a temporary fasta file if sequences are provided
51
+ temp_fasta = None
52
+ if sequences is not None:
53
+ if isinstance(sequences, list):
54
+ sequences = {f"seq_{i}": seq for i, seq in enumerate(sequences)}
55
+
56
+ temp_fasta = tempfile.NamedTemporaryFile(mode='w', suffix='.fasta', delete=False)
57
+ for label, seq in sequences.items():
58
+ temp_fasta.write(f">{label}\n{seq}\n")
59
+ temp_fasta.close()
60
+ fasta_path = temp_fasta.name
61
+
62
+ if fasta_path is None:
63
+ raise ValueError("Either 'sequences' or 'fasta_path' must be provided.")
64
+
65
+ return_results = False
66
+ if output_path is None:
67
+ if streaming_output:
68
+ logger.warning("No output_path provided. Disabling streaming_output and returning in-memory results.")
69
+ output_path = tempfile.mkdtemp()
70
+ streaming_output = False
71
+ return_results = True
72
+
73
+ # Create args object
74
+ args_dict = {
75
+ "model_name": model_name,
76
+ "fasta_path": fasta_path,
77
+ "output_path": output_path,
78
+ "extract_embeddings": extract_embeddings,
79
+ "layers": layers,
80
+ "batch_size": batch_size,
81
+ "device": device,
82
+ "precision": precision,
83
+ "streaming_output": streaming_output,
84
+ "discard_padding": discard_padding,
85
+ "max_input_length": max_input_length,
86
+ "experiment_name": experiment_name,
87
+ "tokenizer_from": kwargs.get("tokenizer_from"),
88
+ "substring_path": kwargs.get("substring_path"),
89
+ "context": kwargs.get("context", 0),
90
+ "split_long_sequences": kwargs.get("split_long_sequences", False),
91
+ "split_overlap": kwargs.get("split_overlap", 0),
92
+ "force_split_length": kwargs.get("force_split_length"),
93
+ "num_workers": kwargs.get("num_workers", 8),
94
+ "disable_special_tokens": kwargs.get("disable_special_tokens", False),
95
+ "flatten": kwargs.get("flatten", False),
96
+ "flush_batches_after": kwargs.get("flush_batches_after", 128),
97
+ }
98
+
99
+ args = SimpleNamespace(**args_dict)
100
+
101
+ selected_model_class = select_model(model_name)
102
+ embedder = selected_model_class(args)
103
+ embedder.run()
104
+
105
+ results = {"output_path": output_path}
106
+
107
+ if return_results:
108
+ # Pick up in-memory results before they are lost
109
+ for output_type in extract_embeddings:
110
+ obj = getattr(embedder, output_type, None)
111
+ if obj and "output_data" in obj:
112
+ results[output_type] = obj["output_data"]
113
+
114
+ # Cleanup temp file
115
+ if temp_fasta:
116
+ os.unlink(temp_fasta.name)
117
+
118
+ return results