@@ -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