Skip to content

Commit 1a24210

Browse files
nbollistrishorts
andauthored
Pep model stability (#2642)
* ignore * Pep Model Stability * Address shortreed comment --------- Co-authored-by: trishorts <mshort@chem.wisc.edu>
1 parent 8b16d9e commit 1a24210

1 file changed

Lines changed: 51 additions & 63 deletions

File tree

MetaMorpheus/EngineLayer/FdrAnalysis/PEPAnalysisEngine.cs

Lines changed: 51 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,6 @@ public string ComputePEPValuesForAllPSMs()
163163
var myPredictions = trainedModels[groupIndexNumber].Transform(mlContext.Data.LoadFromEnumerable(PSMDataGroups[groupIndexNumber]));
164164
CalibratedBinaryClassificationMetrics metrics = mlContext.BinaryClassification.Evaluate(data: myPredictions, labelColumnName: "Label", scoreColumnName: "Score");
165165

166-
//Parallel operation of the following code requires the method to be stored and then read, once for each thread
167-
//if not output directory is specified, the model cannot be stored, and we must force single-threaded operation
168-
if (OutputFolder != null)
169-
{
170-
mlContext.Model.Save(trainedModels[groupIndexNumber], dataView.Schema, Path.Combine(OutputFolder, "model.zip"));
171-
}
172-
173166
//model is trained on peptides but here we can use that to compute PEP for all PSMs
174167
int ambiguousPeptidesResolved = Compute_PSM_PEP(peptideGroups, peptideGroupIndices[groupIndexNumber], mlContext, trainedModels[groupIndexNumber], SearchType, OutputFolder);
175168

@@ -389,82 +382,77 @@ public static string AggregateMetricsForOutput(List<CalibratedBinaryClassificati
389382
return s.ToString();
390383
}
391384

392-
private readonly object _modelLock = new();
393-
394385
public int Compute_PSM_PEP(List<SpectralMatchGroup> peptideGroups,
395386
List<int> peptideGroupIndices,
396387
MLContext mLContext, TransformerChain<BinaryPredictionTransformer<Microsoft.ML.Calibrators.CalibratedModelParametersBase<Microsoft.ML.Trainers.FastTree.FastTreeBinaryModelParameters, Microsoft.ML.Calibrators.PlattCalibrator>>> trainedModel, string searchType, string outputFolder)
397388
{
398389
int maxThreads = FileSpecificParametersDictionary.Values.FirstOrDefault().MaxThreadsToUsePerFile;
399390
int ambiguousPeptidesResolved = 0;
400391

401-
//the trained model is not threadsafe. Therefore, to use the same model for each thread saved the model to disk. Then each thread reads its own copy of the model back from disk.
402-
//If there is no output folder specified, then this can't happen. We set maxthreads eqaul to one and use the model that gets passed into the method.
403-
if (String.IsNullOrEmpty(outputFolder))
404-
{
405-
maxThreads = 1;
406-
}
392+
var predictionEnginePerThread =
393+
new ThreadLocal<PredictionEngine<PsmData, TruePositivePrediction>>(
394+
() => mLContext.Model.CreatePredictionEngine<PsmData, TruePositivePrediction>(trainedModel),
395+
trackAllValues: true);
407396

408-
Parallel.ForEach(Partitioner.Create(0, peptideGroupIndices.Count),
409-
new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
410-
(range, loopState) =>
411-
{
412-
// Stop loop if canceled
413-
if (GlobalVariables.StopLoops) { return; }
414-
415-
ITransformer threadSpecificTrainedModel;
416-
417-
if (maxThreads == 1)
418-
{
419-
threadSpecificTrainedModel = trainedModel;
420-
}
421-
else
397+
try
398+
{
399+
Parallel.ForEach(Partitioner.Create(0, peptideGroupIndices.Count),
400+
new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
401+
(range, loopState) =>
422402
{
423-
lock (_modelLock)
424-
{
425-
threadSpecificTrainedModel = mLContext.Model.Load(Path.Combine(outputFolder, "model.zip"), out DataViewSchema savedModelSchema);
426-
}
427-
}
403+
// Stop loop if canceled
404+
if (GlobalVariables.StopLoops) { return; }
428405

429-
// one prediction engine per thread, because the prediction engine is not thread-safe
430-
var threadPredictionEngine = mLContext.Model.CreatePredictionEngine<PsmData, TruePositivePrediction>(threadSpecificTrainedModel);
406+
// one prediction engine per thread, because the prediction engine is not thread-safe
407+
var threadPredictionEngine = predictionEnginePerThread.Value;
431408

432-
int ambigousPeptidesRemovedinThread = 0;
409+
int ambigousPeptidesRemovedinThread = 0;
433410

434-
List<int> indiciesOfPeptidesToRemove = new List<int>();
435-
List<double> pepValuePredictions = new List<double>();
436-
for (int i = range.Item1; i < range.Item2; i++)
437-
{
438-
foreach (SpectralMatch psm in peptideGroups[peptideGroupIndices[i]])
411+
List<int> indiciesOfPeptidesToRemove = new List<int>();
412+
List<double> pepValuePredictions = new List<double>();
413+
for (int i = range.Item1; i < range.Item2; i++)
439414
{
440-
// I'm not sure what's going one here vis-a-vis disambiguations, but I'm not going to touch it for now
441-
if (psm != null)
415+
foreach (SpectralMatch psm in peptideGroups[peptideGroupIndices[i]])
442416
{
443-
indiciesOfPeptidesToRemove.Clear();
444-
pepValuePredictions.Clear();
445-
446-
//Here we compute the pepvalue predection for each ambiguous peptide in a PSM. Ambiguous peptides with lower pepvalue predictions are removed from the PSM.
447-
var bestMatchingBioPolymersWithSetMods = psm.BestMatchingBioPolymersWithSetMods.ToList();
448-
foreach (SpectralMatchHypothesis bestMatch in bestMatchingBioPolymersWithSetMods)
417+
// I'm not sure what's going one here vis-a-vis disambiguations, but I'm not going to touch it for now
418+
if (psm != null)
449419
{
450-
PsmData pd = CreateOnePsmDataEntry(searchType, psm, bestMatch, !bestMatch.IsDecoy);
451-
var pepValuePrediction = threadPredictionEngine.Predict(pd);
452-
pepValuePredictions.Add(pepValuePrediction.Probability);
453-
//A score is available using the variable pepvaluePrediction.Score
420+
indiciesOfPeptidesToRemove.Clear();
421+
pepValuePredictions.Clear();
422+
423+
//Here we compute the pepvalue predection for each ambiguous peptide in a PSM. Ambiguous peptides with lower pepvalue predictions are removed from the PSM.
424+
var bestMatchingBioPolymersWithSetMods = psm.BestMatchingBioPolymersWithSetMods.ToList();
425+
foreach (SpectralMatchHypothesis bestMatch in bestMatchingBioPolymersWithSetMods)
426+
{
427+
PsmData pd = CreateOnePsmDataEntry(searchType, psm, bestMatch, !bestMatch.IsDecoy);
428+
var pepValuePrediction = threadPredictionEngine.Predict(pd);
429+
pepValuePredictions.Add(pepValuePrediction.Probability);
430+
//A score is available using the variable pepvaluePrediction.Score
431+
}
432+
433+
GetIndiciesOfPeptidesToRemove(indiciesOfPeptidesToRemove, pepValuePredictions);
434+
RemoveBestMatchingPeptidesWithLowPEP(psm, indiciesOfPeptidesToRemove, bestMatchingBioPolymersWithSetMods, ref ambigousPeptidesRemovedinThread);
435+
436+
psm.PsmFdrInfo.PEP = 1 - pepValuePredictions.Max();
437+
psm.PeptideFdrInfo.PEP = 1 - pepValuePredictions.Max();
454438
}
455439

456-
GetIndiciesOfPeptidesToRemove(indiciesOfPeptidesToRemove, pepValuePredictions);
457-
RemoveBestMatchingPeptidesWithLowPEP(psm, indiciesOfPeptidesToRemove, bestMatchingBioPolymersWithSetMods, ref ambigousPeptidesRemovedinThread);
458-
459-
psm.PsmFdrInfo.PEP = 1 - pepValuePredictions.Max();
460-
psm.PeptideFdrInfo.PEP = 1 - pepValuePredictions.Max();
461440
}
462-
463441
}
464-
}
465442

466-
Interlocked.Add(ref ambiguousPeptidesResolved, ambigousPeptidesRemovedinThread);
467-
});
443+
Interlocked.Add(ref ambiguousPeptidesResolved, ambigousPeptidesRemovedinThread);
444+
});
445+
}
446+
finally
447+
{
448+
foreach (var engine in predictionEnginePerThread.Values)
449+
{
450+
engine?.Dispose();
451+
}
452+
453+
predictionEnginePerThread.Dispose();
454+
}
455+
468456
return ambiguousPeptidesResolved;
469457
}
470458

0 commit comments

Comments
 (0)