pepe-cli 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,164 @@
1
+ import logging
2
+ import torch
3
+ from esm import pretrained
4
+ from pepe.embedders.base_embedder import BaseEmbedder
5
+ import pepe.utils
6
+
7
+ logger = logging.getLogger("src.embedders.esm_embedder")
8
+
9
+
10
+ class ESMEmbedder(BaseEmbedder):
11
+ def __init__(self, args):
12
+ super().__init__(args)
13
+ self.sequences = pepe.utils.fasta_to_dict(args.fasta_path)
14
+ self.num_sequences = len(self.sequences)
15
+ (
16
+ self.model,
17
+ self.alphabet,
18
+ self.num_heads,
19
+ self.num_layers,
20
+ self.embedding_size,
21
+ self.prepend_bos,
22
+ self.append_eos,
23
+ ) = self._initialize_model(self.model_name)
24
+ self.valid_tokens = set(self.alphabet.all_toks)
25
+ pepe.utils.check_input_tokens(
26
+ self.valid_tokens, self.sequences, self.model_name
27
+ )
28
+ self.special_tokens = self.get_special_tokens()
29
+ self.layers = self._load_layers(self.layers)
30
+ self.data_loader, self.max_length = self._load_data(
31
+ self.sequences, self.substring_dict
32
+ ) # tokenize and batch sequences and update max_length
33
+ self._set_output_objects()
34
+
35
+ def _initialize_model(self, model_name):
36
+ """Initialize the model, tokenizer"""
37
+ # Loading the pretrained model and alphabet for tokenization
38
+ logger.info("Loading model...")
39
+ # model, alphabet = pretrained.load_model_and_alphabet(model_name)
40
+ model, alphabet = pretrained.load_model_and_alphabet_hub(model_name)
41
+ model.eval() # Setting the model to evaluation mode
42
+ if not self.disable_special_tokens:
43
+ model.append_eos = True if not model_name.startswith("esm1") else False # type: ignore
44
+ model.prepend_bos = True # type: ignore
45
+ else:
46
+ model.append_eos = False # type: ignore
47
+ model.prepend_bos = False # type: ignore
48
+
49
+ num_heads = model.layers[0].self_attn.num_heads # type: ignore
50
+ num_layers = len(model.layers) # type: ignore
51
+ embedding_size = (
52
+ model.embed_tokens.embedding_dim # type: ignore
53
+ if model_name.startswith("esm1")
54
+ else model.embed_dim
55
+ )
56
+
57
+ # Moving the model to GPU if available for faster processing
58
+ if torch.cuda.is_available() and self.device == "cuda":
59
+ model = model.cuda()
60
+ logger.info("Transferred model to GPU")
61
+ else:
62
+ logger.info("No GPU available, using CPU")
63
+ return (
64
+ model,
65
+ alphabet,
66
+ num_heads,
67
+ num_layers,
68
+ embedding_size,
69
+ model.prepend_bos,
70
+ model.append_eos,
71
+ )
72
+
73
+ def get_special_tokens(self):
74
+ special_tokens = self.alphabet.all_special_tokens
75
+ special_token_ids = torch.tensor(
76
+ [self.alphabet.tok_to_idx[tok] for tok in special_tokens],
77
+ device=self.device,
78
+ dtype=torch.int8,
79
+ )
80
+ return special_token_ids
81
+
82
+ def _load_layers(self, layers):
83
+ if not layers:
84
+ layers = list(range(1, self.model.num_layers + 1)) # type: ignore
85
+ return layers
86
+ # Checking if the specified representation layers are valid
87
+ assert all(
88
+ -(self.model.num_layers + 1) <= i <= self.model.num_layers for i in layers # type: ignore
89
+ )
90
+ layers = [
91
+ (i + self.model.num_layers + 1) % (self.model.num_layers + 1) # type: ignore
92
+ for i in layers
93
+ ]
94
+ return layers
95
+
96
+ def _load_data(self, sequences, substring_dict=None):
97
+ # Creating a dataset from the input fasta file
98
+ dataset = pepe.utils.ESMDataset(
99
+ sequences,
100
+ substring_dict,
101
+ self.context,
102
+ self.alphabet,
103
+ self.max_length,
104
+ self.prepend_bos, # type: ignore
105
+ self.append_eos, # type: ignore
106
+ )
107
+ # Generating batch indices based on token count
108
+ logger.info("Generating batches...")
109
+ batches = pepe.utils.TokenBudgetBatchSampler(dataset, self.batch_size)
110
+ # DataLoader to iterate through batches efficiently
111
+ data_loader = torch.utils.data.DataLoader(
112
+ dataset, batch_sampler=batches, collate_fn=dataset.safe_collate
113
+ )
114
+ logger.info("Data loaded")
115
+ # Getting the maximum sequence length from the dataset
116
+ max_length = dataset.get_max_encoded_length()
117
+ return data_loader, max_length
118
+
119
+ def _compute_outputs(
120
+ self,
121
+ model,
122
+ toks,
123
+ attention_mask,
124
+ return_embeddings,
125
+ return_contacts,
126
+ return_logits,
127
+ ):
128
+ outputs = model(
129
+ toks,
130
+ repr_layers=self.layers,
131
+ return_contacts=return_contacts,
132
+ )
133
+ if return_logits:
134
+ logits = (
135
+ outputs["logits"]
136
+ .to(dtype=self._precision_to_dtype(self.precision, "torch"))
137
+ .permute(2, 0, 1)
138
+ .cpu()
139
+ ) # permute to match the shape of the representations
140
+ torch.cuda.empty_cache()
141
+ else:
142
+ logits = None
143
+
144
+ if return_contacts:
145
+ attention_matrices = (
146
+ outputs["attentions"]
147
+ .to(dtype=self._precision_to_dtype(self.precision, "torch"))
148
+ .permute(1, 0, 2, 3, 4)
149
+ ).cpu() # permute to match the shape of the representations
150
+ torch.cuda.empty_cache()
151
+ else:
152
+ attention_matrices = None
153
+ # Extracting layer representations and moving them to CPU
154
+ if return_embeddings:
155
+ representations = {
156
+ layer: t.to(
157
+ dtype=self._precision_to_dtype(self.precision, "torch")
158
+ ).cpu()
159
+ for layer, t in outputs["representations"].items()
160
+ }
161
+ torch.cuda.empty_cache()
162
+ else:
163
+ representations = None
164
+ return logits, representations, attention_matrices
@@ -0,0 +1,200 @@
1
+ import logging
2
+ import os
3
+ import torch
4
+ import pepe.utils
5
+ from pepe.embedders.base_embedder import BaseEmbedder
6
+ from transformers import T5EncoderModel, T5Tokenizer
7
+ from transformers import RoFormerTokenizer, RoFormerModel
8
+ from transformers.models.roformer.modeling_roformer import (
9
+ RoFormerSinusoidalPositionalEmbedding,
10
+ )
11
+
12
+
13
+ # Set max_split_size_mb
14
+ os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
15
+
16
+ logger = logging.getLogger("src.embedders.huggingface_embedder")
17
+
18
+
19
+ class HuggingfaceEmbedder(BaseEmbedder):
20
+ def __init__(self, args):
21
+ super().__init__(args)
22
+ if self.return_logits:
23
+ logger.warning(
24
+ "Warning: Logits are not supported for this model. Setting to False."
25
+ )
26
+ self.return_logits = False
27
+ self.output_types.remove("logits")
28
+
29
+ def _load_layers(self, layers):
30
+ """Check if the specified representation layers are valid."""
31
+ if not layers:
32
+ layers = list(range(1, self.model.config.num_hidden_layers + 1)) # type: ignore
33
+ return layers
34
+ assert all(
35
+ -(self.model.config.num_hidden_layers + 1) # type: ignore
36
+ <= i
37
+ <= self.model.config.num_hidden_layers # type: ignore
38
+ for i in layers
39
+ )
40
+ layers = [
41
+ (i + self.model.config.num_hidden_layers + 1) # type: ignore
42
+ % (self.model.config.num_hidden_layers + 1) # type: ignore
43
+ for i in layers
44
+ ]
45
+ return layers
46
+
47
+ def _load_data(self, sequences, substring_dict):
48
+ """Tokenize sequences and create a DataLoader."""
49
+ # Tokenize sequences
50
+ dataset = pepe.utils.HuggingFaceDataset(
51
+ sequences,
52
+ substring_dict,
53
+ self.context,
54
+ self.tokenizer, # type: ignore
55
+ self.max_length,
56
+ add_special_tokens=not self.disable_special_tokens,
57
+ )
58
+ logger.info("Batching sequences...")
59
+ batch_sampler = pepe.utils.TokenBudgetBatchSampler(
60
+ dataset=dataset, token_budget=self.batch_size
61
+ )
62
+ data_loader = torch.utils.data.DataLoader(
63
+ dataset, batch_sampler=batch_sampler, collate_fn=dataset.safe_collate
64
+ )
65
+ max_length = dataset.get_max_encoded_length()
66
+ logger.info("Finished tokenizing and batching sequences")
67
+
68
+ return data_loader, max_length
69
+
70
+ def _compute_outputs(
71
+ self,
72
+ model,
73
+ toks,
74
+ attention_mask,
75
+ return_embeddings,
76
+ return_contacts,
77
+ return_logits=False,
78
+ ):
79
+ outputs = model(
80
+ input_ids=toks,
81
+ attention_mask=attention_mask,
82
+ output_hidden_states=return_embeddings,
83
+ output_attentions=return_contacts,
84
+ )
85
+ if return_contacts:
86
+ attention_matrices = (
87
+ torch.stack(outputs.attentions) # type: ignore
88
+ .to(self._precision_to_dtype(self.precision, "torch")) # type: ignore
89
+ .cpu()
90
+ ) # stack attention matrices across layers
91
+ torch.cuda.empty_cache()
92
+ else:
93
+ attention_matrices = None
94
+ if return_embeddings:
95
+ representations = {
96
+ layer: outputs.hidden_states[layer]
97
+ .to(
98
+ self._precision_to_dtype(self.precision, "torch"),
99
+ )
100
+ .cpu()
101
+ for layer in self.layers # type: ignore
102
+ }
103
+ torch.cuda.empty_cache()
104
+ else:
105
+ representations = None
106
+ logits = None # Model doesn't return logits
107
+ return logits, representations, attention_matrices
108
+
109
+
110
+ class Antiberta2Embedder(HuggingfaceEmbedder):
111
+ def __init__(self, args):
112
+ super().__init__(args)
113
+ self.sequences = pepe.utils.fasta_to_dict(args.fasta_path)
114
+ self.num_sequences = len(self.sequences)
115
+ (
116
+ self.model,
117
+ self.tokenizer,
118
+ self.num_heads,
119
+ self.num_layers,
120
+ self.embedding_size,
121
+ ) = self._initialize_model(self.model_link)
122
+ self.valid_tokens = set(self.tokenizer.get_vocab().keys())
123
+ pepe.utils.check_input_tokens(
124
+ self.valid_tokens, self.sequences, self.model_name
125
+ )
126
+ self.special_tokens = torch.tensor(
127
+ self.tokenizer.all_special_ids, device=self.device, dtype=torch.int8
128
+ )
129
+ self.layers = self._load_layers(self.layers)
130
+ self.data_loader, self.max_length = self._load_data(
131
+ self.sequences, self.substring_dict
132
+ )
133
+ self._set_output_objects()
134
+ assert self.max_length <= 256, "AntiBERTa2 only supports max_length <= 256"
135
+
136
+ def _initialize_model(self, model_link="alchemab/antiberta2-cssp"):
137
+ """Initialize the model, tokenizer, and device."""
138
+ if torch.cuda.is_available() and self.device == "cuda":
139
+ device = torch.device("cuda")
140
+ logger.info("Transferred model to GPU")
141
+ else:
142
+ device = torch.device("cpu")
143
+ logger.info("No GPU available, using CPU")
144
+ tokenizer = RoFormerTokenizer.from_pretrained(model_link, use_fast=True)
145
+ model = RoFormerModel.from_pretrained(model_link).to(device) # type: ignore
146
+ model.eval()
147
+ num_heads = model.config.num_attention_heads
148
+ num_layers = model.config.num_hidden_layers
149
+ embedding_size = model.config.hidden_size
150
+ return model, tokenizer, num_heads, num_layers, embedding_size
151
+
152
+
153
+ class T5Embedder(HuggingfaceEmbedder):
154
+ def __init__(self, args):
155
+ super().__init__(args)
156
+ self.sequences = self.fasta_to_dict(args.fasta_path) # type: ignore
157
+ self.num_sequences = len(self.sequences)
158
+ (
159
+ self.model,
160
+ self.tokenizer,
161
+ self.num_heads,
162
+ self.num_layers,
163
+ self.embedding_size,
164
+ ) = self._initialize_model(self.model_link)
165
+ self.valid_tokens = self.get_valid_tokens()
166
+ pepe.utils.check_input_tokens(
167
+ self.valid_tokens, self.sequences, self.model_name
168
+ )
169
+ self.special_tokens = torch.tensor(
170
+ self.tokenizer.all_special_ids, device=self.device, dtype=torch.int8
171
+ )
172
+ self.layers = self._load_layers(self.layers)
173
+ self.data_loader, self.max_length = self._load_data(
174
+ self.sequences, self.substring_dict
175
+ )
176
+ self._set_output_objects()
177
+
178
+ def get_valid_tokens(self):
179
+ valid_tokens = set(
180
+ k[1:] if k.startswith("▁") else k
181
+ for k in set(self.tokenizer.get_vocab().keys())
182
+ )
183
+ return valid_tokens
184
+
185
+ def _initialize_model(self, model_link="Rostlab/prot_t5_xl_half_uniref50-enc"):
186
+ """Initialize the model, tokenizer, and device."""
187
+
188
+ if torch.cuda.is_available() and self.device == "cuda":
189
+ device = torch.device("cuda")
190
+ logger.info("Transferred model to GPU")
191
+ else:
192
+ device = torch.device("cpu")
193
+ logger.info("No GPU available, using CPU")
194
+ tokenizer = T5Tokenizer.from_pretrained(model_link, use_fast=True)
195
+ model = T5EncoderModel.from_pretrained(model_link).to(device) # type: ignore
196
+ model.eval()
197
+ num_heads = model.config.num_heads
198
+ num_layers = model.config.num_layers
199
+ embedding_size = model.config.hidden_size
200
+ return model, tokenizer, num_heads, num_layers, embedding_size
pepe/model_selecter.py ADDED
@@ -0,0 +1,99 @@
1
+ from pepe.embedders.esm_embedder import ESMEmbedder
2
+ from pepe.embedders.huggingface_embedder import T5Embedder, Antiberta2Embedder
3
+ from pepe.embedders.custom_embedder import CustomEmbedder
4
+
5
+
6
+ import os
7
+
8
+
9
+ def select_model(model_name):
10
+ if "esm2" in model_name.lower():
11
+ return ESMEmbedder
12
+ elif "esm1" in model_name.lower():
13
+ return ESMEmbedder
14
+ # elif "antiberta2" in model_name.lower() and model_name.startswith("alchemab"):
15
+ # return Antiberta2Embedder
16
+ # elif "t5" in model_name.lower() and model_name.startswith("Rostlab"):
17
+ # return T5Embedder
18
+ elif (
19
+ model_name.endswith(".pt")
20
+ or model_name.endswith(".pth")
21
+ or model_name.startswith("custom:")
22
+ or (
23
+ os.path.exists(model_name)
24
+ and (os.path.isfile(model_name) or os.path.isdir(model_name))
25
+ )
26
+ ):
27
+ return CustomEmbedder
28
+ elif "/" in model_name:
29
+ # Assume it's a Hugging Face model (username/model-name format)
30
+ # Try to determine the architecture automatically
31
+ try:
32
+ from transformers import AutoConfig
33
+
34
+ config = AutoConfig.from_pretrained(model_name)
35
+ model_type = config.model_type.lower()
36
+
37
+ if model_type in ["t5", "mt5"]:
38
+ return T5Embedder
39
+ elif model_type in ["roformer"]:
40
+ return Antiberta2Embedder
41
+ elif model_type in ["bert"]:
42
+ # For BERT-like models, we could potentially use a generic embedder
43
+ # but for now, suggest using CustomEmbedder or creating a specific one
44
+ raise ValueError(
45
+ f"BERT-like models are not yet directly supported. Consider using a PyTorch version of the model with CustomEmbedder."
46
+ )
47
+ else:
48
+ # For other architectures, you might want to add more specific embedders
49
+ # or use a generic HuggingfaceEmbedder
50
+ raise ValueError(
51
+ f"Model architecture '{model_type}' not yet supported for custom Hugging Face models"
52
+ )
53
+ except Exception as e:
54
+ # Check if it's a Keras/TensorFlow model
55
+ error_msg = str(e)
56
+ if "Unrecognized model" in error_msg or "model_type" in error_msg:
57
+ raise ValueError(
58
+ f"Model {model_name} appears to be a Keras/TensorFlow model or has an unsupported architecture. EmbedAIRR currently supports PyTorch models only. Consider using a PyTorch version or converting the model."
59
+ )
60
+ else:
61
+ raise ValueError(
62
+ f"Could not determine model architecture for {model_name}: {e}"
63
+ )
64
+ else:
65
+ raise ValueError(f"Model {model_name} not supported")
66
+
67
+
68
+ supported_models = [
69
+ # ESM models
70
+ "esm1_t34_670M_UR50S",
71
+ "esm1_t34_670M_UR50D",
72
+ "esm1_t34_670M_UR100",
73
+ "esm1_t12_85M_UR50S",
74
+ "esm1_t6_43M_UR50S",
75
+ "esm1b_t33_650M_UR50S",
76
+ #'esm_msa1_t12_100M_UR50S',
77
+ #'esm_msa1b_t12_100M_UR50S',
78
+ "esm1v_t33_650M_UR90S_1",
79
+ "esm1v_t33_650M_UR90S_2",
80
+ "esm1v_t33_650M_UR90S_3",
81
+ "esm1v_t33_650M_UR90S_4",
82
+ "esm1v_t33_650M_UR90S_5",
83
+ #'esm_if1_gvp4_t16_142M_UR50',
84
+ "esm2_t6_8M_UR50D",
85
+ "esm2_t12_35M_UR50D",
86
+ "esm2_t30_150M_UR50D",
87
+ "esm2_t33_650M_UR50D",
88
+ "esm2_t36_3B_UR50D",
89
+ "esm2_t48_15B_UR50D",
90
+ # Pre-defined Hugging Face models
91
+ "Rostlab/prot_t5_xl_half_uniref50-enc",
92
+ "Rostlab/ProstT5",
93
+ "alchemab/antiberta2-cssp",
94
+ "alchemab/antiberta2",
95
+ # Custom models examples:
96
+ # - PyTorch models: "/path/to/model.pt", "/path/to/model_directory/", "custom:/path/to/model.pt"
97
+ # - Hugging Face models: "username/model-name", "./local_hf_model"
98
+ # - See documentation for details on custom model requirements
99
+ ]
@@ -0,0 +1,167 @@
1
+ import argparse
2
+ from pepe.model_selecter import supported_models
3
+
4
+
5
+ def str2bool(value):
6
+ if isinstance(value, bool):
7
+ return value
8
+ if value.lower() in ("true", "t", "yes", "y", "1"):
9
+ return True
10
+ elif value.lower() in ("false", "f", "no", "n", "0"):
11
+ return False
12
+ else:
13
+ raise argparse.ArgumentTypeError("Boolean value expected.")
14
+
15
+
16
+ def str2ints(value):
17
+ """Convert a string to a list of integers."""
18
+ if isinstance(value, str):
19
+ if value.lower() == "all":
20
+ return None
21
+ elif value.lower() == "last":
22
+ return [-1]
23
+ else:
24
+ try:
25
+ return [int(x) for x in value.split(" ")]
26
+ except ValueError:
27
+ raise argparse.ArgumentTypeError(
28
+ "Invalid input. Expected integer(s) or spaced list of integers or 'all' or 'last'."
29
+ )
30
+ elif isinstance(value, int):
31
+ return [value]
32
+
33
+
34
+ # Parsing command-line arguments for input and output file paths
35
+ def parse_arguments():
36
+ """Parse command-line arguments for input and output file paths."""
37
+ parser = argparse.ArgumentParser(description="Input path")
38
+ parser.add_argument(
39
+ "--experiment_name",
40
+ type=str,
41
+ default=None,
42
+ help="Name of the experiment. Will be used to name the output files. If not provided, the output files will be named after the input file.",
43
+ )
44
+ parser.add_argument(
45
+ "--model_name",
46
+ type=str,
47
+ required=True,
48
+ help="Model name or path to custom model. For custom models, use path to .pt/.pth file or directory containing model files. For predefined models, use model name from supported list.",
49
+ )
50
+ parser.add_argument(
51
+ "--tokenizer_from",
52
+ type=str,
53
+ default=None,
54
+ help="Huggingface address of the tokenizer to use. If not provided, will use the tokenizer from the model. If using a custom model, provide the path to the tokenizer directory.",
55
+ )
56
+ parser.add_argument(
57
+ "--fasta_path",
58
+ type=str,
59
+ required=True,
60
+ help="Path to the input FASTA file. Required. If no experiment name is provided, the output files will be named after the input file.",
61
+ )
62
+ parser.add_argument(
63
+ "--output_path",
64
+ type=str,
65
+ required=True,
66
+ help="Directory for output files \n Will generate a subdirectory for outputs of each output_type.\n Will output multiple files if multiple layers are specified with '--layers'. Output file is a single tensor or a list of tensors when --pooling is False.",
67
+ )
68
+ parser.add_argument(
69
+ "--substring_path",
70
+ default=None,
71
+ type=str,
72
+ help=" Path to a CSV file with columns 'sequence_id' and 'substring'. Only required when selecting 'substring' embedding option.",
73
+ )
74
+ parser.add_argument(
75
+ "--context",
76
+ default=0,
77
+ type=int,
78
+ help="Only specify when including 'substring_pooling' in '--extract_embeddings' option. Number of amino acids to include before and after the substring sequence. Default is 0.",
79
+ )
80
+ parser.add_argument(
81
+ "--layers",
82
+ type=str2ints,
83
+ nargs="*",
84
+ default=[[-1]],
85
+ help="Representation layers to extract from the model. Default is the last layer. Example: argument '--layers -1 6' will output the last layer and the sixth layer.",
86
+ )
87
+ parser.add_argument(
88
+ "--extract_embeddings",
89
+ choices=[
90
+ "per_token",
91
+ "mean_pooled",
92
+ "substring_pooled",
93
+ "attention_head",
94
+ "attention_layer",
95
+ "attention_model",
96
+ "logits",
97
+ ],
98
+ default=["mean_pooled"],
99
+ nargs="+",
100
+ help="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 'pooled'.",
101
+ )
102
+ parser.add_argument(
103
+ "--batch_size",
104
+ type=int,
105
+ default=1024,
106
+ help="Number of tokens (not sequences!) per batch. Default is 1024.",
107
+ )
108
+ parser.add_argument(
109
+ "--discard_padding",
110
+ action="store_true",
111
+ help="Discard padding tokens from per_token embeddings output. Not compatible with --streaming_output Default is False.",
112
+ )
113
+ parser.add_argument(
114
+ "--max_length",
115
+ default="max_length",
116
+ help="Length to which sequences will be padded. Default is longest sequence.",
117
+ )
118
+ parser.add_argument(
119
+ "--streaming_output",
120
+ type=str2bool,
121
+ choices=[True, False],
122
+ default=True,
123
+ help="Preallocate output files and concurrently write embeddings to disk in batches while computing embeddings. Default is True.",
124
+ )
125
+ parser.add_argument(
126
+ "--num_workers",
127
+ type=int,
128
+ default=8,
129
+ help="Number of workers for asynchronous data writing. Only relevant when --batch_writing is enabled. Default is 8.",
130
+ )
131
+ parser.add_argument(
132
+ "--disable_special_tokens",
133
+ type=str2bool,
134
+ choices=[True, False],
135
+ default=False,
136
+ help="Disable special tokens in the model. Default is False.",
137
+ )
138
+ parser.add_argument(
139
+ "--flatten",
140
+ type=str2bool,
141
+ choices=[True, False],
142
+ default=False,
143
+ help="Flatten the output tensors. Default is False.",
144
+ )
145
+ parser.add_argument(
146
+ "--flush_batches_after",
147
+ type=int,
148
+ default=128,
149
+ help="Size (in MB) of outputs to accumulate in RAM per worker (--num_workers) before flushing to disk. Default is 128.",
150
+ )
151
+ parser.add_argument(
152
+ "--precision",
153
+ type=str,
154
+ default="32",
155
+ choices=["float16", "16", "half", "float32", "32", "full"],
156
+ help="Precision of the output data. Inference during embedding is not affected. Default is 'float32'.",
157
+ )
158
+ parser.add_argument(
159
+ "--device",
160
+ type=str.lower,
161
+ default="cuda",
162
+ choices=["cuda", "cpu"],
163
+ help="Device to run the model on. Default is 'cuda'.",
164
+ )
165
+
166
+ args = parser.parse_args()
167
+ return args