Skip to content

Commit 69e054f

Browse files
authored
Merge pull request #62 from bigbio/dev
Update for new version of alphapeptdeep
2 parents a77ab46 + c1c4189 commit 69e054f

4 files changed

Lines changed: 59 additions & 22 deletions

File tree

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ dependencies:
2020
- ms2pip>=4.0
2121
- psutil
2222
- pip:
23-
- peptdeep==1.4.0
23+
- peptdeep==1.4.1

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ scipy = "*"
4141
pygam = "*"
4242
protobuf= "*"
4343
ms2pip = ">=4.0"
44-
peptdeep = "*"
44+
peptdeep = "1.4.1"
4545
psutil = "*" # For memory-aware process count in HPC environments
4646

4747
[tool.poetry.urls]

quantmsrescore/ms2_model_manager.py

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import pandas as pd
2-
from peptdeep.pretrained_models import ModelManager, model_mgr_settings, MODEL_DOWNLOAD_INSTRUCTIONS, \
2+
from peptdeep.pretrained_models import ModelManager, model_mgr_settings, \
33
psm_sampling_with_important_mods, is_model_zip
4+
5+
# Try to import MODEL_DOWNLOAD_INSTRUCTIONS from peptdeep (version-dependent export)
6+
try:
7+
from peptdeep.pretrained_models import MODEL_DOWNLOAD_INSTRUCTIONS
8+
except ImportError:
9+
MODEL_DOWNLOAD_INSTRUCTIONS = (
10+
"Please download the pretrained models manually from "
11+
"https://github.com/MannLabs/alphapeptdeep/releases and place them in the model directory."
12+
)
413
from peptdeep.model.ms2 import pDeepModel, frag_types, max_frag_charge, ModelMS2Bert, calc_ms2_similarity
514
from peptdeep.model.rt import AlphaRTModel
615
from peptdeep.model.ccs import AlphaCCSModel
@@ -57,11 +66,19 @@ def configure_torch_for_hpc(n_threads: int = 1) -> None:
5766

5867

5968
class MS2ModelManager(ModelManager):
69+
"""Extended ModelManager that uses MS2pDeepModel for MS2 predictions.
70+
71+
Note: This class intentionally does not call super().__init__() because it
72+
replaces the ms2_model with MS2pDeepModel. Calling the parent would create
73+
duplicate model instances.
74+
"""
75+
6076
def __init__(self,
6177
mask_modloss: bool = False,
6278
device: str = "gpu",
6379
model_dir: str = ".",
6480
):
81+
# Initialize attributes expected by parent class methods
6582
self._train_psm_logging = True
6683

6784
self.ms2_model: pDeepModel = MS2pDeepModel(
@@ -75,8 +92,9 @@ def __init__(self,
7592
)
7693
self.model_url = "https://github.com/MannLabs/alphapeptdeep/releases/download/pre-trained-models/pretrained_models_v3.zip"
7794

78-
if len(glob.glob(os.path.join(model_dir, "*ms2.pth"))) > 0:
79-
self.load_external_models(ms2_model_file=glob.glob(os.path.join(model_dir, "*ms2.pth"))[0])
95+
ms2_model_files = glob.glob(os.path.join(model_dir, "*ms2.pth"))
96+
if ms2_model_files:
97+
self.load_external_models(ms2_model_file=ms2_model_files[0])
8098
self.model_str = model_dir
8199
else:
82100
self.download_model_path = os.path.join(model_dir, "pretrained_models_v3.zip")
@@ -116,7 +134,9 @@ def _download_models(self, model_zip_file_path: str, skip_if_exists: bool = True
116134
else:
117135
logging.info(f"Downloading pretrained models from {url} to {model_zip_file_path} ...")
118136
try:
119-
os.makedirs(os.path.dirname(model_zip_file_path), exist_ok=True)
137+
parent_dir = os.path.dirname(model_zip_file_path)
138+
if parent_dir:
139+
os.makedirs(parent_dir, exist_ok=True)
120140
context = ssl.create_default_context(cafile=certifi.where())
121141
# Use streaming download with longer timeout for large model files
122142
# timeout=300s (5 min) for slow connections; stream in 1MB chunks
@@ -129,16 +149,21 @@ def _download_models(self, model_zip_file_path: str, skip_if_exists: bool = True
129149
try:
130150
os.remove(model_zip_file_path)
131151
except OSError:
132-
pass
152+
pass # Best-effort cleanup; file may already be removed or locked
133153
raise FileNotFoundError(
134154
f"Downloading model failed: {e}.\n" + MODEL_DOWNLOAD_INSTRUCTIONS
135155
) from e
136156

137157
logging.info("Successfully downloaded pretrained models.")
138158
if not is_model_zip(model_zip_file_path):
159+
# Clean up invalid/corrupted file
160+
try:
161+
os.remove(model_zip_file_path)
162+
except OSError:
163+
pass # Best-effort cleanup; file may already be removed or locked
139164
raise ValueError(
140165
f"Local model file is not a valid zip: {model_zip_file_path}.\n"
141-
f"Please delete this file and try again.\n"
166+
f"The invalid file has been removed. Please try again.\n"
142167
f"Or: {MODEL_DOWNLOAD_INSTRUCTIONS}"
143168
)
144169

@@ -184,6 +209,28 @@ def load_installed_models(self, download_model_path: str = "pretrained_models_v3
184209
download_model_path, model_path_in_zip="generic/charge.pth"
185210
)
186211

212+
def _build_intensity_df(self, matched_intensity_df: pd.DataFrame) -> pd.DataFrame:
213+
"""Build intensity DataFrame with all charged fragment types.
214+
215+
Parameters
216+
----------
217+
matched_intensity_df : pd.DataFrame
218+
The matched fragment intensities.
219+
220+
Returns
221+
-------
222+
pd.DataFrame
223+
Intensity DataFrame with columns for all charged fragment types,
224+
filled with 0.0 for missing columns.
225+
"""
226+
inten_df = pd.DataFrame()
227+
for frag_type in self.ms2_model.charged_frag_types:
228+
if frag_type in matched_intensity_df.columns:
229+
inten_df[frag_type] = matched_intensity_df[frag_type]
230+
else:
231+
inten_df[frag_type] = 0.0
232+
return inten_df
233+
187234
def train_ms2_model(
188235
self,
189236
psm_df: pd.DataFrame,
@@ -215,12 +262,7 @@ def train_ms2_model(
215262
else:
216263
tr_df = psm_df
217264
if len(tr_df) > 0:
218-
tr_inten_df = pd.DataFrame()
219-
for frag_type in self.ms2_model.charged_frag_types:
220-
if frag_type in matched_intensity_df.columns:
221-
tr_inten_df[frag_type] = matched_intensity_df[frag_type]
222-
else:
223-
tr_inten_df[frag_type] = 0.0
265+
tr_inten_df = self._build_intensity_df(matched_intensity_df)
224266

225267
if self.use_grid_nce_search:
226268
self.nce, self.instrument = self.ms2_model.grid_nce_search(
@@ -254,12 +296,7 @@ def train_ms2_model(
254296
test_psm_df = pd.DataFrame()
255297
else:
256298
test_psm_df = psm_df.copy()
257-
tr_inten_df = pd.DataFrame()
258-
for frag_type in self.ms2_model.charged_frag_types:
259-
if frag_type in matched_intensity_df.columns:
260-
tr_inten_df[frag_type] = matched_intensity_df[frag_type]
261-
else:
262-
tr_inten_df[frag_type] = 0.0
299+
tr_inten_df = self._build_intensity_df(matched_intensity_df)
263300
self.set_default_nce_instrument(test_psm_df)
264301
else:
265302
test_psm_df = pd.DataFrame()
@@ -369,7 +406,7 @@ def _set_batch_predict_data(
369406
self,
370407
batch_df: pd.DataFrame,
371408
predicts: np.ndarray,
372-
**kwargs,
409+
**_kwargs,
373410
):
374411
apex_intens = predicts.reshape((len(batch_df), -1)).max(axis=1)
375412
apex_intens[apex_intens <= 0] = 1

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ scipy
99
pygam
1010
protobuf
1111
ms2pip>=4.0
12-
peptdeep==1.4.0
12+
peptdeep==1.4.1
1313
psutil

0 commit comments

Comments
 (0)